From bac05f5edcc4d74d16393d4097c4b64ea3eaebc0 Mon Sep 17 00:00:00 2001 From: eggmanQQQ2 <3671373519@qq.com> Date: Mon, 7 Jul 2025 10:45:44 +0800 Subject: [PATCH] feat : app-main-java --- .../main/java/com/chwl/app/AgentActivity.java | 110 + .../main/java/com/chwl/app/DemoActivity.kt | 55 + .../main/java/com/chwl/app/GuideAdapter.java | 68 + .../main/java/com/chwl/app/MainActivity.java | 989 +++++ .../java/com/chwl/app/MainTabContentView.kt | 4 + .../java/com/chwl/app/NimMiddleActivity.java | 196 + app/src/main/java/com/chwl/app/UIHelper.java | 136 + .../java/com/chwl/app/UserGuideActivity.java | 70 + .../java/com/chwl/app/application/App.java | 657 +++ .../app/application/GlobalHandleManager.java | 115 + .../app/application/IReportConstants.java | 60 + .../chwl/app/application/IReportService.java | 41 + .../chwl/app/application/ReportManager.java | 63 + .../chwl/app/audio/AudioRecordActivity.java | 373 ++ .../com/chwl/app/audio/MyVoiceActivity.java | 227 ++ .../app/audio/RecordingVoiceActivity.java | 478 +++ .../chwl/app/audio/SoundSignatureActivity.kt | 533 +++ .../chwl/app/audio/VoiceMatchActivity.java | 637 +++ .../chwl/app/audio/adapter/CardAdapter.java | 120 + .../app/audio/adapter/MyVoiceListAdapter.java | 262 ++ .../app/audio/helper/AudioPlayerHelper.java | 221 + .../chwl/app/audio/helper/OnPlayListener.java | 39 + .../app/audio/helper/OnRefreshListener.java | 10 + .../app/audio/helper/SvgaCacheManager.java | 171 + .../chwl/app/audio/helper/VmSoundManager.java | 77 + .../app/audio/helper/VoiceMacthHelper.java | 36 + .../app/audio/presenter/MyVoicePresenter.java | 35 + .../presenter/RecordingVoicePresenter.java | 462 +++ .../chwl/app/audio/view/BottleContainer.java | 290 ++ .../com/chwl/app/audio/view/BottleLayout.java | 536 +++ .../app/audio/view/IBottleOpListener.java | 14 + .../com/chwl/app/audio/view/IMyVoiceView.java | 23 + .../app/audio/view/IRecordingVoiceView.java | 79 + .../app/audio/view/PlayLoadingImageView.java | 96 + .../app/audio/viewmodel/SoundViewModel.kt | 377 ++ .../chwl/app/audio/widget/DynamicWave.java | 121 + .../app/audio/widget/OnSwipeListener.java | 28 + .../app/audio/widget/RingProgressView.java | 115 + .../app/audio/widget/RoundProgressView.java | 171 + .../VoiceBottleFilterGenderBottomDialog.java | 105 + .../app/audio/widget/VoiceCardConfig.java | 43 + .../VoiceCardItemTouchHelperCallback.java | 156 + .../audio/widget/VoiceCardLayoutManager.java | 110 + .../audio/widget/VoiceCardRecyclerView.java | 38 + .../com/chwl/app/audio/widget/VoiceLine.java | 225 ++ .../com/chwl/app/audio/widget/VoiceWave.java | 193 + .../app/avroom/BottomViewListenerWrapper.java | 53 + .../chwl/app/avroom/ButtonItemFactory.java | 529 +++ .../avroom/ChatMemberDiffUtilCallback.java | 44 + .../chwl/app/avroom/SoftKeyBoardListener.java | 81 + .../app/avroom/UserCardButtonManager.java | 12 + .../app/avroom/activity/AVRoomActivity.java | 1600 ++++++++ .../app/avroom/activity/CreatePKActivity.java | 446 ++ .../avroom/activity/RecordForPKActivity.java | 151 + .../avroom/activity/RoomBgSettingActivity.kt | 77 + .../activity/RoomBlackListActivity.java | 201 + .../avroom/activity/RoomInviteActivity.java | 237 ++ .../activity/RoomManagerListActivity.java | 160 + .../activity/RoomOnlineUserActivity.java | 69 + .../avroom/activity/RoomRankListActivity.java | 87 + .../avroom/activity/RoomSettingActivity.java | 1045 +++++ .../activity/RoomTitleEditActivity.java | 191 + .../avroom/activity/RoomTypeSwitchActivity.kt | 396 ++ .../avroom/adapter/AuctionListAdapter.java | 36 + .../avroom/adapter/AuctionListEmptyItem.java | 42 + .../avroom/adapter/AuctionListHeaderItem.java | 48 + .../app/avroom/adapter/AuctionListItem.java | 123 + .../avroom/adapter/BaseMicroViewAdapter.java | 691 ++++ .../app/avroom/adapter/CommonVPAdapter.kt | 25 + .../avroom/adapter/CpMicroViewAdapter.java | 140 + .../avroom/adapter/CreateRoomGameAdapter.kt | 18 + .../adapter/CreateRoomGameGuideAdapter.kt | 16 + .../avroom/adapter/DatingMicroViewAdapter.kt | 235 ++ .../app/avroom/adapter/ExitRoomAdapter.kt | 22 + .../avroom/adapter/GameMicroViewAdapter.kt | 98 + .../adapter/GameMiniMicroViewAdapter.kt | 68 + .../avroom/adapter/HomePartyPageAdapter.java | 33 + .../app/avroom/adapter/Mic19ViewAdapter.java | 144 + .../app/avroom/adapter/Mic20ViewAdapter.java | 70 + .../app/avroom/adapter/MicQueueAdapter.java | 99 + .../app/avroom/adapter/MicroViewAdapter.java | 110 + .../adapter/OnMicroItemClickListener.java | 17 + .../app/avroom/adapter/OnlineUserAdapter.java | 239 ++ .../app/avroom/adapter/PKMicQueueAdapter.java | 98 + .../avroom/adapter/PartyMicroViewAdapter.java | 78 + .../avroom/adapter/RecordForPKAdapter.java | 153 + .../adapter/RevelryMicroViewAdapter.java | 78 + .../chwl/app/avroom/adapter/RoomBgAdapter.kt | 45 + .../avroom/adapter/RoomBlackListAdapter.java | 36 + .../adapter/RoomConsumeListAdapter.java | 196 + .../adapter/RoomConsumerListAdapterTemp.java | 205 + .../adapter/RoomContributeListAdapter.java | 35 + .../app/avroom/adapter/RoomGameListAdapter.kt | 18 + .../app/avroom/adapter/RoomGameplayAdapter.kt | 23 + .../app/avroom/adapter/RoomInviteAdapter.java | 246 ++ .../adapter/RoomMessageIndicatorAdapter.java | 106 + .../avroom/adapter/RoomNormalListAdapter.java | 105 + .../adapter/RoomRankFragmentPageAdapter.java | 27 + .../adapter/RoomRankHalfHourListAdapter.java | 63 + .../app/avroom/adapter/RoomVPAdapter.java | 31 + .../avroom/adapter/SendBroadcastAdapter.kt | 14 + .../adapter/SingleAnchorMicroViewAdapter.kt | 94 + .../adapter/SingleRoomPKMicroViewAdapter.kt | 120 + .../chwl/app/avroom/adapter/UpMicAdapter.java | 105 + .../avroom/anotherroompk/RoomPKBoardView.kt | 200 + .../anotherroompk/RoomPKCreateActivity.kt | 143 + .../anotherroompk/RoomPKRankListView.kt | 63 + .../anotherroompk/RoomPKSearchActivity.kt | 105 + .../anotherroompk/RoomPKSearchAdapter.kt | 20 + .../anotherroompk/RoomPkFinishDialog.kt | 89 + .../anotherroompk/RoomPkForceFinishDialog.kt | 54 + .../anotherroompk/RoomPkReceivedDialog.kt | 84 + .../avroom/anotherroompk/RoomPkRuleDialog.kt | 19 + .../chwl/app/avroom/bean/LuckyBagConfig.java | 13 + .../app/avroom/bean/LuckyBagDetailEntity.java | 22 + .../chwl/app/avroom/bean/LuckyBagEntity.java | 28 + .../app/avroom/bean/LuckyBagGiftBody.java | 27 + .../app/avroom/bean/LuckyBagGiftItemBody.java | 9 + .../app/avroom/bean/LuckyBagGoldBody.java | 18 + .../avroom/bean/LuckyBagOpenBiliEntity.java | 14 + .../app/avroom/bean/LuckyBagOpenEntity.java | 11 + .../app/avroom/bean/LuckyBagOpenGiftBean.java | 10 + .../avroom/bean/LuckyBagOpenGiftEntity.java | 9 + .../app/avroom/bean/LuckyBagOpenUserBean.java | 10 + .../app/avroom/bean/RoomAlbumPhotoInfo.kt | 14 + .../chwl/app/avroom/bean/RoomGameplayItem.kt | 63 + .../app/avroom/bean/RoomLuckyBagInfo.java | 13 + .../com/chwl/app/avroom/bean/RoomPlayBean.kt | 8 + .../avroom/dialog/AttentionHintDialog.java | 61 + .../app/avroom/dialog/BaseRoomNotifyDialog.kt | 174 + .../app/avroom/dialog/CreateGameRoomDialog.kt | 62 + .../app/avroom/dialog/CreateRoomDialog.kt | 114 + .../avroom/dialog/DatingVipRuleDialog.java | 35 + .../app/avroom/dialog/ExitRoomPopupWindow.kt | 170 + .../app/avroom/dialog/MicQueueDialog.java | 609 +++ .../app/avroom/dialog/NewUserGiftDialog.kt | 19 + .../app/avroom/dialog/PKMicQueueDialog.java | 545 +++ .../avroom/dialog/PKSelectPeopleDialog.java | 242 ++ .../app/avroom/dialog/PKTimePickerDialog.java | 171 + .../app/avroom/dialog/RequestUpMicDialog.kt | 44 + .../app/avroom/dialog/RoomBgPreviewDialog.kt | 155 + .../chwl/app/avroom/dialog/RoomBgSetDialog.kt | 543 +++ .../app/avroom/dialog/RoomBoomInfoDialog.kt | 201 + .../app/avroom/dialog/RoomBoomRewardDialog.kt | 89 + .../app/avroom/dialog/RoomGameListDialog.kt | 419 ++ .../app/avroom/dialog/RoomGameplayDialog.kt | 420 ++ .../avroom/dialog/RoomLuckyBagBiliDialog.kt | 215 + .../app/avroom/dialog/RoomLuckyBagDialog.kt | 870 ++++ .../avroom/dialog/RoomLuckyBagOpenDialog.kt | 379 ++ .../chwl/app/avroom/dialog/RoomMusicDialog.kt | 30 + .../app/avroom/dialog/RoomNotifyBoomDialog.kt | 57 + .../avroom/dialog/RoomNotifyBravoDialog.kt | 80 + .../avroom/dialog/RoomNotifyCpBindDialog.kt | 89 + .../avroom/dialog/RoomNotifyCpGiftDialog.kt | 31 + .../avroom/dialog/RoomNotifyLevelUpDialog.kt | 96 + .../avroom/dialog/RoomNotifyLuckBagDialog.kt | 82 + .../dialog/RoomNotifyLuckyGiftDialog.kt | 83 + .../avroom/dialog/RoomOperationDialog.java | 830 ++++ .../avroom/dialog/RoomTeamPKResultDialog.java | 351 ++ .../app/avroom/dialog/RoomTeamPkDialog.kt | 325 ++ .../app/avroom/dialog/SelectLabelDialog.kt | 41 + .../app/avroom/dialog/SendBroadcastDialog.kt | 152 + .../app/avroom/dialog/SingleRoomTipDialog.kt | 18 + .../app/avroom/fragment/BaseRoomFragment.kt | 2108 ++++++++++ .../fragment/FakeSingleRoomBackFragment.kt | 123 + .../avroom/fragment/FakeSingleRoomFragment.kt | 119 + .../app/avroom/fragment/GameRoomFragment.kt | 278 ++ .../avroom/fragment/HomePartyFragment.java | 928 +++++ .../fragment/HomePartyRoomFragment.java | 1063 +++++ .../IRoomRankDialogChangePageListener.java | 5 + .../IRoomRankDialogDismissListener.java | 5 + .../fragment/IRoomRankHalfHourView.java | 18 + .../fragment/InputPwdDialogFragment.java | 122 + .../avroom/fragment/OnlineUserFragment.java | 183 + .../app/avroom/fragment/PartyRoomFragment.kt | 34 + .../avroom/fragment/RevelryRoomFragment.kt | 34 + .../app/avroom/fragment/Room19Fragment.kt | 33 + .../app/avroom/fragment/Room20Fragment.kt | 33 + .../fragment/RoomCharmListFragment.java | 41 + .../RoomCharmRankingListFragment.java | 176 + .../fragment/RoomContributeFragment.java | 206 + .../fragment/RoomContributeListFragment.java | 63 + .../fragment/RoomRankDialogFragment.java | 99 + .../avroom/fragment/RoomRankDialogUtils.java | 65 + .../avroom/fragment/RoomRankListFragment.java | 81 + .../fragment/RoomTitleDialogFragment.java | 82 + .../app/avroom/fragment/SingleRoomFragment.kt | 245 ++ .../com/chwl/app/avroom/game/AppConfig.java | 17 + .../com/chwl/app/avroom/game/GameDelegate.kt | 715 ++++ .../avroom/game/OnGameStatusChangeListener.kt | 13 + .../avroom/gameplay/GameplayRecyclerView.kt | 22 + .../avroom/gameplay/RoomGameplayListWidget.kt | 66 + .../app/avroom/gameplay/RoomGameplayWidget.kt | 119 + .../avroom/gameplay/RoomPlayListAdapter.kt | 16 + .../giftvalue/GiftValueDialogUiHelper.java | 133 + .../app/avroom/headline/RoomHeadlineWidget.kt | 113 + .../chwl/app/avroom/helper/AnimHelper.java | 111 + .../chwl/app/avroom/helper/RoomViewModel.java | 30 + .../NewUserChargePrizeDialog.kt | 34 + .../avroom/newuserchargegift/RewardAdapter.kt | 21 + .../avroom/online/RoomOnlineAvatarAdapter.kt | 40 + .../app/avroom/online/RoomOnlineWidget.kt | 230 ++ .../app/avroom/presenter/AvRoomPresenter.java | 535 +++ .../avroom/presenter/BaseRoomPresenter.java | 607 +++ .../presenter/BaseRoomRankPresenter.java | 84 + .../avroom/presenter/CreatePKPresenter.java | 100 + .../avroom/presenter/GameRoomPresenter.java | 14 + .../avroom/presenter/HomePartyPresenter.java | 299 ++ .../presenter/HomePartyUserListPresenter.java | 33 + .../presenter/RecordForPKPresenter.java | 62 + .../avroom/presenter/RoomBlackPresenter.java | 44 + .../presenter/RoomCharmRankingPresenter.java | 68 + .../RoomContributeListPresenter.java | 39 + .../avroom/presenter/RoomInvitePresenter.java | 99 + .../presenter/RoomManagerPresenter.java | 148 + .../avroom/presenter/RoomNewbiePresenter.java | 68 + .../presenter/RoomRankHalfHourPresenter.java | 103 + .../presenter/RoomSettingPresenter.java | 258 ++ .../avroom/presenter/SingleRoomPresenter.java | 15 + .../app/avroom/rank/RoomRankNumberWidget.kt | 91 + .../chwl/app/avroom/rank/RoomRankWidget.kt | 94 + .../MyRecommendCardActivity.java | 86 + .../recommendcard/RecommendCardFragment.java | 132 + .../RecommendCardListAdapter.java | 103 + .../ChooseGiftRoomAlbumDialogFragment.kt | 84 + .../chwl/app/avroom/room_album/PhotoItem.kt | 14 + .../avroom/room_album/RoomAlbumActivity.kt | 121 + .../avroom/room_album/RoomAlbumFragment.kt | 201 + .../room_album/RoomAlbumFragmentViewModel.kt | 69 + .../app/avroom/room_album/RoomAlbumModel.kt | 100 + .../avroom/room_album/RoomAlbumViewModel.kt | 48 + .../room_album/UnlockRoomAlbumPhotoDialog.kt | 59 + .../UploadRoomAlbumDialogFragment.kt | 280 ++ .../singleroompk/SingleRoomPKBoardView.kt | 146 + .../SingleRoomPKCreateActivity.kt | 143 + .../singleroompk/SingleRoomPKRankListView.kt | 61 + .../SingleRoomPKSearchActivity.kt | 94 + .../singleroompk/SingleRoomPKSearchAdapter.kt | 35 + .../singleroompk/SingleRoomPkFinishDialog.kt | 97 + .../SingleRoomPkForceFinishDialog.kt | 54 + .../SingleRoomPkReceivedDialog.kt | 77 + .../singleroompk/SingleRoomPkRuleDialog.kt | 30 + .../com/chwl/app/avroom/view/IAvRoomView.java | 86 + .../com/chwl/app/avroom/view/IBaseRoomView.kt | 76 + .../chwl/app/avroom/view/ICreatePKView.java | 11 + .../chwl/app/avroom/view/IGameRoomView.java | 17 + .../avroom/view/IHomePartyUserListView.java | 22 + .../chwl/app/avroom/view/IHomePartyView.java | 22 + .../avroom/view/ILightChatConsumeView.java | 21 + .../app/avroom/view/ILightChatOnlineView.java | 40 + .../app/avroom/view/ILightChatRoomView.java | 32 + .../app/avroom/view/IRecordForPKView.java | 12 + .../chwl/app/avroom/view/IRoomBlackView.java | 43 + .../view/IRoomCharmRankingListView.java | 12 + .../avroom/view/IRoomContributeListView.java | 16 + .../chwl/app/avroom/view/IRoomInviteView.java | 17 + .../app/avroom/view/IRoomManagerView.java | 20 + .../chwl/app/avroom/view/IRoomMemberView.java | 29 + .../app/avroom/view/IRoomSettingView.java | 42 + .../chwl/app/avroom/view/ISingleRoomView.java | 13 + .../app/avroom/widget/ActivityTimerView.java | 79 + .../chwl/app/avroom/widget/BottomView.java | 594 +++ .../chwl/app/avroom/widget/BravoCoinView.kt | 154 + .../chwl/app/avroom/widget/CoinTipsView.kt | 225 ++ .../avroom/widget/EditRoomTitleDialog.java | 237 ++ .../avroom/widget/FixRoomTitleTextView.java | 38 + .../avroom/widget/GalleryLayoutManager.java | 1071 +++++ .../app/avroom/widget/GiftEffectView.java | 464 +++ .../chwl/app/avroom/widget/GiftV2View.java | 1053 +++++ .../avroom/widget/LollipopFixedWebView.java | 38 + .../com/chwl/app/avroom/widget/LuckyBagBtn.kt | 135 + .../chwl/app/avroom/widget/MagicTextView.java | 329 ++ .../chwl/app/avroom/widget/MessageView.java | 3592 +++++++++++++++++ .../com/chwl/app/avroom/widget/MicroView.java | 368 ++ .../avroom/widget/OnMsgLongClickListener.java | 7 + .../chwl/app/avroom/widget/PKProgressBar.kt | 37 + .../avroom/widget/RankNavigatorAdapter.java | 85 + .../app/avroom/widget/RoomEffectBoxView.kt | 1273 ++++++ .../chwl/app/avroom/widget/RoomEffectView.kt | 2027 ++++++++++ .../widget/RoomRankNavigatorAdapter.java | 83 + .../avroom/widget/RoomRankWrapViewPager.java | 70 + .../app/avroom/widget/ScaleTransformer.java | 23 + .../widget/ScrollSpeedLinearLayoutManger.java | 53 + .../chwl/app/avroom/widget/SliddingView.java | 51 + .../app/avroom/widget/TeamPKUserListView.kt | 46 + .../avroom/widget/TemplateMessageAdapter.kt | 220 + .../com/chwl/app/avroom/widget/VDHLayout.java | 181 + .../widget/VerticalViewPagerAdapter.java | 57 + .../com/chwl/app/avroom/widget/ViewItem.java | 119 + .../chwl/app/avroom/widget/VipProgressBar.kt | 48 + .../chwl/app/base/AbstractMvpActivity.java | 111 + .../chwl/app/base/AbstractMvpFragment.java | 107 + .../java/com/chwl/app/base/BaseActivity.java | 1497 +++++++ .../chwl/app/base/BaseBindingActivity.java | 39 + .../com/chwl/app/base/BaseBindingDialog.java | 91 + .../chwl/app/base/BaseBindingFragment.java | 32 + .../base/BaseBindingTakePhotoActivity.java | 82 + .../java/com/chwl/app/base/BaseBsDialog.java | 58 + .../com/chwl/app/base/BaseDialogFragment.kt | 132 + .../java/com/chwl/app/base/BaseFragment.java | 677 ++++ .../com/chwl/app/base/BaseLazyFragment.java | 58 + .../com/chwl/app/base/BaseListFragment.kt | 109 + .../com/chwl/app/base/BaseListViewModel.java | 66 + .../chwl/app/base/BaseMsListViewModel.java | 72 + .../com/chwl/app/base/BaseMvpActivity.java | 12 + .../com/chwl/app/base/BaseMvpFragment.java | 15 + .../com/chwl/app/base/BaseMvpPresenter.java | 28 + .../java/com/chwl/app/base/BaseSdDialog.java | 43 + .../main/java/com/chwl/app/base/BaseVM.java | 9 + .../chwl/app/base/BaseViewBindingActivity.kt | 39 + .../chwl/app/base/BaseViewBindingFragment.kt | 42 + .../java/com/chwl/app/base/BaseViewModel.kt | 64 + .../chwl/app/base/DialogManagerInterface.java | 10 + app/src/main/java/com/chwl/app/base/Event.kt | 27 + .../com/chwl/app/base/GlobalViewModelOwner.kt | 22 + .../com/chwl/app/base/IAcitivityBase.java | 15 + .../main/java/com/chwl/app/base/IBase.java | 7 + .../java/com/chwl/app/base/IDataStatus.java | 50 + .../com/chwl/app/base/PhotoPickActivity.kt | 204 + .../main/java/com/chwl/app/base/TitleBar.java | 609 +++ .../chwl/app/base/list/BaseRecyclerView.java | 341 ++ .../chwl/app/base/list/BaseViewHolder.java | 508 +++ .../com/chwl/app/base/list/CommonAdapter.java | 117 + .../com/chwl/app/base/list/DefalutStatus.java | 31 + .../java/com/chwl/app/base/list/Header.java | 15 + .../app/base/list/IHeaderHolderListener.java | 9 + .../chwl/app/base/list/IRecyclerListener.java | 34 + .../com/chwl/app/base/list/IStatusView.java | 17 + .../app/base/list/LineColorDecoration.java | 96 + .../chwl/app/base/list/LoadingViewHolder.java | 23 + .../app/base/list/MultiCommonAdapter.java | 42 + .../chwl/app/base/list/MultiItemEntity.java | 9 + .../base/list/OnItemChildClickListener.java | 9 + .../base/list/OnItemParentClickListener.java | 9 + .../app/base/list/RefreshRecyclerView.java | 34 + .../chwl/app/base/list/WrapperAdapter.java | 324 ++ .../bills/activities/BillBaseActivity.java | 185 + .../activities/BillGiftExpendActivity.java | 187 + .../activities/BillGiftInComeActivity.java | 213 + .../BillGiftIncomeGroupActivity.java | 148 + .../bills/activities/BillNobleActivity.java | 155 + .../bills/activities/ChargeBillsActivity.java | 198 + .../bills/activities/ChatBillsActivity.java | 161 + .../bills/activities/RedBagBillsActivity.java | 190 + .../bills/activities/TotalBillsActivity.java | 80 + .../app/bills/adapter/BillBaseAdapter.java | 40 + .../app/bills/adapter/ChargeBillsAdapter.java | 33 + .../app/bills/adapter/ChatBillsAdapter.java | 41 + .../app/bills/adapter/GiftExpendAdapter.java | 40 + .../app/bills/adapter/GiftIncomeAdapter.java | 39 + .../app/bills/adapter/NobleBillAdapter.java | 31 + .../app/bills/adapter/RadishGiftAdapter.java | 47 + .../app/bills/adapter/RedBagBillsAdapter.java | 30 + .../chwl/app/bills/event/DateInfoEvent.java | 15 + .../com/chwl/app/bills/event/TopEvent.java | 10 + .../app/bills/fragmemt/BaseBillsFragment.java | 134 + .../bills/fragmemt/GiftIncomeFragment.java | 148 + .../bills/fragmemt/GiftOutputFragment.java | 142 + .../bills/fragmemt/RadishGiftFragment.java | 155 + .../BillGiftIncomeGroupPresenter.java | 7 + .../bills/presenter/GiftIncomePresenter.java | 29 + .../bills/presenter/GiftOutputPresenter.java | 26 + .../bills/presenter/RadishGiftPresenter.java | 41 + .../bills/view/IBillGiftIncomeGroupView.java | 6 + .../chwl/app/bills/view/IGiftIncomeView.java | 8 + .../chwl/app/bills/view/IGiftOutputView.java | 10 + .../chwl/app/bills/view/IRadishGiftView.java | 8 + .../chwl/app/bills/view/ISmoothToTopView.java | 7 + .../BillGiftIncomeGroupNavigatorAdapter.java | 71 + .../chwl/app/bills/widget/BillItemView.java | 67 + .../com/chwl/app/bindadapter/BaseAdapter.java | 52 + .../app/bindadapter/BaseBindingAdapter.kt | 65 + .../bindadapter/BaseBindingViewHolder.java | 23 + .../app/bindadapter/BindingViewHolder.java | 23 + .../com/chwl/app/bindadapter/RvAdapter.java | 41 + .../com/chwl/app/bindadapter/ViewAdapter.java | 179 + .../chwl/app/common/AbsStatusFragment.java | 36 + .../com/chwl/app/common/CommonPagerAdapter.kt | 14 + .../com/chwl/app/common/EmptyViewHelper.java | 68 + .../com/chwl/app/common/IStatusFragment.java | 10 + .../com/chwl/app/common/LoadingFragment.java | 87 + .../chwl/app/common/NetworkErrorFragment.java | 70 + .../com/chwl/app/common/NoDataFragment.java | 130 + .../com/chwl/app/common/ReloadFragment.java | 125 + .../com/chwl/app/common/ViewPagerAdapter.java | 38 + .../chwl/app/common/app/ActivityStack.java | 167 + .../chwl/app/common/dialog/DialogCommon.kt | 45 + .../common/permission/EasyPermissions.java | 300 ++ .../common/permission/PermissionActivity.java | 133 + .../common/permission/StatusBarCompat.java | 162 + .../app/common/server/NetworkService.java | 207 + .../app/common/svga/SimpleSvgaCallback.java | 29 + .../svga/SimpleSvgaParseCompletion.java | 20 + .../app/common/util/AppLifeCycleHelper.java | 90 + .../com/chwl/app/common/util/BitmapUtil.java | 164 + .../app/common/util/DialogCommonUtil.java | 41 + .../app/common/util/PauseWorkerHandler.java | 86 + .../chwl/app/common/widget/AgeSexView.java | 56 + .../com/chwl/app/common/widget/BadgeView.java | 447 ++ .../widget/ChangeColorIconWithText.java | 278 ++ .../common/widget/CircleGradualImageView.java | 134 + .../app/common/widget/CircleImageSpan.java | 127 + .../app/common/widget/CircleImageView.java | 260 ++ .../widget/CustomAutoWidthImageSpan.java | 144 + .../app/common/widget/CustomImageSpan.java | 355 ++ .../chwl/app/common/widget/DragLayout.java | 195 + .../common/widget/FloatingLiveMiniView.java | 99 + .../chwl/app/common/widget/LimitEditText.java | 94 + .../app/common/widget/LoadingImageView.java | 59 + .../chwl/app/common/widget/MaskImageView.java | 208 + .../widget/OriginalDrawStatusClickSpan.java | 42 + .../chwl/app/common/widget/OvalImageView.java | 63 + .../chwl/app/common/widget/PlayerView.java | 54 + .../app/common/widget/RectRoundImageView.java | 94 + .../app/common/widget/SlideListViewPager.java | 58 + .../chwl/app/common/widget/StatusLayout.java | 127 + .../chwl/app/common/widget/TextDrawable.java | 66 + .../app/common/widget/TutuSwitchView.java | 29 + .../widget/dialog/BaseAlertDialogBuilder.java | 18 + .../dialog/ChooseWorldsIndicatorAdapter.java | 77 + .../widget/dialog/CommonPopupDialog.java | 160 + .../widget/dialog/CustomPopupDialog.java | 118 + .../common/widget/dialog/DialogManager.java | 1199 ++++++ .../common/widget/dialog/DialogUiHelper.java | 80 + .../widget/dialog/ListViewMenuItem.java | 31 + .../widget/dialog/LoadingImageView.java | 57 + .../widget/dialog/TimeOutProgressDialog.java | 89 + .../java/com/chwl/app/constants/AnyType.java | 9 + .../com/chwl/app/constants/BundleKeys.java | 24 + .../chwl/app/constants/UserInfoConstants.java | 10 + .../decoration/adapter/CarShopAdapter.java | 69 + .../adapter/DecorationCommonAdapter.kt | 22 + .../app/decoration/adapter/DressUpAdapter.kt | 141 + .../app/decoration/adapter/MyCarAdapter.java | 146 + .../adapter/MyChatBubbleAdapter.java | 80 + .../decoration/adapter/MyHeadWearAdapter.java | 81 + .../adapter/MyNamePlateAdapter.java | 63 + .../adapter/MyUserCardWearAdapter.java | 120 + .../helper/DecorationDialogHelper.java | 363 ++ .../decoration/helper/DecorationHelper.java | 76 + .../decoration/helper/DecorationSaleType.java | 14 + .../chwl/app/decoration/ui/DressUpDialog.kt | 182 + .../ui/activity/DressUpTabActivity.kt | 246 ++ .../ui/fragment/DressUpMyFragment.kt | 576 +++ .../ui/fragment/DressUpStoreFragment.kt | 193 + .../chwl/app/decoration/util/DressUpUtil.kt | 548 +++ .../view/DecorationCommonFragment.kt | 110 + .../view/DecorationStoreActivity.kt | 132 + .../chwl/app/decoration/view/ICarView.java | 24 + .../app/decoration/view/MyCarFragment.java | 174 + .../decoration/view/MyChatBubbleFragment.java | 108 + .../decoration/view/MyDecorationActivity.java | 301 ++ .../decoration/view/MyHeadWearFragment.java | 160 + .../decoration/view/MyNamePlateFragment.java | 156 + .../view/MyUserCardWearFragment.java | 110 + .../BadgeScaleTransitionPagerTitleView.java | 97 + .../view/widgets/CarMagicIndicator.java | 73 + .../widgets/MyDecorationMagicIndicator.java | 77 + .../app/decoration/viewmodel/CarShopVm.java | 28 + .../viewmodel/DecorationViewModel.kt | 56 + .../app/decoration/viewmodel/HeadWearVm.java | 44 + .../app/decoration/viewmodel/MyCarVm.java | 26 + .../decoration/viewmodel/UserCardWearVm.java | 27 + .../viewmodel/UserChatBubbleVm.java | 27 + .../com/chwl/app/earn/EarnRecordViewModel.kt | 176 + .../earn/activity/ConvertDiamondActivity.kt | 191 + .../app/earn/activity/EarnRecordActivity.kt | 116 + .../app/earn/activity/GoldDetailActivity.kt | 349 ++ .../app/earn/adapter/GoldDetailAdapter.kt | 26 + .../app/earn/adapter/GoldRecordAdapter.kt | 27 + .../chwl/app/earn/adapter/GoldRoomAdapter.kt | 45 + .../java/com/chwl/app/event/ChargeEvent.java | 14 + .../java/com/chwl/app/event/DressUpEvent.java | 29 + .../chwl/app/event/OpenRoomIntroEvent.java | 4 + .../chwl/app/fansteam/FansTeamJoinActivity.kt | 108 + .../app/fansteam/FansTeamJoinedActivity.kt | 135 + .../chwl/app/fansteam/FansTeamListActivity.kt | 70 + .../chwl/app/fansteam/FansTeamListAdapter.kt | 35 + .../chwl/app/fansteam/FansTeamTaskAdapter.kt | 34 + .../chwl/app/fansteam/FansTeamViewModel.kt | 75 + .../main/java/com/chwl/app/friend/Holder.java | 8 + .../action/AbstractSelectFriendAction.java | 44 + .../action/DefaultSelectFriendAction.java | 13 + .../friend/action/SelectFriendManager.java | 34 + .../app/friend/view/SelectFriendActivity.java | 318 ++ .../com/chwl/app/guide/GuideActivity.java | 92 + .../java/com/chwl/app/home/HomeMeViewModel.kt | 45 + .../com/chwl/app/home/HomeMessageViewModel.kt | 26 + .../java/com/chwl/app/home/HomeViewModel.kt | 106 + .../java/com/chwl/app/home/MeViewModel.kt | 79 + .../com/chwl/app/home/RoomCommonViewModel.kt | 29 + .../com/chwl/app/home/RoomSingleViewModel.kt | 27 + .../app/home/activity/AssociationActivity.kt | 95 + .../home/activity/CollectionRoomActivity.java | 108 + .../app/home/activity/CommunityNoticeAct.java | 152 + .../app/home/activity/EventCenterActivity.kt | 77 + .../app/home/activity/EventCreateActivity.kt | 562 +++ .../app/home/activity/EventMyAllActivity.kt | 208 + .../home/activity/EventSelectRoomActivity.kt | 126 + .../home/activity/NewUserListActivity.java | 139 + .../home/activity/RoomHistoryListActivity.kt | 97 + .../app/home/activity/VisitorListActivity.kt | 101 + .../chwl/app/home/adapter/BannerAdapter.java | 86 + .../home/adapter/CollectionRoomAdapter.java | 35 + .../home/adapter/CommunityNoticeAdapter.java | 88 + .../adapter/ContactsIndicatorAdapter.java | 117 + .../app/home/adapter/EventOfficialAdapter.kt | 90 + .../home/adapter/EventSelectRoomAdapter.kt | 22 + .../app/home/adapter/EventSquareAdapter.kt | 110 + .../home/adapter/FindNewUserListAdapter.java | 56 + .../adapter/FragmentViewPagerAdapter.java | 34 + .../app/home/adapter/HomeBannerAdapter.kt | 100 + .../chwl/app/home/adapter/HomeChatAdapter.kt | 39 + .../app/home/adapter/HomeConcernsAdapter.java | 54 + .../home/adapter/HomeIndicatorAdapter.java | 103 + .../app/home/adapter/HomeLiveTopAdapter.kt | 34 + .../adapter/HomeRankViewFlipperAdapter.kt | 62 + .../chwl/app/home/adapter/HomeRoomAdapter.kt | 192 + .../home/adapter/HomeRoomFragmentAdapter.java | 85 + .../app/home/adapter/HomeRoomUserAdapter.kt | 16 + .../chwl/app/home/adapter/HomeTopAdapter.java | 60 + .../adapter/MainMagicIndicatorAdapter.java | 110 + .../chwl/app/home/adapter/MeCenterAdapter.kt | 49 + .../chwl/app/home/adapter/MeGameAdapter.kt | 19 + .../chwl/app/home/adapter/RoomActAdapter.kt | 51 + .../app/home/adapter/RoomCommonAdapter.kt | 28 + .../chwl/app/home/adapter/RoomGameAdapter.kt | 61 + .../home/adapter/RoomHistoryListAdapter.kt | 32 + .../app/home/adapter/RoomNewFriendsAdapter.kt | 232 ++ .../adapter/TopMagicIndicatorAdapter.java | 83 + .../app/home/adapter/VisitorListAdapter.java | 107 + .../app/home/dialog/EventDurationDialog.kt | 124 + .../app/home/dialog/HelloMessageDialog.kt | 63 + .../app/home/dialog/NewUserHelloDialog.kt | 54 + .../app/home/dialog/ProtocolUpdateDialog.java | 112 + .../app/home/dialog/RecommendRoomDialog.kt | 40 + .../app/home/event/ContactTrashEvent.java | 4 + .../app/home/fragment/AttentionFragment.java | 272 ++ .../app/home/fragment/ContactsListFragment.kt | 171 + .../chwl/app/home/fragment/EventMyFragment.kt | 302 ++ .../home/fragment/EventOfficialFragment.kt | 104 + .../app/home/fragment/EventSquareFragment.kt | 178 + .../chwl/app/home/fragment/HomeFragment.kt | 131 + .../home/fragment/HomeRecommendFragment.kt | 400 ++ .../fragment/HomeRoomCollectListFragment.kt | 102 + .../fragment/HomeRoomHistoryListFragment.kt | 102 + .../app/home/fragment/HomeTabRoomFragment.kt | 156 + .../app/home/fragment/HomeWithMeFragment.kt | 119 + .../com/chwl/app/home/fragment/MeFragment.kt | 424 ++ .../chwl/app/home/helper/AutoScrollTask.kt | 23 + .../com/chwl/app/home/helper/BannerHelper.kt | 80 + .../chwl/app/home/helper/EventCenterUtil.kt | 32 + .../app/home/helper/LoadPageDataHelper.java | 61 + .../chwl/app/home/helper/OpenRoomHelper.java | 245 ++ .../presenter/CommunityNoticePresenter.java | 91 + .../home/presenter/MainFragmentPresenter.java | 87 + .../app/home/presenter/MainPresenter.java | 40 + .../home/presenter/NewUserListPresenter.java | 49 + .../app/home/view/ICommunityNoticeAct.java | 14 + .../home/view/IFamilyHomeActivityView.java | 21 + .../chwl/app/home/view/IMainFragmentView.java | 34 + .../com/chwl/app/home/view/IMainView.java | 17 + .../home/view/INewUserListActivityView.java | 11 + .../chwl/app/home/widget/AnchorCardView.kt | 249 ++ .../app/home/widget/ListViewAdaptWidth.java | 47 + .../app/home/widget/MePageIndicatorView.java | 133 + .../app/home/widget/StickyScrollView.java | 396 ++ .../adapter/LuckyMoneyMemberListAdapter.java | 57 + .../dialog/LuckyMoneyComfirmToPayDialog.java | 22 + .../luckymoney/dialog/LuckyMoneyDialog.java | 234 ++ .../view/LuckyMoneyCreationActivity.java | 322 ++ .../view/LuckyMoneyDetailActivity.java | 130 + .../viewholder/LuckyMoneyMsgViewHolder.java | 126 + .../viewholder/LuckyMoneyTipsViewHolder.java | 89 + .../main/java/com/chwl/app/module/Extras.java | 16 + .../app/module/IRoomNewbieMessageView.java | 9 + .../com/chwl/app/module/IRoomNewbieView.java | 14 + .../com/chwl/app/module/RoomNewbieModel.java | 103 + .../app/monsterhunting/ImpactValueLayout.java | 71 + .../monsterhunting/MonsterEscapeDialog.java | 80 + .../MonsterHuntingAnimationManager.java | 259 ++ .../MonsterHuntingIntroductionDialog.java | 63 + .../MonsterHuntingRewardDialog.java | 156 + .../MonsterHuntingRewardsAdapter.java | 96 + .../MonsterHuntingSvgaManager.java | 209 + .../app/monsterhunting/QuitConfirmDialog.java | 69 + .../monsterhunting/SimpleCountDownTimer.java | 31 + .../bean/AttackMonsterResultInfo.java | 53 + .../monsterhunting/bean/UpdateMyGoldInfo.java | 32 + .../chwl/app/notify/GlobalNotifyManager.kt | 270 ++ .../chwl/app/notify/GlobalNotifyManagerNew.kt | 248 ++ .../java/com/chwl/app/notify/NotifyAdapter.kt | 80 + .../com/chwl/app/notify/RoomNotifyManager.kt | 131 + .../app/notify/views/BaiShunGameNotify.kt | 180 + .../app/notify/views/FindLoveImageNotify.kt | 62 + .../com/chwl/app/notify/views/GiftNotify.kt | 132 + .../app/notify/views/LuckyBagGiftNotify.kt | 108 + .../app/notify/views/TemplateImageNotify.kt | 100 + .../app/notify/views/TemplateSvgaNotify.kt | 106 + .../com/chwl/app/notify/views/TestNotify.kt | 30 + .../app/other/SplashBitmapTransformation.java | 54 + .../app/other/activity/SplashActivity.java | 343 ++ .../other/dialog/PrivacyAgreementDialog.java | 122 + .../app/other/present/SplashPresenter.java | 15 + .../com/chwl/app/other/view/ISplashView.java | 18 + .../java/com/chwl/app/pay/GiveGoldModel.kt | 68 + .../chwl/app/pay/activity/GiveGoldActivity.kt | 251 ++ .../pay/activity/GiveGoldAgentsActivity.kt | 103 + .../app/pay/activity/GiveGoldBiliActivity.kt | 432 ++ .../pay/activity/GiveGoldDetailActivity.kt | 115 + .../pay/activity/GiveGoldSearchActivity.kt | 84 + .../pay/activity/GiveGoldToUserActivity.kt | 420 ++ .../pay/adapter/GiveDiamondDetailAdapter.kt | 29 + .../chwl/app/pay/adapter/GiveGiftAdapter.java | 34 + .../app/pay/adapter/GiveGiftDetailAdapter.kt | 24 + .../chwl/app/pay/adapter/GiveSearchAdapter.kt | 22 + .../chwl/app/pay/adapter/LatelyGiveAdapter.kt | 25 + .../app/pay/fragment/GiveDiamondFragment.kt | 73 + .../chwl/app/pay/fragment/GiveGiftFragment.kt | 73 + .../chwl/app/pay/interfaces/PasswordView.java | 23 + .../password/GiveGoldPassWordFragment.java | 132 + .../pay/password/GiveGoldPasswordView.java | 135 + .../app/pay/presenter/ChargePresenter.java | 37 + .../chwl/app/pay/presenter/PayPresenter.java | 49 + .../com/chwl/app/pay/view/IChargeView.java | 13 + .../java/com/chwl/app/pay/view/IPayView.java | 16 + .../pay/widget/GridPasswordNoFocusView.java | 436 ++ .../com/chwl/app/photo/BigPagerAdapter.java | 70 + .../com/chwl/app/photo/BigPhotoActivity.java | 208 + .../chwl/app/photo/BigPhotoItemFragment.java | 157 + .../chwl/app/photo/DynamicImageAdapter.java | 76 + .../app/photo/OnFragmentOptionListener.java | 12 + .../java/com/chwl/app/photo/PagerOption.java | 51 + .../java/com/chwl/app/photo/PhotoAdapter.java | 94 + .../chwl/app/photo/PreviewPhotoActivity.java | 88 + .../com/chwl/app/photo/ZoomImageView.java | 476 +++ .../radish/activity/RadishRecordActivity.java | 128 + .../radish/adapter/RadishRecordAdapter.java | 38 + .../app/radish/helper/PrizeAnimUiHelper.java | 202 + .../radish/helper/TaskCenterDialogHelper.java | 34 + .../presenter/RadishRecordFrgPresenter.java | 42 + .../presenter/RadishRecordPresenter.java | 28 + .../task/activity/TaskCenterActivity.java | 167 + .../radish/task/adpter/TaskCenterAdapter.java | 70 + .../task/fragment/TaskCenterFragment.java | 194 + .../presenter/TaskCenterFrgPresenter.java | 7 + .../task/presenter/TaskCenterPresenter.java | 12 + .../app/radish/task/view/ITaskCenterView.java | 11 + .../radish/task/view/ITaskCenterViewFrg.java | 6 + .../app/radish/view/IRadishRecordFrgView.java | 9 + .../app/radish/view/IRadishRecordView.java | 6 + .../radish/wallet/RadishWalletManager.java | 59 + .../radish/widget/RadishRecordNavAdapter.java | 77 + .../radish/widget/TaskCenterNavAdapter.java | 77 + .../app/reciever/IncomingCallReceiver.java | 23 + .../reciever/NotificationClickReceiver.java | 24 + .../chwl/app/reciever/OnePixelReceiver.java | 33 + .../chwl/app/relation/cp/CpDataManager.java | 30 + .../com/chwl/app/relation/cp/CpDataParser.kt | 51 + .../com/chwl/app/relation/cp/CpViewHelper.kt | 111 + .../relation/cp/activity/CpHomeActivity.kt | 122 + .../cp/activity/CpInviteRecordActivity.kt | 149 + .../relation/cp/activity/CpTaskActivity.kt | 152 + .../app/relation/cp/adapter/CpTaskAdapter.kt | 20 + .../cp/adapter/CpTaskIndicatorAdapter.java | 97 + .../cp/adapter/DeclarationRecommondAdapter.kt | 12 + .../cp/adapter/InviteRecordAdapter.kt | 52 + .../relation/cp/adapter/TaskPagerAdapter.kt | 13 + .../app/relation/cp/dialog/CpGlobalDialog.kt | 112 + .../relation/cp/dialog/CpInvitePageDialog.kt | 92 + .../cp/dialog/CpInviteReplyConfirmDialog.kt | 41 + .../relation/cp/dialog/CpInviteReplyDialog.kt | 133 + .../chwl/app/relation/cp/dialog/CpMpDialog.kt | 67 + .../relation/cp/fragment/CpTaskFragment.kt | 47 + .../cp/fragment/UserInfoCpFragment.kt | 114 + .../com/chwl/app/relation/cp/model/Api.kt | 121 + .../com/chwl/app/relation/cp/model/CpModel.kt | 77 + .../app/relation/cp/viewmodel/CpViewModel.kt | 183 + .../cp/widget/CpTaskDescriptionView.kt | 95 + .../relation/cp/widget/RelationCpCardView.kt | 174 + .../relation/extention/RelationExtention.kt | 7 + .../com/chwl/app/service/DaemonService.java | 117 + .../main/java/com/chwl/app/share/Holder.java | 8 + .../viewholder/InAppSharingMsgViewHolder.java | 113 + .../com/chwl/app/skill/SKillDataParser.kt | 106 + .../com/chwl/app/skill/SkillDataDelegate.kt | 203 + .../app/skill/activity/AddSkillActivity.kt | 132 + .../app/skill/activity/EditSkillActivity.kt | 101 + .../app/skill/activity/SkillDetailActivity.kt | 64 + .../skill/activity/SkillEditableDelegate.kt | 90 + .../app/skill/activity/SkillHomeActivity.kt | 178 + .../app/skill/adapter/AddSkillCardAdapter.kt | 19 + .../app/skill/adapter/MineSkillCardAdapter.kt | 38 + .../skill/adapter/SkillSelectionAdapter.kt | 104 + .../skill/decoration/SkillGridDecoration.kt | 29 + .../SkillLinearVerticalDecoration.kt | 36 + .../app/skill/dialog/AddSkillCardDialog.kt | 45 + .../app/skill/dialog/SkillSelectionDialog.kt | 43 + .../java/com/chwl/app/skill/repository/Api.kt | 35 + .../chwl/app/skill/repository/ISkillModel.kt | 19 + .../skill/repository/SkillDataManager.java | 31 + .../chwl/app/skill/repository/SkillModel.kt | 59 + .../com/chwl/app/skill/widget/EditItem.kt | 55 + .../chwl/app/skill/widget/ItemAttribute.kt | 29 + .../app/skill/widget/ItemEventListener.kt | 9 + .../app/skill/widget/RecordDurationItem.kt | 21 + .../app/skill/widget/RecordIResourceItem.kt | 202 + .../chwl/app/skill/widget/SelectionItem.kt | 58 + .../chwl/app/skill/widget/SkillAttribute.kt | 20 + .../chwl/app/skill/widget/SkillCardView.kt | 135 + .../com/chwl/app/skill/widget/SkillItem.kt | 11 + .../chwl/app/skill/widget/SkillItemHelper.kt | 58 + .../app/skill/widget/TimerRecorderView.kt | 179 + .../com/chwl/app/star/DefAnimatorListener.kt | 18 + .../com/chwl/app/star/SendGiftTipsDialog.kt | 71 + .../java/com/chwl/app/star/StarAdapter.kt | 28 + .../java/com/chwl/app/star/StarFragment.kt | 355 ++ .../java/com/chwl/app/star/StarViewModel.kt | 121 + .../app/support/FragmentVisibleStateHelper.kt | 57 + .../chwl/app/support/IMUserInfoProvider.kt | 26 + .../app/support/PreloadResourceViewModel.kt | 202 + .../chwl/app/support/float/BaseFloatView.kt | 91 + .../com/chwl/app/support/float/DoubleQueue.kt | 62 + .../com/chwl/app/support/float/FloatQueue.kt | 48 + .../com/chwl/app/support/float/FloatView.kt | 12 + .../app/support/float/FloatViewAdapter.kt | 10 + .../com/chwl/app/support/float/FloatWindow.kt | 41 + .../app/support/float/FloatWindowEngine.kt | 90 + .../com/chwl/app/support/float/QueueItem.kt | 8 + .../app/support/float/SimpleFloatQueue.kt | 101 + .../app/support/float/SimpleFloatWindow.kt | 83 + .../chwl/app/sys/ErbanSysMsgViewModel.java | 30 + .../team/adapter/AddTeamMemberAdapter.java | 62 + .../app/team/adapter/TeamListAdapter.java | 48 + .../team/adapter/TeamMemberListAdapter.java | 154 + .../team/adapter/TeamWeeklyBillAdapter.java | 71 + .../com/chwl/app/team/bean/NimTeamMember.java | 85 + .../chwl/app/team/dialog/QuitTeamDialog.java | 14 + .../app/team/event/TeamMemberUpdateEvent.java | 11 + .../chwl/app/team/view/AddMemberActivity.java | 265 ++ .../team/view/AddMemberSearchActivity.java | 221 + .../team/view/CreateTeamMessageActivity.java | 196 + .../team/view/NimTeamManagementActivity.java | 387 ++ .../app/team/view/NimTeamMessageActivity.java | 414 ++ .../app/team/view/NimTeamMessageFragment.java | 145 + .../chwl/app/team/view/TeamListFragment.java | 79 + .../app/team/view/TeamMemberListActivity.java | 376 ++ .../view/TeamMemberSearchListActivity.java | 290 ++ .../app/team/view/TeamWeeklyBillActivity.java | 168 + .../view/TeamWeeklyBillSearchActivity.java | 197 + .../app/team/view/UpdateTeamNameActivity.java | 78 + .../app/team/viewmodel/FamilyMemberVM.java | 27 + .../com/chwl/app/team/viewmodel/TeamVM.java | 265 ++ .../com/chwl/app/ui/adapter/GiftAdapter.kt | 21 + .../chwl/app/ui/adapter/StarWeekAdapter.java | 52 + .../com/chwl/app/ui/anim/AnimFactory.java | 206 + .../chwl/app/ui/anim/FlowFaceDrawable.java | 208 + .../com/chwl/app/ui/anim/FrameAnimation.java | 333 ++ .../com/chwl/app/ui/anim/OneFaceDrawable.java | 131 + .../chwl/app/ui/anim/OverlayFaceDrawable.java | 190 + .../com/chwl/app/ui/anim/WavingDrawable.java | 92 + .../com/chwl/app/ui/bean/BaseResponse.java | 34 + .../com/chwl/app/ui/bean/CountryBean.java | 12 + .../chwl/app/ui/bean/FirstRechargeInfo.java | 13 + .../java/com/chwl/app/ui/bean/Footer.java | 8 + .../chwl/app/ui/bean/FooterLoadMoreBean.java | 16 + .../chwl/app/ui/bean/GiveGoldAgentBean.java | 20 + .../chwl/app/ui/bean/GiveGoldBiliBean.java | 25 + .../chwl/app/ui/bean/GiveGoldBiliEntity.java | 23 + .../com/chwl/app/ui/bean/LevelChargeBean.java | 13 + .../chwl/app/ui/bean/RechargeUserInfo.java | 24 + .../java/com/chwl/app/ui/bean/ShareInfo.java | 16 + .../java/com/chwl/app/ui/bean/header.java | 8 + .../com/chwl/app/ui/debug/DebugActivity.kt | 50 + .../com/chwl/app/ui/debug/DebugAdapter.kt | 47 + .../app/ui/feedback/CustomerServiceDialog.kt | 61 + .../ui/feedback/CustomerServiceItemAdapter.kt | 34 + .../chwl/app/ui/feedback/FeedbackActivity.kt | 295 ++ .../app/ui/feedback/FeedbackTypeAdapter.kt | 42 + .../chwl/app/ui/feedback/FeedbackViewModel.kt | 36 + .../game_team/invite/GameTeamInviteDialog.kt | 202 + .../invite/GameTeamInviteViewModel.kt | 22 + .../record/GameTeamRecordActivity.kt | 63 + .../game_team/record/GameTeamRecordAdapter.kt | 38 + .../record/GameTeamRecordFragment.kt | 154 + .../GameTeamRecordIndicatorAdapter.java | 103 + .../record/GameTeamRecordViewModel.kt | 23 + .../app/ui/gift/adapter/FaceGVAdapter.java | 143 + .../app/ui/gift/adapter/FaceVPAdapter.java | 40 + .../OnGiftDialogBtnClickListenerWrapper.java | 16 + .../chwl/app/ui/gift/dialog/GiftGridView.java | 165 + .../chwl/app/ui/gift/dialog/GiftInfoVm.java | 145 + .../app/ui/gift/dialog/PageIndicatorView.java | 133 + .../app/ui/gift/gif/AnimatedGifDrawable.java | 64 + .../app/ui/gift/gif/AnimatedImageSpan.java | 78 + .../com/chwl/app/ui/gift/gif/GifDecoder.java | 625 +++ .../chwl/app/ui/gift/util/ExpressionUtil.java | 261 ++ .../app/ui/gift/util/GiftPanelControl.java | 220 + .../chwl/app/ui/gift/util/GlideCacheUtil.java | 175 + .../app/ui/gift/util/RecyclerViewUtil.java | 86 + .../chwl/app/ui/gift/widget/CustormAnim.java | 91 + .../app/ui/gift/widget/GiftAnimationUtil.java | 127 + .../chwl/app/ui/gift/widget/GiftControl.java | 282 ++ .../chwl/app/ui/gift/widget/GiftDataInfo.java | 131 + .../app/ui/gift/widget/GiftFrameLayout.java | 494 +++ .../ui/gift/widget/GlideCircleTransform.java | 61 + .../chwl/app/ui/gift/widget/ICustormAnim.java | 14 + .../app/ui/gift/widget/NumberTextView.java | 92 + .../app/ui/gift/widget/StrokeTextView.java | 95 + .../com/chwl/app/ui/im/GreetPresenter.java | 42 + .../java/com/chwl/app/ui/im/ImInitHelper.java | 220 + .../chwl/app/ui/im/MessageListPanelEx.java | 1385 +++++++ .../chwl/app/ui/im/MsgViewHolderAitMe.java | 55 + .../com/chwl/app/ui/im/RouterHandler.java | 321 ++ .../app/ui/im/actions/ChatterBoxAction.java | 42 + .../app/ui/im/actions/FamilyGameAction.java | 29 + .../chwl/app/ui/im/actions/GiftAction.java | 75 + .../app/ui/im/actions/GiftActionEvent.java | 43 + .../app/ui/im/actions/LuckyMoneyAction.java | 31 + .../ui/im/audio/ShakeHeartDialogFragment.java | 174 + .../ui/im/avtivity/AddBlackListActivity.java | 155 + .../ui/im/avtivity/AddBlackListPresenter.java | 29 + .../ui/im/avtivity/BaseMessageActivity.java | 205 + .../app/ui/im/avtivity/BlackListAdapter.java | 148 + .../im/avtivity/BlackListManageActivity.java | 121 + .../im/avtivity/BlackListManagePresenter.java | 26 + .../app/ui/im/avtivity/IAddBlackListView.java | 27 + .../ui/im/avtivity/IBlackListManageView.java | 29 + .../im/avtivity/NewBaseMessageActivity.java | 200 + .../app/ui/im/avtivity/NimFriendModel.java | 164 + .../ui/im/avtivity/NimP2PMessageActivity.java | 512 +++ .../ui/im/avtivity/SwipeRecyclerViewItem.java | 149 + .../ui/im/chat/GameTeamInviteViewHolder.kt | 118 + .../app/ui/im/chat/MVHChatterBoxStart.java | 169 + .../ui/im/chat/MsgViewHolderAudioParty.java | 78 + .../app/ui/im/chat/MsgViewHolderChatHint.java | 51 + .../app/ui/im/chat/MsgViewHolderConfirm.java | 217 + .../app/ui/im/chat/MsgViewHolderContent.java | 66 + .../MsgViewHolderCpRelationalConfirm.java | 173 + .../chat/MsgViewHolderCpRelationalNotify.java | 82 + .../chat/MsgViewHolderEventStartNotify.java | 110 + .../app/ui/im/chat/MsgViewHolderFairy.java | 93 + .../app/ui/im/chat/MsgViewHolderGift.java | 71 + .../app/ui/im/chat/MsgViewHolderHello.java | 76 + .../app/ui/im/chat/MsgViewHolderLevel.java | 55 + .../app/ui/im/chat/MsgViewHolderLottery.java | 40 + .../app/ui/im/chat/MsgViewHolderOnline.java | 69 + .../chat/MsgViewHolderP2PContactRecharge.java | 81 + .../ui/im/chat/MsgViewHolderRedPacket.java | 47 + .../app/ui/im/chat/MsgViewHolderSkill.java | 53 + .../app/ui/im/chat/MsgViewHolderText.java | 162 + .../app/ui/im/chat/SysMsgV2ViewHolder.java | 300 ++ .../chwl/app/ui/im/chat/SysMsgViewHolder.java | 310 ++ .../app/ui/im/fragment/MessageFragment.java | 745 ++++ .../chwl/app/ui/im/friend/ActFriendList.java | 36 + .../ui/im/friend/FriendFragmentCpDelegate.kt | 108 + .../app/ui/im/friend/FriendListAdapter.java | 191 + .../app/ui/im/friend/FriendListFragment.java | 264 ++ .../ui/im/friend/FriendListFragmentKotlin.kt | 157 + .../chwl/app/ui/im/model/IMCustomModel.java | 55 + .../ui/im/recent/RecentContactsFragment.java | 734 ++++ .../app/ui/im/recent/RecentListFragment.java | 273 ++ .../com/chwl/app/ui/im/recent/TeamExt.java | 21 + .../adapter/AttentionInRoomAdapter.java | 63 + .../recent/adapter/RecentContactAdapter.java | 52 + .../recent/holder/CommonRecentViewHolder.java | 172 + .../ui/im/recent/holder/RecentViewHolder.java | 186 + .../recent/holder/TeamRecentViewHolder.java | 221 + .../ui/indicator_impl/IndicatorHelper.java | 38 + .../JustColorIndicatorAdapter.java | 79 + .../indicator_impl/OnItemSelectListener.java | 12 + .../chwl/app/ui/invite/InviteImageHelper.kt | 196 + .../chwl/app/ui/invite/ShareInviteDialog.kt | 81 + .../com/chwl/app/ui/invite/ShareInviteInfo.kt | 31 + .../app/ui/keepalive/OnePiexlActivity.java | 71 + .../chwl/app/ui/language/LanguageActivity.kt | 84 + .../chwl/app/ui/language/LanguageAdapter.kt | 41 + .../com/chwl/app/ui/language/LanguageItem.kt | 7 + .../java/com/chwl/app/ui/link/LinkActivity.kt | 56 + .../java/com/chwl/app/ui/link/LinkHelper.kt | 22 + .../java/com/chwl/app/ui/link/LinkIntent.kt | 17 + .../com/chwl/app/ui/list/BaseListAdapter.java | 62 + .../chwl/app/ui/login/AccountValidator.java | 104 + .../app/ui/login/AddUserInfoActivity.java | 63 + .../com/chwl/app/ui/login/AreaCodeActivity.kt | 100 + .../chwl/app/ui/login/BindCodeActivity.java | 205 + .../chwl/app/ui/login/BindEmailActivity.kt | 198 + .../chwl/app/ui/login/BindPhoneActivity.kt | 219 + .../chwl/app/ui/login/BindSuccessDialog.java | 68 + .../chwl/app/ui/login/CodeDownDescTimer.java | 49 + .../com/chwl/app/ui/login/CodeDownTimer.java | 69 + .../chwl/app/ui/login/LoginCodeActivity.kt | 273 ++ .../app/ui/login/LoginPasswordActivity.java | 756 ++++ .../chwl/app/ui/login/LoginPhoneActivity.kt | 155 + .../app/ui/login/LoginVerifyActivity.java | 433 ++ .../chwl/app/ui/login/ModifyInfoActivity.java | 191 + .../chwl/app/ui/login/PasswordValidator.java | 61 + .../chwl/app/ui/login/RegionListAdapter.kt | 32 + .../app/ui/login/ShowBindEmailActivity.kt | 53 + .../app/ui/login/ShowBindPhoneActivity.kt | 54 + .../ui/login/dialog/CountrySelectDialog.kt | 102 + .../login/fragment/AddUserInfoFragment.java | 391 ++ .../app/ui/login/helper/LogoutHelper.java | 81 + .../chwl/app/ui/login/ui/CodeEditText.java | 236 ++ .../ui/patriarch/PatriarchModeActivity.java | 58 + .../ui/patriarch/PatriarchPwdActivity.java | 130 + .../patriarch/help/LimitEnterRoomHelper.java | 79 + .../ui/patriarch/help/PmDialogShowMrg.java | 172 + .../com/chwl/app/ui/pay/ChargeActivity.java | 433 ++ .../com/chwl/app/ui/pay/ChargeAdapter.java | 58 + .../chwl/app/ui/praise/BezierEvaluator.java | 32 + .../java/com/chwl/app/ui/praise/HPUtils.java | 15 + .../java/com/chwl/app/ui/praise/HiPraise.java | 34 + .../app/ui/praise/HiPraiseAnimationView.java | 172 + .../app/ui/praise/HiPraiseWithCallback.java | 22 + .../chwl/app/ui/praise/OnDrawCallback.java | 13 + .../chwl/app/ui/praise/PraiseDrawable.java | 253 ++ .../ui/praise/PraiseWithCallbackDrawable.java | 24 + .../chwl/app/ui/praise/SimpleDrawTask.java | 131 + .../com/chwl/app/ui/praise/UpdateThread.java | 26 + .../chwl/app/ui/praise/base/IDrawTask.java | 17 + .../chwl/app/ui/praise/base/IDrawable.java | 22 + .../com/chwl/app/ui/praise/base/IPraise.java | 12 + .../chwl/app/ui/praise/base/IPraiseView.java | 12 + .../app/ui/radish/RadishRecordFragment.java | 152 + .../ui/relation/AttentionListActivity.java | 242 ++ .../chwl/app/ui/relation/FansListActivity.kt | 111 + .../app/ui/relation/FansListFragment.java | 282 ++ .../adapter/AttentionListAdapter.java | 146 + .../ui/relation/adapter/FansViewAdapter.java | 143 + .../app/ui/search/RoomHistoryAdapter.java | 41 + .../chwl/app/ui/search/SearchActivity.java | 651 +++ .../com/chwl/app/ui/search/SearchAdapter.java | 164 + .../app/ui/search/SearchDetailFragment.java | 233 ++ .../app/ui/search/SearchHallActivity.java | 282 ++ .../app/ui/search/SearchHistoryAdapter.java | 32 + .../chwl/app/ui/search/SearchUserActivity.kt | 158 + .../chwl/app/ui/search/event/SearchEvent.java | 10 + .../ui/search/presenter/SearchPresenter.java | 111 + .../chwl/app/ui/search/view/ISearchView.java | 30 + .../ui/setting/GrantedPermissionsActivity.kt | 103 + .../com/chwl/app/ui/setting/LabActivity.java | 73 + .../app/ui/setting/ModifyPwdActivity.java | 348 ++ .../app/ui/setting/NoticeSettingActivity.java | 158 + .../app/ui/setting/PermissionGuideActivity.kt | 68 + .../ui/setting/PrivacySettingActivity.java | 144 + .../app/ui/setting/ResetPasswordActivity.kt | 333 ++ .../chwl/app/ui/setting/SettingActivity.kt | 265 ++ .../app/ui/setting/ShieldManageActivity.kt | 110 + .../app/ui/setting/VerifyEmailActivity.kt | 209 + .../app/ui/setting/VerifyPhoneActivity.kt | 223 + .../com/chwl/app/ui/setting/VipSetActivity.kt | 202 + .../ui/setting/adapter/RoomShieldAdapter.kt | 25 + .../app/ui/setting/bean/PermissionEntity.kt | 50 + .../app/ui/setting/viewmodel/SetViewModel.kt | 41 + .../app/ui/user/activity/AboutActivity.java | 51 + .../ui/user/activity/ShowPhotoActivity.java | 112 + .../ui/user/activity/UserCpListActivity.kt | 235 ++ .../ui/user/activity/UserForbidActivity.kt | 145 + .../app/ui/user/activity/UserGiftActivity.kt | 56 + .../ui/user/activity/UserInfoActivity.java | 955 +++++ .../user/activity/UserInfoModifyActivity.kt | 696 ++++ .../user/activity/UserModifyPhotosActivity.kt | 337 ++ .../ui/user/adapter/ArrayWheelAdapter.java | 44 + .../adapter/CommonWrapIndicatorAdapter.java | 104 + .../adapter/ContactsIndicatorAdapter.java | 105 + .../ui/user/adapter/DrawableIndicator.java | 177 + .../chwl/app/ui/user/adapter/GiftAdapter.java | 46 + .../HomeRecommendIndicatorAdapter.java | 104 + .../app/ui/user/adapter/PhotoAdapter.java | 68 + .../app/ui/user/adapter/SkillPicsAdapter.kt | 12 + .../app/ui/user/adapter/UserCpListAdapter.kt | 59 + .../app/ui/user/adapter/UserGiftAdapter.java | 76 + .../ui/user/adapter/UserInfoAlbumAdapter.kt | 17 + .../ui/user/adapter/UserInfoCpListAdapter.kt | 49 + .../user/adapter/UserInfoDynamicAdapter.java | 262 ++ .../user/adapter/UserInfoGameTeamAdapter.kt | 31 + .../ui/user/adapter/UserInfoGiftAdapter.kt | 34 + .../adapter/UserInfoIndicatorAdapter.java | 102 + .../ui/user/adapter/UserInfoLabelAdapter.kt | 20 + .../ui/user/adapter/UserInfoMedalAdapter.kt | 53 + .../user/adapter/UserInfoTopAlbumAdapter.kt | 27 + .../ui/user/adapter/UserJoinWorldAdapter.java | 26 + .../app/ui/user/adapter/UserLabelAdapter.kt | 49 + .../ui/user/adapter/UserLabelDialogAdapter.kt | 23 + .../ui/user/adapter/UserModifyLabelAdapter.kt | 22 + .../user/adapter/UserModifyPhotosAdapter.java | 119 + .../app/ui/user/adapter/UserPhotoAdapter.java | 132 + .../ui/user/adapter/UserTabBaseAdapter.java | 53 + .../decorationsend/DSAttentionFragment.java | 202 + .../DSAttentionListAdapter.java | 61 + .../decorationsend/DSBaseListAdapter.java | 86 + .../decorationsend/DSFansListFragment.java | 219 + .../decorationsend/DSFansViewAdapter.java | 63 + .../decorationsend/DSFriendListAdapter.java | 61 + .../decorationsend/DSFriendListFragment.java | 157 + .../DecorationSendActivity.java | 173 + .../decorationsend/UserInfoSkillDecoration.kt | 29 + .../ui/user/dialog/CpRelationChangeDialog.kt | 80 + .../chwl/app/ui/user/dialog/UserAreaDialog.kt | 101 + .../com/chwl/app/ui/user/event/LabelEvent.kt | 8 + .../chwl/app/ui/user/event/UserLabelEvent.kt | 8 + .../app/ui/user/fragment/LabelFragment.kt | 62 + .../ui/user/fragment/UserInfoDataFragment.kt | 229 ++ .../user/fragment/UserInfoDynamicFragment.kt | 141 + .../user/fragment/UserInfoGiftFragment.java | 203 + .../ui/user/viewmodel/UserInfoViewModel.kt | 148 + .../java/com/chwl/app/ui/utils/CpUtils.kt | 223 + .../com/chwl/app/ui/utils/DesignUtils.java | 89 + .../java/com/chwl/app/ui/utils/GameUtil.kt | 46 + .../com/chwl/app/ui/utils/GlideCacheUtil.java | 175 + .../java/com/chwl/app/ui/utils/ImageLoad.kt | 220 + .../com/chwl/app/ui/utils/ImageLoadUtils.java | 630 +++ .../chwl/app/ui/utils/ImageLoadUtilsV2.java | 177 + .../app/ui/utils/NinePatchBitmapFactory.java | 194 + .../com/chwl/app/ui/utils/RVDelegate.java | 190 + .../java/com/chwl/app/ui/utils/SoftPool.kt | 62 + .../app/ui/utils/SurfaceViewAnimation.java | 506 +++ .../java/com/chwl/app/ui/utils/VipUtil.kt | 83 + .../chwl/app/ui/utils/sys/InstallUtil.java | 116 + .../chwl/app/ui/utils/sys/PermissionUtil.kt | 4 + .../com/chwl/app/ui/wallet/WalletActivity.kt | 128 + .../chwl/app/ui/wallet/WalletCoinsFragment.kt | 35 + .../app/ui/wallet/WalletDiamondFragment.kt | 53 + .../app/ui/wallet/WalletIndicatorAdapter.java | 105 + .../com/chwl/app/ui/wallet/WalletViewModel.kt | 75 + .../app/ui/wallet/payment/GPaymentClient.kt | 285 ++ .../app/ui/wallet/payment/IPaymentClient.kt | 42 + .../app/ui/wallet/payment/PaymentException.kt | 13 + .../app/ui/wallet/payment/PaymentIntent.kt | 4 + .../app/ui/wallet/payment/PaymentResult.kt | 12 + .../app/ui/webview/CommonWebViewActivity.java | 485 +++ .../app/ui/webview/CommonWebViewFragment.java | 122 + .../ui/webview/DatingRuleWebViewActivity.java | 32 + .../app/ui/webview/DialogWebViewActivity.java | 71 + .../webview/DialogWebViewCenterActivity.java | 99 + .../webview/FairyDialogWebViewActivity.java | 55 + .../com/chwl/app/ui/webview/JSInterface.java | 663 +++ .../com/chwl/app/ui/webview/ShareH5Event.java | 21 + .../app/ui/webview/SimpleJSInterface.java | 116 + .../app/ui/webview/SimpleWebViewActivity.java | 245 ++ .../ui/webview/TarotPayWebViewActivity.java | 38 + .../ui/webview/baishun/BaiShunGameJSBridge.kt | 58 + .../webview/baishun/BaiShunGameWebActivity.kt | 49 + .../webview/baishun/BaiShunGameWebFragment.kt | 268 ++ .../webview/baishun/IBaiShunGameListener.kt | 5 + .../ui/webview/baishun/IBaiShunGameView.kt | 19 + .../webview/baishun/JoyPlayGameWebFragment.kt | 314 ++ .../app/ui/webview/baishun/JoyPlayJSBridge.kt | 62 + .../baishun/LeaderccGameWebFragment.kt | 285 ++ .../ui/webview/baishun/LeaderccJSBridge.kt | 74 + .../event/CloseDialogWebViewEvent.java | 7 + .../ui/webview/event/H5NotifyClientEvent.java | 15 + .../app/ui/webview/event/ShowNavEvent.java | 19 + .../ui/webview/event/TaroPayResultEvent.java | 20 + .../room_banner/RoomBannerTabAdapter.kt | 47 + .../RoomBannerWebDialogActivity.kt | 91 + .../room_banner/RoomWebDialogActivity.kt | 27 + .../com/chwl/app/ui/widget/Anticlockwise.java | 91 + .../app/ui/widget/AppBarLayoutBehavior.java | 176 + .../ui/widget/BonsellaJoinAttackButtonView.kt | 176 + .../app/ui/widget/BonsellaJoinAttackLayout.kt | 356 ++ .../com/chwl/app/ui/widget/ButtonItem.java | 108 + .../chwl/app/ui/widget/CharAlignTextView.java | 68 + .../app/ui/widget/ColorfulRingProgressView.kt | 295 ++ .../app/ui/widget/CustomExpandableText.java | 257 ++ .../chwl/app/ui/widget/DatingSelectDialog.kt | 24 + .../chwl/app/ui/widget/DefaultToolBar.java | 94 + .../app/ui/widget/DividerItemDecoration.java | 119 + .../com/chwl/app/ui/widget/DividerUtil.java | 80 + .../app/ui/widget/EdgeTransparentView.java | 141 + .../app/ui/widget/FixedTouchViewPager.java | 62 + .../chwl/app/ui/widget/FlickerAvatarView.java | 104 + .../chwl/app/ui/widget/GiftAvatarAdapter.java | 219 + .../com/chwl/app/ui/widget/GiftDialog.java | 1980 +++++++++ .../chwl/app/ui/widget/GiftRecyclerView.java | 77 + .../app/ui/widget/GridViewWithoutScroll.java | 40 + .../app/ui/widget/InterceptTouchLayout.java | 41 + .../chwl/app/ui/widget/LeftNotiDialog.java | 94 + .../com/chwl/app/ui/widget/LevelHeadView.java | 90 + .../com/chwl/app/ui/widget/LevelUpDialog.java | 41 + .../ui/widget/LinearLayoutManagerWrapper.java | 34 + .../app/ui/widget/ListViewWithoutScroll.java | 40 + .../chwl/app/ui/widget/LivingIconView.java | 97 + .../chwl/app/ui/widget/LoadingAdapter.java | 134 + .../com/chwl/app/ui/widget/LoadingDialog.java | 30 + .../com/chwl/app/ui/widget/MagicAdapter.java | 155 + .../chwl/app/ui/widget/MagicRecyclerView.java | 73 + .../chwl/app/ui/widget/MainRedPointTab.java | 160 + .../java/com/chwl/app/ui/widget/MainTab.java | 97 + .../com/chwl/app/ui/widget/MainTabLayout.java | 175 + .../com/chwl/app/ui/widget/MarqueeLayout.java | 119 + .../com/chwl/app/ui/widget/MarqueeTextView.kt | 414 ++ .../com/chwl/app/ui/widget/MicSelectDialog.kt | 157 + .../ui/widget/MultipleGraduallyTextView.kt | 61 + .../chwl/app/ui/widget/MyItemAnimator.java | 684 ++++ .../chwl/app/ui/widget/NobleAvatarView.java | 118 + .../app/ui/widget/NobleOpenNoticeView.java | 173 + .../java/com/chwl/app/ui/widget/NumView.java | 36 + .../app/ui/widget/ObservableScrollView.java | 48 + .../app/ui/widget/OnPageSelectedListener.java | 21 + .../ParentClickHorizontalScrollView.java | 66 + .../chwl/app/ui/widget/PinEntryEditText.java | 630 +++ .../com/chwl/app/ui/widget/RecallDialog.java | 118 + .../com/chwl/app/ui/widget/RectLayout.java | 45 + .../app/ui/widget/RecyclerRefreshLayout.java | 228 ++ .../RecyclerViewNoBugLinearLayoutManager.java | 46 + .../widget/RecyclerViewNoViewpagerScroll.java | 31 + .../com/chwl/app/ui/widget/RedPointView.java | 84 + .../ui/widget/ScollLinearLayoutManager.java | 53 + .../chwl/app/ui/widget/ShareRedBagDialog.java | 29 + .../com/chwl/app/ui/widget/SideBarView.kt | 146 + .../app/ui/widget/SimpleAnimListener.java | 39 + .../chwl/app/ui/widget/SquareImageView.java | 36 + .../com/chwl/app/ui/widget/SquareLayout.java | 37 + .../com/chwl/app/ui/widget/SuperEditText.java | 126 + .../app/ui/widget/TextSpannableBuilder.java | 196 + .../chwl/app/ui/widget/TextWatcherSimple.java | 20 + .../app/ui/widget/TopRoundLinearLayout.java | 66 + .../chwl/app/ui/widget/UserInfoDialog.java | 1384 +++++++ .../com/chwl/app/ui/widget/UserInfoView.java | 72 + .../ui/widget/UserInfoWrapContentPager.java | 46 + .../app/ui/widget/UserMagicIndicator.java | 81 + .../app/ui/widget/WrapContentViewPager.java | 44 + .../ScaleTransitionPagerTitleView.java | 85 + .../widget/adapter/GiftDialogNumberAdapter.kt | 12 + .../ui/widget/bubble/LeBubbleTextView.java | 73 + .../widget/bubble/LeBubbleTextViewHelper.java | 123 + .../ui/widget/bubble/LeBubbleTextViews.java | 98 + .../widget/bubble/LeBubbleTitleTextView.java | 173 + .../app/ui/widget/bubble/LeBubbleView.java | 300 ++ .../widget/bubble/LeRoundRectDrawable2.java | 134 + .../widget/bubble/LeStateColorDrawable.java | 49 + .../widget/bubble/TintedBitmapDrawable.java | 45 + .../ui/widget/dialog/AllPlayEffectDialog.java | 527 +++ .../dialog/AllServiceGiftGoRoomTipsDialog.kt | 100 + .../dialog/AllServiceGiftLevelDialog.kt | 184 + .../dialog/AllServiceVipLevelUPDialog.java | 153 + .../chwl/app/ui/widget/dialog/BaseDialog.java | 26 + .../app/ui/widget/dialog/CommonDialog.java | 123 + .../ui/widget/dialog/CommonLoadingDialog.java | 73 + .../ui/widget/dialog/CommonMessageDialog.kt | 17 + .../app/ui/widget/dialog/CommonTipDialog.java | 123 + .../dialog/ExchangeDiamondTipDialog.java | 79 + .../dialog/GiftManualQuantityDialog.java | 92 + .../widget/dialog/GiveDiamondTipDialog.java | 152 + .../app/ui/widget/dialog/MonsterDialog.java | 174 + .../app/ui/widget/dialog/OpenNobleDialog.java | 81 + .../dialog/OpenNobleGlobalNoticeDialog.java | 77 + .../ui/widget/drawgift/DrawGiftHelper.java | 134 + .../app/ui/widget/drawgift/DrawGiftModel.java | 67 + .../widget/drawgift/DrawGiftPlayHelper.java | 165 + .../ui/widget/drawgift/DrawGiftPlayView.java | 216 + .../app/ui/widget/drawgift/DrawGiftView.java | 354 ++ .../dynamicface/DynamicFaceAdapter.java | 116 + .../dynamicface/DynamicFaceAdapterNew.kt | 41 + .../dynamicface/DynamicFaceBuilder.java | 360 ++ .../widget/dynamicface/DynamicFaceDialog.java | 323 ++ .../app/ui/widget/dynamicface/FaceItem.java | 39 + .../ui/widget/dynamicface/FaceResultItem.java | 89 + .../app/ui/widget/higuide/GuideUtils.java | 93 + .../chwl/app/ui/widget/higuide/GuideView.java | 201 + .../chwl/app/ui/widget/higuide/HiGuide.java | 126 + .../app/ui/widget/higuide/HiLightInfo.java | 45 + .../app/ui/widget/higuide/LightConfig.java | 49 + .../chwl/app/ui/widget/higuide/OverLayer.java | 54 + .../chwl/app/ui/widget/higuide/Overlay.java | 211 + .../ui/widget/higuide/TuTuGuideHelper.java | 768 ++++ .../app/ui/widget/higuide/TuTuGuideView.java | 170 + .../app/ui/widget/interfacex/MicListItem.java | 23 + .../FragmentContainerHelper.java | 162 + .../widget/magicindicator/GiftIndicator.java | 186 + .../widget/magicindicator/MagicIndicator.java | 63 + .../magicindicator/NavigatorHelper.java | 171 + .../ui/widget/magicindicator/ScrollState.java | 12 + .../magicindicator/ViewPagerHelper.java | 62 + .../magicindicator/abs/IPagerNavigator.java | 34 + .../buildins/ArgbEvaluatorHolder.java | 28 + .../magicindicator/buildins/UIUtil.java | 23 + .../circlenavigator/CircleNavigator.java | 314 ++ .../commonnavigator/CommonNavigator.java | 494 +++ .../abs/CommonNavigatorAdapter.java | 41 + .../abs/IMeasurablePagerTitleView.java | 17 + .../commonnavigator/abs/IPagerIndicator.java | 21 + .../commonnavigator/abs/IPagerTitleView.java | 34 + .../indicators/BezierPagerIndicator.java | 165 + .../GradientLinePagerIndicator.java | 23 + .../GradientLineRoundPagerIndicator.java | 28 + .../indicators/LinePagerIndicator.java | 220 + .../indicators/TestPagerIndicator.java | 102 + .../indicators/TriangularPagerIndicator.java | 161 + .../indicators/WrapPagerIndicator.kt | 121 + .../commonnavigator/model/PositionData.java | 41 + .../titles/ClipPagerTitleView.java | 192 + .../titles/ColorTransitionPagerTitleView.java | 40 + .../titles/CommonPagerTitleView.java | 144 + .../titles/DummyPagerTitleView.java | 34 + .../titles/SimplePagerTitleView.java | 99 + .../titles/badge/BadgeAnchor.java | 22 + .../titles/badge/BadgePagerTitleView.java | 222 + .../titles/badge/BadgeRule.java | 32 + .../ext/FontChangePagerTitleView.java | 181 + .../ext/MainCommonNavigatorAdapter.java | 67 + .../marqueeview/AvRoomNobleWelcomeView.java | 130 + .../widget/marqueeview/BetterMarqueeView.java | 146 + .../ui/widget/marqueeview/MarqueeView.java | 304 ++ .../ui/widget/password/PassWordFragment.java | 173 + .../app/ui/widget/password/PasswordEvent.java | 25 + .../widget/password/PasswordKeyboardView.java | 230 ++ .../app/ui/widget/password/PasswordView.java | 113 + .../decoration/ColorDecoration.java | 229 ++ .../decoration/DatingItemDecoration.java | 49 + .../decoration/GridSpacingItemDecoration.java | 45 + .../GridSpacingItemNewDecoration.java | 99 + .../decoration/GridVItemDecoration.java | 158 + .../decoration/HorizontalDecoration.java | 56 + .../decoration/SpacingDecoration.java | 73 + .../decoration/TagItemDecoration.kt | 42 + .../decoration/VerticalDecoration.java | 56 + .../layoutmanager/BoosRoomLayoutManager.kt | 302 ++ .../layoutmanager/FullyGridLayoutManager.java | 102 + .../FullyLinearLayoutManager.java | 99 + .../app/ui/widget/rollviewpager/HintView.java | 10 + .../OnRollViewClickListener.java | 8 + .../widget/rollviewpager/RollPagerView.java | 448 ++ .../app/ui/widget/rollviewpager/Util.java | 24 + .../adapter/DynamicPagerAdapter.java | 43 + .../adapter/LoopPagerAdapter.java | 121 + .../adapter/StaticPagerAdapter.java | 70 + .../adapter/StaticPagerAdapterWrapper.java | 26 + .../hintview/ColorPointHintView.java | 40 + .../rollviewpager/hintview/IconHintView.java | 78 + .../rollviewpager/hintview/ShapeHintView.java | 80 + .../rollviewpager/hintview/TextHintView.java | 45 + .../widget/viewpager/NoScrollViewPager.java | 46 + .../ui/widget/viewpager/ScrollViewPager.java | 27 + .../com/chwl/app/utils/ActWhiteListMrg.java | 41 + .../java/com/chwl/app/utils/AnimLoadUtil.kt | 490 +++ .../app/utils/AppBarStateChangeListener.java | 40 + .../java/com/chwl/app/utils/AvatarHelper.kt | 42 + .../chwl/app/utils/BlurTransformation.java | 94 + .../com/chwl/app/utils/CertificateHelper.java | 119 + .../com/chwl/app/utils/CleanLeakUtils.java | 59 + .../com/chwl/app/utils/ClipboardUtils.java | 136 + .../com/chwl/app/utils/CommonJumpHelper.java | 91 + .../app/utils/DoubleClickCheckListener.java | 34 + .../java/com/chwl/app/utils/FastBlur.java | 257 ++ .../java/com/chwl/app/utils/FloatManager.java | 71 + .../java/com/chwl/app/utils/FontTextView.java | 33 + .../java/com/chwl/app/utils/GiftAnimUtil.java | 81 + .../java/com/chwl/app/utils/HomeUIManager.kt | 112 + .../com/chwl/app/utils/KeyBoardUtils.java | 44 + .../com/chwl/app/utils/LimitInputFliter.java | 19 + .../com/chwl/app/utils/LoginSuccessManager.kt | 87 + .../java/com/chwl/app/utils/MsgBuilder.kt | 95 + .../com/chwl/app/utils/NamePlateHelper.kt | 75 + .../chwl/app/utils/NotificationsUtils.java | 128 + .../com/chwl/app/utils/NumberFormatUtil.java | 37 + .../java/com/chwl/app/utils/NumberUtils.kt | 108 + .../main/java/com/chwl/app/utils/OSUtils.java | 59 + .../com/chwl/app/utils/ObjectTypeHelper.java | 81 + .../java/com/chwl/app/utils/PermissionUtil.kt | 125 + .../chwl/app/utils/PushMessageHandler.java | 70 + .../main/java/com/chwl/app/utils/RSBlur.java | 66 + .../java/com/chwl/app/utils/RegexUtil.java | 66 + .../com/chwl/app/utils/ResourceManager.kt | 102 + .../com/chwl/app/utils/RoomBoomManager.kt | 304 ++ .../com/chwl/app/utils/RoomHelperManager.kt | 294 ++ .../chwl/app/utils/RoomNotifyDialogManager.kt | 365 ++ .../java/com/chwl/app/utils/ShareManager.kt | 115 + .../com/chwl/app/utils/SpannableBuilder.java | 73 + .../java/com/chwl/app/utils/ThreadUtil.java | 136 + .../java/com/chwl/app/utils/TimeUiUtils.java | 35 + .../java/com/chwl/app/utils/UserUtils.java | 37 + .../com/chwl/app/utils/VapAnimListener.java | 43 + .../chwl/app/utils/VpSwipeRefreshLayout.java | 60 + .../main/java/com/chwl/app/utils/WeakPool.kt | 62 + .../java/com/chwl/app/utils/WebViewUtils.java | 28 + .../com/chwl/app/view/AutoMirroredAnimView.kt | 30 + .../chwl/app/view/AutoMirroredImageView.kt | 30 + .../view/AutoMirroredShapeableImageView.kt | 23 + .../main/java/com/chwl/app/view/EffectView.kt | 673 +++ .../com/chwl/app/view/GenderAgeTextView.kt | 90 + .../com/chwl/app/view/MyCircleIndicator.java | 78 + .../com/chwl/app/view/NestedScrollableHost.kt | 111 + .../com/chwl/app/view/ShadowFrameLayout.java | 92 + .../com/chwl/app/view/WrapHeightViewPager.kt | 37 + .../layoutmanager/AutoPlayRecyclerView.java | 88 + .../layoutmanager/AutoPlaySnapHelper.java | 115 + .../layoutmanager/CarouselLayoutManager.java | 167 + .../view/layoutmanager/CenterSnapHelper.java | 177 + .../layoutmanager/CircleLayoutManager.java | 376 ++ .../CircleScaleLayoutManager.java | 393 ++ .../layoutmanager/GalleryLayoutManager.java | 286 ++ .../view/layoutmanager/OrientationHelper.java | 423 ++ .../view/layoutmanager/PageSnapHelper.java | 51 + .../layoutmanager/RotateLayoutManager.java | 178 + .../layoutmanager/ScaleLayoutManager.java | 221 + .../app/view/layoutmanager/ScrollHelper.java | 32 + .../layoutmanager/ViewPagerLayoutManager.java | 973 +++++ .../java/com/chwl/app/vip/VipBroadcastView.kt | 108 + .../com/chwl/app/vip/VipCenterActivity.kt | 520 +++ .../com/chwl/app/vip/VipSettingActivity.kt | 70 + .../java/com/chwl/app/vip/VipViewModel.kt | 181 + .../com/chwl/app/vip/adapter/PayAdapter.kt | 20 + .../chwl/app/vip/adapter/VipAuthAdapter.kt | 26 + .../app/vip/adapter/VipCenterBannerAdapter.kt | 187 + .../VipCenterIdentificationsAdapter.kt | 278 ++ .../vip/adapter/VipMagicIndicatorAdapter.java | 99 + .../chwl/app/vip/adapter/VipRebateAdapter.kt | 68 + .../java/com/chwl/app/vip/bean/PayInfo.kt | 8 + .../com/chwl/app/vip/dialog/PaymentDialog.kt | 76 + .../app/vip/dialog/SelectPayTypeDialog.kt | 181 + .../app/vip/dialog/VipAuthDetailsDialog.kt | 29 + .../chwl/app/vip/dialog/VipBroadcastDialog.kt | 94 + .../app/vip/dialog/VipRemainTimeDialog.kt | 22 + .../chwl/app/vip/dialog/VipUpgradeDialog.kt | 80 + .../java/com/chwl/app/vip/util/VipHelper.java | 82 + .../com/chwl/app/vip/view/VipBroadcastView.kt | 108 + .../java/com/chwl/app/vip/view/VipTabView.kt | 48 + 1320 files changed, 180194 insertions(+) create mode 100644 app/src/main/java/com/chwl/app/AgentActivity.java create mode 100644 app/src/main/java/com/chwl/app/DemoActivity.kt create mode 100644 app/src/main/java/com/chwl/app/GuideAdapter.java create mode 100644 app/src/main/java/com/chwl/app/MainActivity.java create mode 100644 app/src/main/java/com/chwl/app/MainTabContentView.kt create mode 100644 app/src/main/java/com/chwl/app/NimMiddleActivity.java create mode 100644 app/src/main/java/com/chwl/app/UIHelper.java create mode 100644 app/src/main/java/com/chwl/app/UserGuideActivity.java create mode 100644 app/src/main/java/com/chwl/app/application/App.java create mode 100644 app/src/main/java/com/chwl/app/application/GlobalHandleManager.java create mode 100644 app/src/main/java/com/chwl/app/application/IReportConstants.java create mode 100644 app/src/main/java/com/chwl/app/application/IReportService.java create mode 100644 app/src/main/java/com/chwl/app/application/ReportManager.java create mode 100644 app/src/main/java/com/chwl/app/audio/AudioRecordActivity.java create mode 100644 app/src/main/java/com/chwl/app/audio/MyVoiceActivity.java create mode 100644 app/src/main/java/com/chwl/app/audio/RecordingVoiceActivity.java create mode 100644 app/src/main/java/com/chwl/app/audio/SoundSignatureActivity.kt create mode 100644 app/src/main/java/com/chwl/app/audio/VoiceMatchActivity.java create mode 100644 app/src/main/java/com/chwl/app/audio/adapter/CardAdapter.java create mode 100644 app/src/main/java/com/chwl/app/audio/adapter/MyVoiceListAdapter.java create mode 100644 app/src/main/java/com/chwl/app/audio/helper/AudioPlayerHelper.java create mode 100644 app/src/main/java/com/chwl/app/audio/helper/OnPlayListener.java create mode 100644 app/src/main/java/com/chwl/app/audio/helper/OnRefreshListener.java create mode 100644 app/src/main/java/com/chwl/app/audio/helper/SvgaCacheManager.java create mode 100644 app/src/main/java/com/chwl/app/audio/helper/VmSoundManager.java create mode 100644 app/src/main/java/com/chwl/app/audio/helper/VoiceMacthHelper.java create mode 100644 app/src/main/java/com/chwl/app/audio/presenter/MyVoicePresenter.java create mode 100644 app/src/main/java/com/chwl/app/audio/presenter/RecordingVoicePresenter.java create mode 100644 app/src/main/java/com/chwl/app/audio/view/BottleContainer.java create mode 100644 app/src/main/java/com/chwl/app/audio/view/BottleLayout.java create mode 100644 app/src/main/java/com/chwl/app/audio/view/IBottleOpListener.java create mode 100644 app/src/main/java/com/chwl/app/audio/view/IMyVoiceView.java create mode 100644 app/src/main/java/com/chwl/app/audio/view/IRecordingVoiceView.java create mode 100644 app/src/main/java/com/chwl/app/audio/view/PlayLoadingImageView.java create mode 100644 app/src/main/java/com/chwl/app/audio/viewmodel/SoundViewModel.kt create mode 100644 app/src/main/java/com/chwl/app/audio/widget/DynamicWave.java create mode 100644 app/src/main/java/com/chwl/app/audio/widget/OnSwipeListener.java create mode 100644 app/src/main/java/com/chwl/app/audio/widget/RingProgressView.java create mode 100644 app/src/main/java/com/chwl/app/audio/widget/RoundProgressView.java create mode 100644 app/src/main/java/com/chwl/app/audio/widget/VoiceBottleFilterGenderBottomDialog.java create mode 100644 app/src/main/java/com/chwl/app/audio/widget/VoiceCardConfig.java create mode 100644 app/src/main/java/com/chwl/app/audio/widget/VoiceCardItemTouchHelperCallback.java create mode 100644 app/src/main/java/com/chwl/app/audio/widget/VoiceCardLayoutManager.java create mode 100644 app/src/main/java/com/chwl/app/audio/widget/VoiceCardRecyclerView.java create mode 100644 app/src/main/java/com/chwl/app/audio/widget/VoiceLine.java create mode 100644 app/src/main/java/com/chwl/app/audio/widget/VoiceWave.java create mode 100644 app/src/main/java/com/chwl/app/avroom/BottomViewListenerWrapper.java create mode 100644 app/src/main/java/com/chwl/app/avroom/ButtonItemFactory.java create mode 100644 app/src/main/java/com/chwl/app/avroom/ChatMemberDiffUtilCallback.java create mode 100644 app/src/main/java/com/chwl/app/avroom/SoftKeyBoardListener.java create mode 100644 app/src/main/java/com/chwl/app/avroom/UserCardButtonManager.java create mode 100644 app/src/main/java/com/chwl/app/avroom/activity/AVRoomActivity.java create mode 100644 app/src/main/java/com/chwl/app/avroom/activity/CreatePKActivity.java create mode 100644 app/src/main/java/com/chwl/app/avroom/activity/RecordForPKActivity.java create mode 100644 app/src/main/java/com/chwl/app/avroom/activity/RoomBgSettingActivity.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/activity/RoomBlackListActivity.java create mode 100644 app/src/main/java/com/chwl/app/avroom/activity/RoomInviteActivity.java create mode 100644 app/src/main/java/com/chwl/app/avroom/activity/RoomManagerListActivity.java create mode 100644 app/src/main/java/com/chwl/app/avroom/activity/RoomOnlineUserActivity.java create mode 100644 app/src/main/java/com/chwl/app/avroom/activity/RoomRankListActivity.java create mode 100644 app/src/main/java/com/chwl/app/avroom/activity/RoomSettingActivity.java create mode 100644 app/src/main/java/com/chwl/app/avroom/activity/RoomTitleEditActivity.java create mode 100644 app/src/main/java/com/chwl/app/avroom/activity/RoomTypeSwitchActivity.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/AuctionListAdapter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/AuctionListEmptyItem.java create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/AuctionListHeaderItem.java create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/AuctionListItem.java create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/BaseMicroViewAdapter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/CommonVPAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/CpMicroViewAdapter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/CreateRoomGameAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/CreateRoomGameGuideAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/DatingMicroViewAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/ExitRoomAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/GameMicroViewAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/GameMiniMicroViewAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/HomePartyPageAdapter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/Mic19ViewAdapter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/Mic20ViewAdapter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/MicQueueAdapter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/MicroViewAdapter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/OnMicroItemClickListener.java create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/OnlineUserAdapter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/PKMicQueueAdapter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/PartyMicroViewAdapter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/RecordForPKAdapter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/RevelryMicroViewAdapter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/RoomBgAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/RoomBlackListAdapter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/RoomConsumeListAdapter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/RoomConsumerListAdapterTemp.java create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/RoomContributeListAdapter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/RoomGameListAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/RoomGameplayAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/RoomInviteAdapter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/RoomMessageIndicatorAdapter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/RoomNormalListAdapter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/RoomRankFragmentPageAdapter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/RoomRankHalfHourListAdapter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/RoomVPAdapter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/SendBroadcastAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/SingleAnchorMicroViewAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/SingleRoomPKMicroViewAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/adapter/UpMicAdapter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPKBoardView.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPKCreateActivity.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPKRankListView.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPKSearchActivity.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPKSearchAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPkFinishDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPkForceFinishDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPkReceivedDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPkRuleDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/bean/LuckyBagConfig.java create mode 100644 app/src/main/java/com/chwl/app/avroom/bean/LuckyBagDetailEntity.java create mode 100644 app/src/main/java/com/chwl/app/avroom/bean/LuckyBagEntity.java create mode 100644 app/src/main/java/com/chwl/app/avroom/bean/LuckyBagGiftBody.java create mode 100644 app/src/main/java/com/chwl/app/avroom/bean/LuckyBagGiftItemBody.java create mode 100644 app/src/main/java/com/chwl/app/avroom/bean/LuckyBagGoldBody.java create mode 100644 app/src/main/java/com/chwl/app/avroom/bean/LuckyBagOpenBiliEntity.java create mode 100644 app/src/main/java/com/chwl/app/avroom/bean/LuckyBagOpenEntity.java create mode 100644 app/src/main/java/com/chwl/app/avroom/bean/LuckyBagOpenGiftBean.java create mode 100644 app/src/main/java/com/chwl/app/avroom/bean/LuckyBagOpenGiftEntity.java create mode 100644 app/src/main/java/com/chwl/app/avroom/bean/LuckyBagOpenUserBean.java create mode 100644 app/src/main/java/com/chwl/app/avroom/bean/RoomAlbumPhotoInfo.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/bean/RoomGameplayItem.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/bean/RoomLuckyBagInfo.java create mode 100644 app/src/main/java/com/chwl/app/avroom/bean/RoomPlayBean.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/AttentionHintDialog.java create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/BaseRoomNotifyDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/CreateGameRoomDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/CreateRoomDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/DatingVipRuleDialog.java create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/ExitRoomPopupWindow.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/MicQueueDialog.java create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/NewUserGiftDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/PKMicQueueDialog.java create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/PKSelectPeopleDialog.java create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/PKTimePickerDialog.java create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/RequestUpMicDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/RoomBgPreviewDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/RoomBgSetDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/RoomBoomInfoDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/RoomBoomRewardDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/RoomGameListDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/RoomGameplayDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/RoomLuckyBagBiliDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/RoomLuckyBagDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/RoomLuckyBagOpenDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/RoomMusicDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/RoomNotifyBoomDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/RoomNotifyBravoDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/RoomNotifyCpBindDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/RoomNotifyCpGiftDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/RoomNotifyLevelUpDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/RoomNotifyLuckBagDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/RoomNotifyLuckyGiftDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/RoomOperationDialog.java create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/RoomTeamPKResultDialog.java create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/RoomTeamPkDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/SelectLabelDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/SendBroadcastDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/dialog/SingleRoomTipDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/fragment/BaseRoomFragment.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/fragment/FakeSingleRoomBackFragment.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/fragment/FakeSingleRoomFragment.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/fragment/GameRoomFragment.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/fragment/HomePartyFragment.java create mode 100644 app/src/main/java/com/chwl/app/avroom/fragment/HomePartyRoomFragment.java create mode 100644 app/src/main/java/com/chwl/app/avroom/fragment/IRoomRankDialogChangePageListener.java create mode 100644 app/src/main/java/com/chwl/app/avroom/fragment/IRoomRankDialogDismissListener.java create mode 100644 app/src/main/java/com/chwl/app/avroom/fragment/IRoomRankHalfHourView.java create mode 100644 app/src/main/java/com/chwl/app/avroom/fragment/InputPwdDialogFragment.java create mode 100644 app/src/main/java/com/chwl/app/avroom/fragment/OnlineUserFragment.java create mode 100644 app/src/main/java/com/chwl/app/avroom/fragment/PartyRoomFragment.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/fragment/RevelryRoomFragment.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/fragment/Room19Fragment.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/fragment/Room20Fragment.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/fragment/RoomCharmListFragment.java create mode 100644 app/src/main/java/com/chwl/app/avroom/fragment/RoomCharmRankingListFragment.java create mode 100644 app/src/main/java/com/chwl/app/avroom/fragment/RoomContributeFragment.java create mode 100644 app/src/main/java/com/chwl/app/avroom/fragment/RoomContributeListFragment.java create mode 100644 app/src/main/java/com/chwl/app/avroom/fragment/RoomRankDialogFragment.java create mode 100644 app/src/main/java/com/chwl/app/avroom/fragment/RoomRankDialogUtils.java create mode 100644 app/src/main/java/com/chwl/app/avroom/fragment/RoomRankListFragment.java create mode 100644 app/src/main/java/com/chwl/app/avroom/fragment/RoomTitleDialogFragment.java create mode 100644 app/src/main/java/com/chwl/app/avroom/fragment/SingleRoomFragment.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/game/AppConfig.java create mode 100644 app/src/main/java/com/chwl/app/avroom/game/GameDelegate.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/game/OnGameStatusChangeListener.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/gameplay/GameplayRecyclerView.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/gameplay/RoomGameplayListWidget.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/gameplay/RoomGameplayWidget.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/gameplay/RoomPlayListAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/giftvalue/GiftValueDialogUiHelper.java create mode 100644 app/src/main/java/com/chwl/app/avroom/headline/RoomHeadlineWidget.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/helper/AnimHelper.java create mode 100644 app/src/main/java/com/chwl/app/avroom/helper/RoomViewModel.java create mode 100644 app/src/main/java/com/chwl/app/avroom/newuserchargegift/NewUserChargePrizeDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/newuserchargegift/RewardAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/online/RoomOnlineAvatarAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/online/RoomOnlineWidget.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/presenter/AvRoomPresenter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/presenter/BaseRoomPresenter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/presenter/BaseRoomRankPresenter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/presenter/CreatePKPresenter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/presenter/GameRoomPresenter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/presenter/HomePartyPresenter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/presenter/HomePartyUserListPresenter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/presenter/RecordForPKPresenter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/presenter/RoomBlackPresenter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/presenter/RoomCharmRankingPresenter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/presenter/RoomContributeListPresenter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/presenter/RoomInvitePresenter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/presenter/RoomManagerPresenter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/presenter/RoomNewbiePresenter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/presenter/RoomRankHalfHourPresenter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/presenter/RoomSettingPresenter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/presenter/SingleRoomPresenter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/rank/RoomRankNumberWidget.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/rank/RoomRankWidget.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/recommendcard/MyRecommendCardActivity.java create mode 100644 app/src/main/java/com/chwl/app/avroom/recommendcard/RecommendCardFragment.java create mode 100644 app/src/main/java/com/chwl/app/avroom/recommendcard/RecommendCardListAdapter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/room_album/ChooseGiftRoomAlbumDialogFragment.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/room_album/PhotoItem.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/room_album/RoomAlbumActivity.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/room_album/RoomAlbumFragment.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/room_album/RoomAlbumFragmentViewModel.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/room_album/RoomAlbumModel.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/room_album/RoomAlbumViewModel.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/room_album/UnlockRoomAlbumPhotoDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/room_album/UploadRoomAlbumDialogFragment.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPKBoardView.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPKCreateActivity.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPKRankListView.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPKSearchActivity.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPKSearchAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPkFinishDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPkForceFinishDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPkReceivedDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPkRuleDialog.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/view/IAvRoomView.java create mode 100644 app/src/main/java/com/chwl/app/avroom/view/IBaseRoomView.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/view/ICreatePKView.java create mode 100644 app/src/main/java/com/chwl/app/avroom/view/IGameRoomView.java create mode 100644 app/src/main/java/com/chwl/app/avroom/view/IHomePartyUserListView.java create mode 100644 app/src/main/java/com/chwl/app/avroom/view/IHomePartyView.java create mode 100644 app/src/main/java/com/chwl/app/avroom/view/ILightChatConsumeView.java create mode 100644 app/src/main/java/com/chwl/app/avroom/view/ILightChatOnlineView.java create mode 100644 app/src/main/java/com/chwl/app/avroom/view/ILightChatRoomView.java create mode 100644 app/src/main/java/com/chwl/app/avroom/view/IRecordForPKView.java create mode 100644 app/src/main/java/com/chwl/app/avroom/view/IRoomBlackView.java create mode 100644 app/src/main/java/com/chwl/app/avroom/view/IRoomCharmRankingListView.java create mode 100644 app/src/main/java/com/chwl/app/avroom/view/IRoomContributeListView.java create mode 100644 app/src/main/java/com/chwl/app/avroom/view/IRoomInviteView.java create mode 100644 app/src/main/java/com/chwl/app/avroom/view/IRoomManagerView.java create mode 100644 app/src/main/java/com/chwl/app/avroom/view/IRoomMemberView.java create mode 100644 app/src/main/java/com/chwl/app/avroom/view/IRoomSettingView.java create mode 100644 app/src/main/java/com/chwl/app/avroom/view/ISingleRoomView.java create mode 100644 app/src/main/java/com/chwl/app/avroom/widget/ActivityTimerView.java create mode 100644 app/src/main/java/com/chwl/app/avroom/widget/BottomView.java create mode 100644 app/src/main/java/com/chwl/app/avroom/widget/BravoCoinView.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/widget/CoinTipsView.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/widget/EditRoomTitleDialog.java create mode 100644 app/src/main/java/com/chwl/app/avroom/widget/FixRoomTitleTextView.java create mode 100644 app/src/main/java/com/chwl/app/avroom/widget/GalleryLayoutManager.java create mode 100644 app/src/main/java/com/chwl/app/avroom/widget/GiftEffectView.java create mode 100644 app/src/main/java/com/chwl/app/avroom/widget/GiftV2View.java create mode 100644 app/src/main/java/com/chwl/app/avroom/widget/LollipopFixedWebView.java create mode 100644 app/src/main/java/com/chwl/app/avroom/widget/LuckyBagBtn.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/widget/MagicTextView.java create mode 100644 app/src/main/java/com/chwl/app/avroom/widget/MessageView.java create mode 100644 app/src/main/java/com/chwl/app/avroom/widget/MicroView.java create mode 100644 app/src/main/java/com/chwl/app/avroom/widget/OnMsgLongClickListener.java create mode 100644 app/src/main/java/com/chwl/app/avroom/widget/PKProgressBar.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/widget/RankNavigatorAdapter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/widget/RoomEffectBoxView.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/widget/RoomEffectView.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/widget/RoomRankNavigatorAdapter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/widget/RoomRankWrapViewPager.java create mode 100644 app/src/main/java/com/chwl/app/avroom/widget/ScaleTransformer.java create mode 100644 app/src/main/java/com/chwl/app/avroom/widget/ScrollSpeedLinearLayoutManger.java create mode 100644 app/src/main/java/com/chwl/app/avroom/widget/SliddingView.java create mode 100644 app/src/main/java/com/chwl/app/avroom/widget/TeamPKUserListView.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/widget/TemplateMessageAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/avroom/widget/VDHLayout.java create mode 100644 app/src/main/java/com/chwl/app/avroom/widget/VerticalViewPagerAdapter.java create mode 100644 app/src/main/java/com/chwl/app/avroom/widget/ViewItem.java create mode 100644 app/src/main/java/com/chwl/app/avroom/widget/VipProgressBar.kt create mode 100644 app/src/main/java/com/chwl/app/base/AbstractMvpActivity.java create mode 100644 app/src/main/java/com/chwl/app/base/AbstractMvpFragment.java create mode 100644 app/src/main/java/com/chwl/app/base/BaseActivity.java create mode 100644 app/src/main/java/com/chwl/app/base/BaseBindingActivity.java create mode 100644 app/src/main/java/com/chwl/app/base/BaseBindingDialog.java create mode 100644 app/src/main/java/com/chwl/app/base/BaseBindingFragment.java create mode 100644 app/src/main/java/com/chwl/app/base/BaseBindingTakePhotoActivity.java create mode 100644 app/src/main/java/com/chwl/app/base/BaseBsDialog.java create mode 100644 app/src/main/java/com/chwl/app/base/BaseDialogFragment.kt create mode 100644 app/src/main/java/com/chwl/app/base/BaseFragment.java create mode 100644 app/src/main/java/com/chwl/app/base/BaseLazyFragment.java create mode 100644 app/src/main/java/com/chwl/app/base/BaseListFragment.kt create mode 100644 app/src/main/java/com/chwl/app/base/BaseListViewModel.java create mode 100644 app/src/main/java/com/chwl/app/base/BaseMsListViewModel.java create mode 100644 app/src/main/java/com/chwl/app/base/BaseMvpActivity.java create mode 100644 app/src/main/java/com/chwl/app/base/BaseMvpFragment.java create mode 100644 app/src/main/java/com/chwl/app/base/BaseMvpPresenter.java create mode 100644 app/src/main/java/com/chwl/app/base/BaseSdDialog.java create mode 100644 app/src/main/java/com/chwl/app/base/BaseVM.java create mode 100644 app/src/main/java/com/chwl/app/base/BaseViewBindingActivity.kt create mode 100644 app/src/main/java/com/chwl/app/base/BaseViewBindingFragment.kt create mode 100644 app/src/main/java/com/chwl/app/base/BaseViewModel.kt create mode 100644 app/src/main/java/com/chwl/app/base/DialogManagerInterface.java create mode 100644 app/src/main/java/com/chwl/app/base/Event.kt create mode 100644 app/src/main/java/com/chwl/app/base/GlobalViewModelOwner.kt create mode 100644 app/src/main/java/com/chwl/app/base/IAcitivityBase.java create mode 100644 app/src/main/java/com/chwl/app/base/IBase.java create mode 100644 app/src/main/java/com/chwl/app/base/IDataStatus.java create mode 100644 app/src/main/java/com/chwl/app/base/PhotoPickActivity.kt create mode 100644 app/src/main/java/com/chwl/app/base/TitleBar.java create mode 100644 app/src/main/java/com/chwl/app/base/list/BaseRecyclerView.java create mode 100644 app/src/main/java/com/chwl/app/base/list/BaseViewHolder.java create mode 100644 app/src/main/java/com/chwl/app/base/list/CommonAdapter.java create mode 100644 app/src/main/java/com/chwl/app/base/list/DefalutStatus.java create mode 100644 app/src/main/java/com/chwl/app/base/list/Header.java create mode 100644 app/src/main/java/com/chwl/app/base/list/IHeaderHolderListener.java create mode 100644 app/src/main/java/com/chwl/app/base/list/IRecyclerListener.java create mode 100644 app/src/main/java/com/chwl/app/base/list/IStatusView.java create mode 100644 app/src/main/java/com/chwl/app/base/list/LineColorDecoration.java create mode 100644 app/src/main/java/com/chwl/app/base/list/LoadingViewHolder.java create mode 100644 app/src/main/java/com/chwl/app/base/list/MultiCommonAdapter.java create mode 100644 app/src/main/java/com/chwl/app/base/list/MultiItemEntity.java create mode 100644 app/src/main/java/com/chwl/app/base/list/OnItemChildClickListener.java create mode 100644 app/src/main/java/com/chwl/app/base/list/OnItemParentClickListener.java create mode 100644 app/src/main/java/com/chwl/app/base/list/RefreshRecyclerView.java create mode 100644 app/src/main/java/com/chwl/app/base/list/WrapperAdapter.java create mode 100644 app/src/main/java/com/chwl/app/bills/activities/BillBaseActivity.java create mode 100644 app/src/main/java/com/chwl/app/bills/activities/BillGiftExpendActivity.java create mode 100644 app/src/main/java/com/chwl/app/bills/activities/BillGiftInComeActivity.java create mode 100644 app/src/main/java/com/chwl/app/bills/activities/BillGiftIncomeGroupActivity.java create mode 100644 app/src/main/java/com/chwl/app/bills/activities/BillNobleActivity.java create mode 100644 app/src/main/java/com/chwl/app/bills/activities/ChargeBillsActivity.java create mode 100644 app/src/main/java/com/chwl/app/bills/activities/ChatBillsActivity.java create mode 100644 app/src/main/java/com/chwl/app/bills/activities/RedBagBillsActivity.java create mode 100644 app/src/main/java/com/chwl/app/bills/activities/TotalBillsActivity.java create mode 100644 app/src/main/java/com/chwl/app/bills/adapter/BillBaseAdapter.java create mode 100644 app/src/main/java/com/chwl/app/bills/adapter/ChargeBillsAdapter.java create mode 100644 app/src/main/java/com/chwl/app/bills/adapter/ChatBillsAdapter.java create mode 100644 app/src/main/java/com/chwl/app/bills/adapter/GiftExpendAdapter.java create mode 100644 app/src/main/java/com/chwl/app/bills/adapter/GiftIncomeAdapter.java create mode 100644 app/src/main/java/com/chwl/app/bills/adapter/NobleBillAdapter.java create mode 100644 app/src/main/java/com/chwl/app/bills/adapter/RadishGiftAdapter.java create mode 100644 app/src/main/java/com/chwl/app/bills/adapter/RedBagBillsAdapter.java create mode 100644 app/src/main/java/com/chwl/app/bills/event/DateInfoEvent.java create mode 100644 app/src/main/java/com/chwl/app/bills/event/TopEvent.java create mode 100644 app/src/main/java/com/chwl/app/bills/fragmemt/BaseBillsFragment.java create mode 100644 app/src/main/java/com/chwl/app/bills/fragmemt/GiftIncomeFragment.java create mode 100644 app/src/main/java/com/chwl/app/bills/fragmemt/GiftOutputFragment.java create mode 100644 app/src/main/java/com/chwl/app/bills/fragmemt/RadishGiftFragment.java create mode 100644 app/src/main/java/com/chwl/app/bills/presenter/BillGiftIncomeGroupPresenter.java create mode 100644 app/src/main/java/com/chwl/app/bills/presenter/GiftIncomePresenter.java create mode 100644 app/src/main/java/com/chwl/app/bills/presenter/GiftOutputPresenter.java create mode 100644 app/src/main/java/com/chwl/app/bills/presenter/RadishGiftPresenter.java create mode 100644 app/src/main/java/com/chwl/app/bills/view/IBillGiftIncomeGroupView.java create mode 100644 app/src/main/java/com/chwl/app/bills/view/IGiftIncomeView.java create mode 100644 app/src/main/java/com/chwl/app/bills/view/IGiftOutputView.java create mode 100644 app/src/main/java/com/chwl/app/bills/view/IRadishGiftView.java create mode 100644 app/src/main/java/com/chwl/app/bills/view/ISmoothToTopView.java create mode 100644 app/src/main/java/com/chwl/app/bills/widget/BillGiftIncomeGroupNavigatorAdapter.java create mode 100644 app/src/main/java/com/chwl/app/bills/widget/BillItemView.java create mode 100644 app/src/main/java/com/chwl/app/bindadapter/BaseAdapter.java create mode 100644 app/src/main/java/com/chwl/app/bindadapter/BaseBindingAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/bindadapter/BaseBindingViewHolder.java create mode 100644 app/src/main/java/com/chwl/app/bindadapter/BindingViewHolder.java create mode 100644 app/src/main/java/com/chwl/app/bindadapter/RvAdapter.java create mode 100644 app/src/main/java/com/chwl/app/bindadapter/ViewAdapter.java create mode 100644 app/src/main/java/com/chwl/app/common/AbsStatusFragment.java create mode 100644 app/src/main/java/com/chwl/app/common/CommonPagerAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/common/EmptyViewHelper.java create mode 100644 app/src/main/java/com/chwl/app/common/IStatusFragment.java create mode 100644 app/src/main/java/com/chwl/app/common/LoadingFragment.java create mode 100644 app/src/main/java/com/chwl/app/common/NetworkErrorFragment.java create mode 100644 app/src/main/java/com/chwl/app/common/NoDataFragment.java create mode 100644 app/src/main/java/com/chwl/app/common/ReloadFragment.java create mode 100644 app/src/main/java/com/chwl/app/common/ViewPagerAdapter.java create mode 100644 app/src/main/java/com/chwl/app/common/app/ActivityStack.java create mode 100644 app/src/main/java/com/chwl/app/common/dialog/DialogCommon.kt create mode 100644 app/src/main/java/com/chwl/app/common/permission/EasyPermissions.java create mode 100644 app/src/main/java/com/chwl/app/common/permission/PermissionActivity.java create mode 100644 app/src/main/java/com/chwl/app/common/permission/StatusBarCompat.java create mode 100644 app/src/main/java/com/chwl/app/common/server/NetworkService.java create mode 100644 app/src/main/java/com/chwl/app/common/svga/SimpleSvgaCallback.java create mode 100644 app/src/main/java/com/chwl/app/common/svga/SimpleSvgaParseCompletion.java create mode 100644 app/src/main/java/com/chwl/app/common/util/AppLifeCycleHelper.java create mode 100644 app/src/main/java/com/chwl/app/common/util/BitmapUtil.java create mode 100644 app/src/main/java/com/chwl/app/common/util/DialogCommonUtil.java create mode 100644 app/src/main/java/com/chwl/app/common/util/PauseWorkerHandler.java create mode 100644 app/src/main/java/com/chwl/app/common/widget/AgeSexView.java create mode 100644 app/src/main/java/com/chwl/app/common/widget/BadgeView.java create mode 100644 app/src/main/java/com/chwl/app/common/widget/ChangeColorIconWithText.java create mode 100644 app/src/main/java/com/chwl/app/common/widget/CircleGradualImageView.java create mode 100644 app/src/main/java/com/chwl/app/common/widget/CircleImageSpan.java create mode 100644 app/src/main/java/com/chwl/app/common/widget/CircleImageView.java create mode 100644 app/src/main/java/com/chwl/app/common/widget/CustomAutoWidthImageSpan.java create mode 100644 app/src/main/java/com/chwl/app/common/widget/CustomImageSpan.java create mode 100644 app/src/main/java/com/chwl/app/common/widget/DragLayout.java create mode 100644 app/src/main/java/com/chwl/app/common/widget/FloatingLiveMiniView.java create mode 100644 app/src/main/java/com/chwl/app/common/widget/LimitEditText.java create mode 100644 app/src/main/java/com/chwl/app/common/widget/LoadingImageView.java create mode 100644 app/src/main/java/com/chwl/app/common/widget/MaskImageView.java create mode 100644 app/src/main/java/com/chwl/app/common/widget/OriginalDrawStatusClickSpan.java create mode 100644 app/src/main/java/com/chwl/app/common/widget/OvalImageView.java create mode 100644 app/src/main/java/com/chwl/app/common/widget/PlayerView.java create mode 100644 app/src/main/java/com/chwl/app/common/widget/RectRoundImageView.java create mode 100644 app/src/main/java/com/chwl/app/common/widget/SlideListViewPager.java create mode 100644 app/src/main/java/com/chwl/app/common/widget/StatusLayout.java create mode 100644 app/src/main/java/com/chwl/app/common/widget/TextDrawable.java create mode 100644 app/src/main/java/com/chwl/app/common/widget/TutuSwitchView.java create mode 100644 app/src/main/java/com/chwl/app/common/widget/dialog/BaseAlertDialogBuilder.java create mode 100644 app/src/main/java/com/chwl/app/common/widget/dialog/ChooseWorldsIndicatorAdapter.java create mode 100644 app/src/main/java/com/chwl/app/common/widget/dialog/CommonPopupDialog.java create mode 100644 app/src/main/java/com/chwl/app/common/widget/dialog/CustomPopupDialog.java create mode 100644 app/src/main/java/com/chwl/app/common/widget/dialog/DialogManager.java create mode 100644 app/src/main/java/com/chwl/app/common/widget/dialog/DialogUiHelper.java create mode 100644 app/src/main/java/com/chwl/app/common/widget/dialog/ListViewMenuItem.java create mode 100644 app/src/main/java/com/chwl/app/common/widget/dialog/LoadingImageView.java create mode 100644 app/src/main/java/com/chwl/app/common/widget/dialog/TimeOutProgressDialog.java create mode 100644 app/src/main/java/com/chwl/app/constants/AnyType.java create mode 100644 app/src/main/java/com/chwl/app/constants/BundleKeys.java create mode 100644 app/src/main/java/com/chwl/app/constants/UserInfoConstants.java create mode 100644 app/src/main/java/com/chwl/app/decoration/adapter/CarShopAdapter.java create mode 100644 app/src/main/java/com/chwl/app/decoration/adapter/DecorationCommonAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/decoration/adapter/DressUpAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/decoration/adapter/MyCarAdapter.java create mode 100644 app/src/main/java/com/chwl/app/decoration/adapter/MyChatBubbleAdapter.java create mode 100644 app/src/main/java/com/chwl/app/decoration/adapter/MyHeadWearAdapter.java create mode 100644 app/src/main/java/com/chwl/app/decoration/adapter/MyNamePlateAdapter.java create mode 100644 app/src/main/java/com/chwl/app/decoration/adapter/MyUserCardWearAdapter.java create mode 100644 app/src/main/java/com/chwl/app/decoration/helper/DecorationDialogHelper.java create mode 100644 app/src/main/java/com/chwl/app/decoration/helper/DecorationHelper.java create mode 100644 app/src/main/java/com/chwl/app/decoration/helper/DecorationSaleType.java create mode 100644 app/src/main/java/com/chwl/app/decoration/ui/DressUpDialog.kt create mode 100644 app/src/main/java/com/chwl/app/decoration/ui/activity/DressUpTabActivity.kt create mode 100644 app/src/main/java/com/chwl/app/decoration/ui/fragment/DressUpMyFragment.kt create mode 100644 app/src/main/java/com/chwl/app/decoration/ui/fragment/DressUpStoreFragment.kt create mode 100644 app/src/main/java/com/chwl/app/decoration/util/DressUpUtil.kt create mode 100644 app/src/main/java/com/chwl/app/decoration/view/DecorationCommonFragment.kt create mode 100644 app/src/main/java/com/chwl/app/decoration/view/DecorationStoreActivity.kt create mode 100644 app/src/main/java/com/chwl/app/decoration/view/ICarView.java create mode 100644 app/src/main/java/com/chwl/app/decoration/view/MyCarFragment.java create mode 100644 app/src/main/java/com/chwl/app/decoration/view/MyChatBubbleFragment.java create mode 100644 app/src/main/java/com/chwl/app/decoration/view/MyDecorationActivity.java create mode 100644 app/src/main/java/com/chwl/app/decoration/view/MyHeadWearFragment.java create mode 100644 app/src/main/java/com/chwl/app/decoration/view/MyNamePlateFragment.java create mode 100644 app/src/main/java/com/chwl/app/decoration/view/MyUserCardWearFragment.java create mode 100644 app/src/main/java/com/chwl/app/decoration/view/widgets/BadgeScaleTransitionPagerTitleView.java create mode 100644 app/src/main/java/com/chwl/app/decoration/view/widgets/CarMagicIndicator.java create mode 100644 app/src/main/java/com/chwl/app/decoration/view/widgets/MyDecorationMagicIndicator.java create mode 100644 app/src/main/java/com/chwl/app/decoration/viewmodel/CarShopVm.java create mode 100644 app/src/main/java/com/chwl/app/decoration/viewmodel/DecorationViewModel.kt create mode 100644 app/src/main/java/com/chwl/app/decoration/viewmodel/HeadWearVm.java create mode 100644 app/src/main/java/com/chwl/app/decoration/viewmodel/MyCarVm.java create mode 100644 app/src/main/java/com/chwl/app/decoration/viewmodel/UserCardWearVm.java create mode 100644 app/src/main/java/com/chwl/app/decoration/viewmodel/UserChatBubbleVm.java create mode 100644 app/src/main/java/com/chwl/app/earn/EarnRecordViewModel.kt create mode 100644 app/src/main/java/com/chwl/app/earn/activity/ConvertDiamondActivity.kt create mode 100644 app/src/main/java/com/chwl/app/earn/activity/EarnRecordActivity.kt create mode 100644 app/src/main/java/com/chwl/app/earn/activity/GoldDetailActivity.kt create mode 100644 app/src/main/java/com/chwl/app/earn/adapter/GoldDetailAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/earn/adapter/GoldRecordAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/earn/adapter/GoldRoomAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/event/ChargeEvent.java create mode 100644 app/src/main/java/com/chwl/app/event/DressUpEvent.java create mode 100644 app/src/main/java/com/chwl/app/event/OpenRoomIntroEvent.java create mode 100644 app/src/main/java/com/chwl/app/fansteam/FansTeamJoinActivity.kt create mode 100644 app/src/main/java/com/chwl/app/fansteam/FansTeamJoinedActivity.kt create mode 100644 app/src/main/java/com/chwl/app/fansteam/FansTeamListActivity.kt create mode 100644 app/src/main/java/com/chwl/app/fansteam/FansTeamListAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/fansteam/FansTeamTaskAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/fansteam/FansTeamViewModel.kt create mode 100644 app/src/main/java/com/chwl/app/friend/Holder.java create mode 100644 app/src/main/java/com/chwl/app/friend/action/AbstractSelectFriendAction.java create mode 100644 app/src/main/java/com/chwl/app/friend/action/DefaultSelectFriendAction.java create mode 100644 app/src/main/java/com/chwl/app/friend/action/SelectFriendManager.java create mode 100644 app/src/main/java/com/chwl/app/friend/view/SelectFriendActivity.java create mode 100644 app/src/main/java/com/chwl/app/guide/GuideActivity.java create mode 100644 app/src/main/java/com/chwl/app/home/HomeMeViewModel.kt create mode 100644 app/src/main/java/com/chwl/app/home/HomeMessageViewModel.kt create mode 100644 app/src/main/java/com/chwl/app/home/HomeViewModel.kt create mode 100644 app/src/main/java/com/chwl/app/home/MeViewModel.kt create mode 100644 app/src/main/java/com/chwl/app/home/RoomCommonViewModel.kt create mode 100644 app/src/main/java/com/chwl/app/home/RoomSingleViewModel.kt create mode 100644 app/src/main/java/com/chwl/app/home/activity/AssociationActivity.kt create mode 100644 app/src/main/java/com/chwl/app/home/activity/CollectionRoomActivity.java create mode 100644 app/src/main/java/com/chwl/app/home/activity/CommunityNoticeAct.java create mode 100644 app/src/main/java/com/chwl/app/home/activity/EventCenterActivity.kt create mode 100644 app/src/main/java/com/chwl/app/home/activity/EventCreateActivity.kt create mode 100644 app/src/main/java/com/chwl/app/home/activity/EventMyAllActivity.kt create mode 100644 app/src/main/java/com/chwl/app/home/activity/EventSelectRoomActivity.kt create mode 100644 app/src/main/java/com/chwl/app/home/activity/NewUserListActivity.java create mode 100644 app/src/main/java/com/chwl/app/home/activity/RoomHistoryListActivity.kt create mode 100644 app/src/main/java/com/chwl/app/home/activity/VisitorListActivity.kt create mode 100644 app/src/main/java/com/chwl/app/home/adapter/BannerAdapter.java create mode 100644 app/src/main/java/com/chwl/app/home/adapter/CollectionRoomAdapter.java create mode 100644 app/src/main/java/com/chwl/app/home/adapter/CommunityNoticeAdapter.java create mode 100644 app/src/main/java/com/chwl/app/home/adapter/ContactsIndicatorAdapter.java create mode 100644 app/src/main/java/com/chwl/app/home/adapter/EventOfficialAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/home/adapter/EventSelectRoomAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/home/adapter/EventSquareAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/home/adapter/FindNewUserListAdapter.java create mode 100644 app/src/main/java/com/chwl/app/home/adapter/FragmentViewPagerAdapter.java create mode 100644 app/src/main/java/com/chwl/app/home/adapter/HomeBannerAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/home/adapter/HomeChatAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/home/adapter/HomeConcernsAdapter.java create mode 100644 app/src/main/java/com/chwl/app/home/adapter/HomeIndicatorAdapter.java create mode 100644 app/src/main/java/com/chwl/app/home/adapter/HomeLiveTopAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/home/adapter/HomeRankViewFlipperAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/home/adapter/HomeRoomAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/home/adapter/HomeRoomFragmentAdapter.java create mode 100644 app/src/main/java/com/chwl/app/home/adapter/HomeRoomUserAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/home/adapter/HomeTopAdapter.java create mode 100644 app/src/main/java/com/chwl/app/home/adapter/MainMagicIndicatorAdapter.java create mode 100644 app/src/main/java/com/chwl/app/home/adapter/MeCenterAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/home/adapter/MeGameAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/home/adapter/RoomActAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/home/adapter/RoomCommonAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/home/adapter/RoomGameAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/home/adapter/RoomHistoryListAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/home/adapter/RoomNewFriendsAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/home/adapter/TopMagicIndicatorAdapter.java create mode 100644 app/src/main/java/com/chwl/app/home/adapter/VisitorListAdapter.java create mode 100644 app/src/main/java/com/chwl/app/home/dialog/EventDurationDialog.kt create mode 100644 app/src/main/java/com/chwl/app/home/dialog/HelloMessageDialog.kt create mode 100644 app/src/main/java/com/chwl/app/home/dialog/NewUserHelloDialog.kt create mode 100644 app/src/main/java/com/chwl/app/home/dialog/ProtocolUpdateDialog.java create mode 100644 app/src/main/java/com/chwl/app/home/dialog/RecommendRoomDialog.kt create mode 100644 app/src/main/java/com/chwl/app/home/event/ContactTrashEvent.java create mode 100644 app/src/main/java/com/chwl/app/home/fragment/AttentionFragment.java create mode 100644 app/src/main/java/com/chwl/app/home/fragment/ContactsListFragment.kt create mode 100644 app/src/main/java/com/chwl/app/home/fragment/EventMyFragment.kt create mode 100644 app/src/main/java/com/chwl/app/home/fragment/EventOfficialFragment.kt create mode 100644 app/src/main/java/com/chwl/app/home/fragment/EventSquareFragment.kt create mode 100644 app/src/main/java/com/chwl/app/home/fragment/HomeFragment.kt create mode 100644 app/src/main/java/com/chwl/app/home/fragment/HomeRecommendFragment.kt create mode 100644 app/src/main/java/com/chwl/app/home/fragment/HomeRoomCollectListFragment.kt create mode 100644 app/src/main/java/com/chwl/app/home/fragment/HomeRoomHistoryListFragment.kt create mode 100644 app/src/main/java/com/chwl/app/home/fragment/HomeTabRoomFragment.kt create mode 100644 app/src/main/java/com/chwl/app/home/fragment/HomeWithMeFragment.kt create mode 100644 app/src/main/java/com/chwl/app/home/fragment/MeFragment.kt create mode 100644 app/src/main/java/com/chwl/app/home/helper/AutoScrollTask.kt create mode 100644 app/src/main/java/com/chwl/app/home/helper/BannerHelper.kt create mode 100644 app/src/main/java/com/chwl/app/home/helper/EventCenterUtil.kt create mode 100644 app/src/main/java/com/chwl/app/home/helper/LoadPageDataHelper.java create mode 100644 app/src/main/java/com/chwl/app/home/helper/OpenRoomHelper.java create mode 100644 app/src/main/java/com/chwl/app/home/presenter/CommunityNoticePresenter.java create mode 100644 app/src/main/java/com/chwl/app/home/presenter/MainFragmentPresenter.java create mode 100644 app/src/main/java/com/chwl/app/home/presenter/MainPresenter.java create mode 100644 app/src/main/java/com/chwl/app/home/presenter/NewUserListPresenter.java create mode 100644 app/src/main/java/com/chwl/app/home/view/ICommunityNoticeAct.java create mode 100644 app/src/main/java/com/chwl/app/home/view/IFamilyHomeActivityView.java create mode 100644 app/src/main/java/com/chwl/app/home/view/IMainFragmentView.java create mode 100644 app/src/main/java/com/chwl/app/home/view/IMainView.java create mode 100644 app/src/main/java/com/chwl/app/home/view/INewUserListActivityView.java create mode 100644 app/src/main/java/com/chwl/app/home/widget/AnchorCardView.kt create mode 100644 app/src/main/java/com/chwl/app/home/widget/ListViewAdaptWidth.java create mode 100644 app/src/main/java/com/chwl/app/home/widget/MePageIndicatorView.java create mode 100644 app/src/main/java/com/chwl/app/home/widget/StickyScrollView.java create mode 100644 app/src/main/java/com/chwl/app/luckymoney/adapter/LuckyMoneyMemberListAdapter.java create mode 100644 app/src/main/java/com/chwl/app/luckymoney/dialog/LuckyMoneyComfirmToPayDialog.java create mode 100644 app/src/main/java/com/chwl/app/luckymoney/dialog/LuckyMoneyDialog.java create mode 100644 app/src/main/java/com/chwl/app/luckymoney/view/LuckyMoneyCreationActivity.java create mode 100644 app/src/main/java/com/chwl/app/luckymoney/view/LuckyMoneyDetailActivity.java create mode 100644 app/src/main/java/com/chwl/app/luckymoney/viewholder/LuckyMoneyMsgViewHolder.java create mode 100644 app/src/main/java/com/chwl/app/luckymoney/viewholder/LuckyMoneyTipsViewHolder.java create mode 100644 app/src/main/java/com/chwl/app/module/Extras.java create mode 100644 app/src/main/java/com/chwl/app/module/IRoomNewbieMessageView.java create mode 100644 app/src/main/java/com/chwl/app/module/IRoomNewbieView.java create mode 100644 app/src/main/java/com/chwl/app/module/RoomNewbieModel.java create mode 100644 app/src/main/java/com/chwl/app/monsterhunting/ImpactValueLayout.java create mode 100644 app/src/main/java/com/chwl/app/monsterhunting/MonsterEscapeDialog.java create mode 100644 app/src/main/java/com/chwl/app/monsterhunting/MonsterHuntingAnimationManager.java create mode 100644 app/src/main/java/com/chwl/app/monsterhunting/MonsterHuntingIntroductionDialog.java create mode 100644 app/src/main/java/com/chwl/app/monsterhunting/MonsterHuntingRewardDialog.java create mode 100644 app/src/main/java/com/chwl/app/monsterhunting/MonsterHuntingRewardsAdapter.java create mode 100644 app/src/main/java/com/chwl/app/monsterhunting/MonsterHuntingSvgaManager.java create mode 100644 app/src/main/java/com/chwl/app/monsterhunting/QuitConfirmDialog.java create mode 100644 app/src/main/java/com/chwl/app/monsterhunting/SimpleCountDownTimer.java create mode 100644 app/src/main/java/com/chwl/app/monsterhunting/bean/AttackMonsterResultInfo.java create mode 100644 app/src/main/java/com/chwl/app/monsterhunting/bean/UpdateMyGoldInfo.java create mode 100644 app/src/main/java/com/chwl/app/notify/GlobalNotifyManager.kt create mode 100644 app/src/main/java/com/chwl/app/notify/GlobalNotifyManagerNew.kt create mode 100644 app/src/main/java/com/chwl/app/notify/NotifyAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/notify/RoomNotifyManager.kt create mode 100644 app/src/main/java/com/chwl/app/notify/views/BaiShunGameNotify.kt create mode 100644 app/src/main/java/com/chwl/app/notify/views/FindLoveImageNotify.kt create mode 100644 app/src/main/java/com/chwl/app/notify/views/GiftNotify.kt create mode 100644 app/src/main/java/com/chwl/app/notify/views/LuckyBagGiftNotify.kt create mode 100644 app/src/main/java/com/chwl/app/notify/views/TemplateImageNotify.kt create mode 100644 app/src/main/java/com/chwl/app/notify/views/TemplateSvgaNotify.kt create mode 100644 app/src/main/java/com/chwl/app/notify/views/TestNotify.kt create mode 100644 app/src/main/java/com/chwl/app/other/SplashBitmapTransformation.java create mode 100644 app/src/main/java/com/chwl/app/other/activity/SplashActivity.java create mode 100644 app/src/main/java/com/chwl/app/other/dialog/PrivacyAgreementDialog.java create mode 100644 app/src/main/java/com/chwl/app/other/present/SplashPresenter.java create mode 100644 app/src/main/java/com/chwl/app/other/view/ISplashView.java create mode 100644 app/src/main/java/com/chwl/app/pay/GiveGoldModel.kt create mode 100644 app/src/main/java/com/chwl/app/pay/activity/GiveGoldActivity.kt create mode 100644 app/src/main/java/com/chwl/app/pay/activity/GiveGoldAgentsActivity.kt create mode 100644 app/src/main/java/com/chwl/app/pay/activity/GiveGoldBiliActivity.kt create mode 100644 app/src/main/java/com/chwl/app/pay/activity/GiveGoldDetailActivity.kt create mode 100644 app/src/main/java/com/chwl/app/pay/activity/GiveGoldSearchActivity.kt create mode 100644 app/src/main/java/com/chwl/app/pay/activity/GiveGoldToUserActivity.kt create mode 100644 app/src/main/java/com/chwl/app/pay/adapter/GiveDiamondDetailAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/pay/adapter/GiveGiftAdapter.java create mode 100644 app/src/main/java/com/chwl/app/pay/adapter/GiveGiftDetailAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/pay/adapter/GiveSearchAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/pay/adapter/LatelyGiveAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/pay/fragment/GiveDiamondFragment.kt create mode 100644 app/src/main/java/com/chwl/app/pay/fragment/GiveGiftFragment.kt create mode 100644 app/src/main/java/com/chwl/app/pay/interfaces/PasswordView.java create mode 100644 app/src/main/java/com/chwl/app/pay/password/GiveGoldPassWordFragment.java create mode 100644 app/src/main/java/com/chwl/app/pay/password/GiveGoldPasswordView.java create mode 100644 app/src/main/java/com/chwl/app/pay/presenter/ChargePresenter.java create mode 100644 app/src/main/java/com/chwl/app/pay/presenter/PayPresenter.java create mode 100644 app/src/main/java/com/chwl/app/pay/view/IChargeView.java create mode 100644 app/src/main/java/com/chwl/app/pay/view/IPayView.java create mode 100644 app/src/main/java/com/chwl/app/pay/widget/GridPasswordNoFocusView.java create mode 100644 app/src/main/java/com/chwl/app/photo/BigPagerAdapter.java create mode 100644 app/src/main/java/com/chwl/app/photo/BigPhotoActivity.java create mode 100644 app/src/main/java/com/chwl/app/photo/BigPhotoItemFragment.java create mode 100644 app/src/main/java/com/chwl/app/photo/DynamicImageAdapter.java create mode 100644 app/src/main/java/com/chwl/app/photo/OnFragmentOptionListener.java create mode 100644 app/src/main/java/com/chwl/app/photo/PagerOption.java create mode 100644 app/src/main/java/com/chwl/app/photo/PhotoAdapter.java create mode 100644 app/src/main/java/com/chwl/app/photo/PreviewPhotoActivity.java create mode 100644 app/src/main/java/com/chwl/app/photo/ZoomImageView.java create mode 100644 app/src/main/java/com/chwl/app/radish/activity/RadishRecordActivity.java create mode 100644 app/src/main/java/com/chwl/app/radish/adapter/RadishRecordAdapter.java create mode 100644 app/src/main/java/com/chwl/app/radish/helper/PrizeAnimUiHelper.java create mode 100644 app/src/main/java/com/chwl/app/radish/helper/TaskCenterDialogHelper.java create mode 100644 app/src/main/java/com/chwl/app/radish/presenter/RadishRecordFrgPresenter.java create mode 100644 app/src/main/java/com/chwl/app/radish/presenter/RadishRecordPresenter.java create mode 100644 app/src/main/java/com/chwl/app/radish/task/activity/TaskCenterActivity.java create mode 100644 app/src/main/java/com/chwl/app/radish/task/adpter/TaskCenterAdapter.java create mode 100644 app/src/main/java/com/chwl/app/radish/task/fragment/TaskCenterFragment.java create mode 100644 app/src/main/java/com/chwl/app/radish/task/presenter/TaskCenterFrgPresenter.java create mode 100644 app/src/main/java/com/chwl/app/radish/task/presenter/TaskCenterPresenter.java create mode 100644 app/src/main/java/com/chwl/app/radish/task/view/ITaskCenterView.java create mode 100644 app/src/main/java/com/chwl/app/radish/task/view/ITaskCenterViewFrg.java create mode 100644 app/src/main/java/com/chwl/app/radish/view/IRadishRecordFrgView.java create mode 100644 app/src/main/java/com/chwl/app/radish/view/IRadishRecordView.java create mode 100644 app/src/main/java/com/chwl/app/radish/wallet/RadishWalletManager.java create mode 100644 app/src/main/java/com/chwl/app/radish/widget/RadishRecordNavAdapter.java create mode 100644 app/src/main/java/com/chwl/app/radish/widget/TaskCenterNavAdapter.java create mode 100644 app/src/main/java/com/chwl/app/reciever/IncomingCallReceiver.java create mode 100644 app/src/main/java/com/chwl/app/reciever/NotificationClickReceiver.java create mode 100644 app/src/main/java/com/chwl/app/reciever/OnePixelReceiver.java create mode 100644 app/src/main/java/com/chwl/app/relation/cp/CpDataManager.java create mode 100644 app/src/main/java/com/chwl/app/relation/cp/CpDataParser.kt create mode 100644 app/src/main/java/com/chwl/app/relation/cp/CpViewHelper.kt create mode 100644 app/src/main/java/com/chwl/app/relation/cp/activity/CpHomeActivity.kt create mode 100644 app/src/main/java/com/chwl/app/relation/cp/activity/CpInviteRecordActivity.kt create mode 100644 app/src/main/java/com/chwl/app/relation/cp/activity/CpTaskActivity.kt create mode 100644 app/src/main/java/com/chwl/app/relation/cp/adapter/CpTaskAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/relation/cp/adapter/CpTaskIndicatorAdapter.java create mode 100644 app/src/main/java/com/chwl/app/relation/cp/adapter/DeclarationRecommondAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/relation/cp/adapter/InviteRecordAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/relation/cp/adapter/TaskPagerAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/relation/cp/dialog/CpGlobalDialog.kt create mode 100644 app/src/main/java/com/chwl/app/relation/cp/dialog/CpInvitePageDialog.kt create mode 100644 app/src/main/java/com/chwl/app/relation/cp/dialog/CpInviteReplyConfirmDialog.kt create mode 100644 app/src/main/java/com/chwl/app/relation/cp/dialog/CpInviteReplyDialog.kt create mode 100644 app/src/main/java/com/chwl/app/relation/cp/dialog/CpMpDialog.kt create mode 100644 app/src/main/java/com/chwl/app/relation/cp/fragment/CpTaskFragment.kt create mode 100644 app/src/main/java/com/chwl/app/relation/cp/fragment/UserInfoCpFragment.kt create mode 100644 app/src/main/java/com/chwl/app/relation/cp/model/Api.kt create mode 100644 app/src/main/java/com/chwl/app/relation/cp/model/CpModel.kt create mode 100644 app/src/main/java/com/chwl/app/relation/cp/viewmodel/CpViewModel.kt create mode 100644 app/src/main/java/com/chwl/app/relation/cp/widget/CpTaskDescriptionView.kt create mode 100644 app/src/main/java/com/chwl/app/relation/cp/widget/RelationCpCardView.kt create mode 100644 app/src/main/java/com/chwl/app/relation/extention/RelationExtention.kt create mode 100644 app/src/main/java/com/chwl/app/service/DaemonService.java create mode 100644 app/src/main/java/com/chwl/app/share/Holder.java create mode 100644 app/src/main/java/com/chwl/app/share/viewholder/InAppSharingMsgViewHolder.java create mode 100644 app/src/main/java/com/chwl/app/skill/SKillDataParser.kt create mode 100644 app/src/main/java/com/chwl/app/skill/SkillDataDelegate.kt create mode 100644 app/src/main/java/com/chwl/app/skill/activity/AddSkillActivity.kt create mode 100644 app/src/main/java/com/chwl/app/skill/activity/EditSkillActivity.kt create mode 100644 app/src/main/java/com/chwl/app/skill/activity/SkillDetailActivity.kt create mode 100644 app/src/main/java/com/chwl/app/skill/activity/SkillEditableDelegate.kt create mode 100644 app/src/main/java/com/chwl/app/skill/activity/SkillHomeActivity.kt create mode 100644 app/src/main/java/com/chwl/app/skill/adapter/AddSkillCardAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/skill/adapter/MineSkillCardAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/skill/adapter/SkillSelectionAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/skill/decoration/SkillGridDecoration.kt create mode 100644 app/src/main/java/com/chwl/app/skill/decoration/SkillLinearVerticalDecoration.kt create mode 100644 app/src/main/java/com/chwl/app/skill/dialog/AddSkillCardDialog.kt create mode 100644 app/src/main/java/com/chwl/app/skill/dialog/SkillSelectionDialog.kt create mode 100644 app/src/main/java/com/chwl/app/skill/repository/Api.kt create mode 100644 app/src/main/java/com/chwl/app/skill/repository/ISkillModel.kt create mode 100644 app/src/main/java/com/chwl/app/skill/repository/SkillDataManager.java create mode 100644 app/src/main/java/com/chwl/app/skill/repository/SkillModel.kt create mode 100644 app/src/main/java/com/chwl/app/skill/widget/EditItem.kt create mode 100644 app/src/main/java/com/chwl/app/skill/widget/ItemAttribute.kt create mode 100644 app/src/main/java/com/chwl/app/skill/widget/ItemEventListener.kt create mode 100644 app/src/main/java/com/chwl/app/skill/widget/RecordDurationItem.kt create mode 100644 app/src/main/java/com/chwl/app/skill/widget/RecordIResourceItem.kt create mode 100644 app/src/main/java/com/chwl/app/skill/widget/SelectionItem.kt create mode 100644 app/src/main/java/com/chwl/app/skill/widget/SkillAttribute.kt create mode 100644 app/src/main/java/com/chwl/app/skill/widget/SkillCardView.kt create mode 100644 app/src/main/java/com/chwl/app/skill/widget/SkillItem.kt create mode 100644 app/src/main/java/com/chwl/app/skill/widget/SkillItemHelper.kt create mode 100644 app/src/main/java/com/chwl/app/skill/widget/TimerRecorderView.kt create mode 100644 app/src/main/java/com/chwl/app/star/DefAnimatorListener.kt create mode 100644 app/src/main/java/com/chwl/app/star/SendGiftTipsDialog.kt create mode 100644 app/src/main/java/com/chwl/app/star/StarAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/star/StarFragment.kt create mode 100644 app/src/main/java/com/chwl/app/star/StarViewModel.kt create mode 100644 app/src/main/java/com/chwl/app/support/FragmentVisibleStateHelper.kt create mode 100644 app/src/main/java/com/chwl/app/support/IMUserInfoProvider.kt create mode 100644 app/src/main/java/com/chwl/app/support/PreloadResourceViewModel.kt create mode 100644 app/src/main/java/com/chwl/app/support/float/BaseFloatView.kt create mode 100644 app/src/main/java/com/chwl/app/support/float/DoubleQueue.kt create mode 100644 app/src/main/java/com/chwl/app/support/float/FloatQueue.kt create mode 100644 app/src/main/java/com/chwl/app/support/float/FloatView.kt create mode 100644 app/src/main/java/com/chwl/app/support/float/FloatViewAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/support/float/FloatWindow.kt create mode 100644 app/src/main/java/com/chwl/app/support/float/FloatWindowEngine.kt create mode 100644 app/src/main/java/com/chwl/app/support/float/QueueItem.kt create mode 100644 app/src/main/java/com/chwl/app/support/float/SimpleFloatQueue.kt create mode 100644 app/src/main/java/com/chwl/app/support/float/SimpleFloatWindow.kt create mode 100644 app/src/main/java/com/chwl/app/sys/ErbanSysMsgViewModel.java create mode 100644 app/src/main/java/com/chwl/app/team/adapter/AddTeamMemberAdapter.java create mode 100644 app/src/main/java/com/chwl/app/team/adapter/TeamListAdapter.java create mode 100644 app/src/main/java/com/chwl/app/team/adapter/TeamMemberListAdapter.java create mode 100644 app/src/main/java/com/chwl/app/team/adapter/TeamWeeklyBillAdapter.java create mode 100644 app/src/main/java/com/chwl/app/team/bean/NimTeamMember.java create mode 100644 app/src/main/java/com/chwl/app/team/dialog/QuitTeamDialog.java create mode 100644 app/src/main/java/com/chwl/app/team/event/TeamMemberUpdateEvent.java create mode 100644 app/src/main/java/com/chwl/app/team/view/AddMemberActivity.java create mode 100644 app/src/main/java/com/chwl/app/team/view/AddMemberSearchActivity.java create mode 100644 app/src/main/java/com/chwl/app/team/view/CreateTeamMessageActivity.java create mode 100644 app/src/main/java/com/chwl/app/team/view/NimTeamManagementActivity.java create mode 100644 app/src/main/java/com/chwl/app/team/view/NimTeamMessageActivity.java create mode 100644 app/src/main/java/com/chwl/app/team/view/NimTeamMessageFragment.java create mode 100644 app/src/main/java/com/chwl/app/team/view/TeamListFragment.java create mode 100644 app/src/main/java/com/chwl/app/team/view/TeamMemberListActivity.java create mode 100644 app/src/main/java/com/chwl/app/team/view/TeamMemberSearchListActivity.java create mode 100644 app/src/main/java/com/chwl/app/team/view/TeamWeeklyBillActivity.java create mode 100644 app/src/main/java/com/chwl/app/team/view/TeamWeeklyBillSearchActivity.java create mode 100644 app/src/main/java/com/chwl/app/team/view/UpdateTeamNameActivity.java create mode 100644 app/src/main/java/com/chwl/app/team/viewmodel/FamilyMemberVM.java create mode 100644 app/src/main/java/com/chwl/app/team/viewmodel/TeamVM.java create mode 100644 app/src/main/java/com/chwl/app/ui/adapter/GiftAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/ui/adapter/StarWeekAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/anim/AnimFactory.java create mode 100644 app/src/main/java/com/chwl/app/ui/anim/FlowFaceDrawable.java create mode 100644 app/src/main/java/com/chwl/app/ui/anim/FrameAnimation.java create mode 100644 app/src/main/java/com/chwl/app/ui/anim/OneFaceDrawable.java create mode 100644 app/src/main/java/com/chwl/app/ui/anim/OverlayFaceDrawable.java create mode 100644 app/src/main/java/com/chwl/app/ui/anim/WavingDrawable.java create mode 100644 app/src/main/java/com/chwl/app/ui/bean/BaseResponse.java create mode 100644 app/src/main/java/com/chwl/app/ui/bean/CountryBean.java create mode 100644 app/src/main/java/com/chwl/app/ui/bean/FirstRechargeInfo.java create mode 100644 app/src/main/java/com/chwl/app/ui/bean/Footer.java create mode 100644 app/src/main/java/com/chwl/app/ui/bean/FooterLoadMoreBean.java create mode 100644 app/src/main/java/com/chwl/app/ui/bean/GiveGoldAgentBean.java create mode 100644 app/src/main/java/com/chwl/app/ui/bean/GiveGoldBiliBean.java create mode 100644 app/src/main/java/com/chwl/app/ui/bean/GiveGoldBiliEntity.java create mode 100644 app/src/main/java/com/chwl/app/ui/bean/LevelChargeBean.java create mode 100644 app/src/main/java/com/chwl/app/ui/bean/RechargeUserInfo.java create mode 100644 app/src/main/java/com/chwl/app/ui/bean/ShareInfo.java create mode 100644 app/src/main/java/com/chwl/app/ui/bean/header.java create mode 100644 app/src/main/java/com/chwl/app/ui/debug/DebugActivity.kt create mode 100644 app/src/main/java/com/chwl/app/ui/debug/DebugAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/ui/feedback/CustomerServiceDialog.kt create mode 100644 app/src/main/java/com/chwl/app/ui/feedback/CustomerServiceItemAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/ui/feedback/FeedbackActivity.kt create mode 100644 app/src/main/java/com/chwl/app/ui/feedback/FeedbackTypeAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/ui/feedback/FeedbackViewModel.kt create mode 100644 app/src/main/java/com/chwl/app/ui/game_team/invite/GameTeamInviteDialog.kt create mode 100644 app/src/main/java/com/chwl/app/ui/game_team/invite/GameTeamInviteViewModel.kt create mode 100644 app/src/main/java/com/chwl/app/ui/game_team/record/GameTeamRecordActivity.kt create mode 100644 app/src/main/java/com/chwl/app/ui/game_team/record/GameTeamRecordAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/ui/game_team/record/GameTeamRecordFragment.kt create mode 100644 app/src/main/java/com/chwl/app/ui/game_team/record/GameTeamRecordIndicatorAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/game_team/record/GameTeamRecordViewModel.kt create mode 100644 app/src/main/java/com/chwl/app/ui/gift/adapter/FaceGVAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/gift/adapter/FaceVPAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/gift/callback/OnGiftDialogBtnClickListenerWrapper.java create mode 100644 app/src/main/java/com/chwl/app/ui/gift/dialog/GiftGridView.java create mode 100644 app/src/main/java/com/chwl/app/ui/gift/dialog/GiftInfoVm.java create mode 100644 app/src/main/java/com/chwl/app/ui/gift/dialog/PageIndicatorView.java create mode 100644 app/src/main/java/com/chwl/app/ui/gift/gif/AnimatedGifDrawable.java create mode 100644 app/src/main/java/com/chwl/app/ui/gift/gif/AnimatedImageSpan.java create mode 100644 app/src/main/java/com/chwl/app/ui/gift/gif/GifDecoder.java create mode 100644 app/src/main/java/com/chwl/app/ui/gift/util/ExpressionUtil.java create mode 100644 app/src/main/java/com/chwl/app/ui/gift/util/GiftPanelControl.java create mode 100644 app/src/main/java/com/chwl/app/ui/gift/util/GlideCacheUtil.java create mode 100644 app/src/main/java/com/chwl/app/ui/gift/util/RecyclerViewUtil.java create mode 100644 app/src/main/java/com/chwl/app/ui/gift/widget/CustormAnim.java create mode 100644 app/src/main/java/com/chwl/app/ui/gift/widget/GiftAnimationUtil.java create mode 100644 app/src/main/java/com/chwl/app/ui/gift/widget/GiftControl.java create mode 100644 app/src/main/java/com/chwl/app/ui/gift/widget/GiftDataInfo.java create mode 100644 app/src/main/java/com/chwl/app/ui/gift/widget/GiftFrameLayout.java create mode 100644 app/src/main/java/com/chwl/app/ui/gift/widget/GlideCircleTransform.java create mode 100644 app/src/main/java/com/chwl/app/ui/gift/widget/ICustormAnim.java create mode 100644 app/src/main/java/com/chwl/app/ui/gift/widget/NumberTextView.java create mode 100644 app/src/main/java/com/chwl/app/ui/gift/widget/StrokeTextView.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/GreetPresenter.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/ImInitHelper.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/MessageListPanelEx.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/MsgViewHolderAitMe.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/RouterHandler.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/actions/ChatterBoxAction.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/actions/FamilyGameAction.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/actions/GiftAction.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/actions/GiftActionEvent.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/actions/LuckyMoneyAction.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/audio/ShakeHeartDialogFragment.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/avtivity/AddBlackListActivity.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/avtivity/AddBlackListPresenter.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/avtivity/BaseMessageActivity.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/avtivity/BlackListAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/avtivity/BlackListManageActivity.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/avtivity/BlackListManagePresenter.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/avtivity/IAddBlackListView.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/avtivity/IBlackListManageView.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/avtivity/NewBaseMessageActivity.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/avtivity/NimFriendModel.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/avtivity/NimP2PMessageActivity.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/avtivity/SwipeRecyclerViewItem.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/chat/GameTeamInviteViewHolder.kt create mode 100644 app/src/main/java/com/chwl/app/ui/im/chat/MVHChatterBoxStart.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderAudioParty.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderChatHint.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderConfirm.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderContent.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderCpRelationalConfirm.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderCpRelationalNotify.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderEventStartNotify.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderFairy.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderGift.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderHello.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderLevel.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderLottery.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderOnline.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderP2PContactRecharge.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderRedPacket.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderSkill.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderText.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/chat/SysMsgV2ViewHolder.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/chat/SysMsgViewHolder.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/fragment/MessageFragment.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/friend/ActFriendList.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/friend/FriendFragmentCpDelegate.kt create mode 100644 app/src/main/java/com/chwl/app/ui/im/friend/FriendListAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/friend/FriendListFragment.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/friend/FriendListFragmentKotlin.kt create mode 100644 app/src/main/java/com/chwl/app/ui/im/model/IMCustomModel.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/recent/RecentContactsFragment.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/recent/RecentListFragment.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/recent/TeamExt.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/recent/adapter/AttentionInRoomAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/recent/adapter/RecentContactAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/recent/holder/CommonRecentViewHolder.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/recent/holder/RecentViewHolder.java create mode 100644 app/src/main/java/com/chwl/app/ui/im/recent/holder/TeamRecentViewHolder.java create mode 100644 app/src/main/java/com/chwl/app/ui/indicator_impl/IndicatorHelper.java create mode 100644 app/src/main/java/com/chwl/app/ui/indicator_impl/JustColorIndicatorAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/indicator_impl/OnItemSelectListener.java create mode 100644 app/src/main/java/com/chwl/app/ui/invite/InviteImageHelper.kt create mode 100644 app/src/main/java/com/chwl/app/ui/invite/ShareInviteDialog.kt create mode 100644 app/src/main/java/com/chwl/app/ui/invite/ShareInviteInfo.kt create mode 100644 app/src/main/java/com/chwl/app/ui/keepalive/OnePiexlActivity.java create mode 100644 app/src/main/java/com/chwl/app/ui/language/LanguageActivity.kt create mode 100644 app/src/main/java/com/chwl/app/ui/language/LanguageAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/ui/language/LanguageItem.kt create mode 100644 app/src/main/java/com/chwl/app/ui/link/LinkActivity.kt create mode 100644 app/src/main/java/com/chwl/app/ui/link/LinkHelper.kt create mode 100644 app/src/main/java/com/chwl/app/ui/link/LinkIntent.kt create mode 100644 app/src/main/java/com/chwl/app/ui/list/BaseListAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/login/AccountValidator.java create mode 100644 app/src/main/java/com/chwl/app/ui/login/AddUserInfoActivity.java create mode 100644 app/src/main/java/com/chwl/app/ui/login/AreaCodeActivity.kt create mode 100644 app/src/main/java/com/chwl/app/ui/login/BindCodeActivity.java create mode 100644 app/src/main/java/com/chwl/app/ui/login/BindEmailActivity.kt create mode 100644 app/src/main/java/com/chwl/app/ui/login/BindPhoneActivity.kt create mode 100644 app/src/main/java/com/chwl/app/ui/login/BindSuccessDialog.java create mode 100644 app/src/main/java/com/chwl/app/ui/login/CodeDownDescTimer.java create mode 100644 app/src/main/java/com/chwl/app/ui/login/CodeDownTimer.java create mode 100644 app/src/main/java/com/chwl/app/ui/login/LoginCodeActivity.kt create mode 100644 app/src/main/java/com/chwl/app/ui/login/LoginPasswordActivity.java create mode 100644 app/src/main/java/com/chwl/app/ui/login/LoginPhoneActivity.kt create mode 100644 app/src/main/java/com/chwl/app/ui/login/LoginVerifyActivity.java create mode 100644 app/src/main/java/com/chwl/app/ui/login/ModifyInfoActivity.java create mode 100644 app/src/main/java/com/chwl/app/ui/login/PasswordValidator.java create mode 100644 app/src/main/java/com/chwl/app/ui/login/RegionListAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/ui/login/ShowBindEmailActivity.kt create mode 100644 app/src/main/java/com/chwl/app/ui/login/ShowBindPhoneActivity.kt create mode 100644 app/src/main/java/com/chwl/app/ui/login/dialog/CountrySelectDialog.kt create mode 100644 app/src/main/java/com/chwl/app/ui/login/fragment/AddUserInfoFragment.java create mode 100644 app/src/main/java/com/chwl/app/ui/login/helper/LogoutHelper.java create mode 100644 app/src/main/java/com/chwl/app/ui/login/ui/CodeEditText.java create mode 100644 app/src/main/java/com/chwl/app/ui/patriarch/PatriarchModeActivity.java create mode 100644 app/src/main/java/com/chwl/app/ui/patriarch/PatriarchPwdActivity.java create mode 100644 app/src/main/java/com/chwl/app/ui/patriarch/help/LimitEnterRoomHelper.java create mode 100644 app/src/main/java/com/chwl/app/ui/patriarch/help/PmDialogShowMrg.java create mode 100644 app/src/main/java/com/chwl/app/ui/pay/ChargeActivity.java create mode 100644 app/src/main/java/com/chwl/app/ui/pay/ChargeAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/praise/BezierEvaluator.java create mode 100644 app/src/main/java/com/chwl/app/ui/praise/HPUtils.java create mode 100644 app/src/main/java/com/chwl/app/ui/praise/HiPraise.java create mode 100644 app/src/main/java/com/chwl/app/ui/praise/HiPraiseAnimationView.java create mode 100644 app/src/main/java/com/chwl/app/ui/praise/HiPraiseWithCallback.java create mode 100644 app/src/main/java/com/chwl/app/ui/praise/OnDrawCallback.java create mode 100644 app/src/main/java/com/chwl/app/ui/praise/PraiseDrawable.java create mode 100644 app/src/main/java/com/chwl/app/ui/praise/PraiseWithCallbackDrawable.java create mode 100644 app/src/main/java/com/chwl/app/ui/praise/SimpleDrawTask.java create mode 100644 app/src/main/java/com/chwl/app/ui/praise/UpdateThread.java create mode 100644 app/src/main/java/com/chwl/app/ui/praise/base/IDrawTask.java create mode 100644 app/src/main/java/com/chwl/app/ui/praise/base/IDrawable.java create mode 100644 app/src/main/java/com/chwl/app/ui/praise/base/IPraise.java create mode 100644 app/src/main/java/com/chwl/app/ui/praise/base/IPraiseView.java create mode 100644 app/src/main/java/com/chwl/app/ui/radish/RadishRecordFragment.java create mode 100644 app/src/main/java/com/chwl/app/ui/relation/AttentionListActivity.java create mode 100644 app/src/main/java/com/chwl/app/ui/relation/FansListActivity.kt create mode 100644 app/src/main/java/com/chwl/app/ui/relation/FansListFragment.java create mode 100644 app/src/main/java/com/chwl/app/ui/relation/adapter/AttentionListAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/relation/adapter/FansViewAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/search/RoomHistoryAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/search/SearchActivity.java create mode 100644 app/src/main/java/com/chwl/app/ui/search/SearchAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/search/SearchDetailFragment.java create mode 100644 app/src/main/java/com/chwl/app/ui/search/SearchHallActivity.java create mode 100644 app/src/main/java/com/chwl/app/ui/search/SearchHistoryAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/search/SearchUserActivity.kt create mode 100644 app/src/main/java/com/chwl/app/ui/search/event/SearchEvent.java create mode 100644 app/src/main/java/com/chwl/app/ui/search/presenter/SearchPresenter.java create mode 100644 app/src/main/java/com/chwl/app/ui/search/view/ISearchView.java create mode 100644 app/src/main/java/com/chwl/app/ui/setting/GrantedPermissionsActivity.kt create mode 100644 app/src/main/java/com/chwl/app/ui/setting/LabActivity.java create mode 100644 app/src/main/java/com/chwl/app/ui/setting/ModifyPwdActivity.java create mode 100644 app/src/main/java/com/chwl/app/ui/setting/NoticeSettingActivity.java create mode 100644 app/src/main/java/com/chwl/app/ui/setting/PermissionGuideActivity.kt create mode 100644 app/src/main/java/com/chwl/app/ui/setting/PrivacySettingActivity.java create mode 100644 app/src/main/java/com/chwl/app/ui/setting/ResetPasswordActivity.kt create mode 100644 app/src/main/java/com/chwl/app/ui/setting/SettingActivity.kt create mode 100644 app/src/main/java/com/chwl/app/ui/setting/ShieldManageActivity.kt create mode 100644 app/src/main/java/com/chwl/app/ui/setting/VerifyEmailActivity.kt create mode 100644 app/src/main/java/com/chwl/app/ui/setting/VerifyPhoneActivity.kt create mode 100644 app/src/main/java/com/chwl/app/ui/setting/VipSetActivity.kt create mode 100644 app/src/main/java/com/chwl/app/ui/setting/adapter/RoomShieldAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/ui/setting/bean/PermissionEntity.kt create mode 100644 app/src/main/java/com/chwl/app/ui/setting/viewmodel/SetViewModel.kt create mode 100644 app/src/main/java/com/chwl/app/ui/user/activity/AboutActivity.java create mode 100644 app/src/main/java/com/chwl/app/ui/user/activity/ShowPhotoActivity.java create mode 100644 app/src/main/java/com/chwl/app/ui/user/activity/UserCpListActivity.kt create mode 100644 app/src/main/java/com/chwl/app/ui/user/activity/UserForbidActivity.kt create mode 100644 app/src/main/java/com/chwl/app/ui/user/activity/UserGiftActivity.kt create mode 100644 app/src/main/java/com/chwl/app/ui/user/activity/UserInfoActivity.java create mode 100644 app/src/main/java/com/chwl/app/ui/user/activity/UserInfoModifyActivity.kt create mode 100644 app/src/main/java/com/chwl/app/ui/user/activity/UserModifyPhotosActivity.kt create mode 100644 app/src/main/java/com/chwl/app/ui/user/adapter/ArrayWheelAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/user/adapter/CommonWrapIndicatorAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/user/adapter/ContactsIndicatorAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/user/adapter/DrawableIndicator.java create mode 100644 app/src/main/java/com/chwl/app/ui/user/adapter/GiftAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/user/adapter/HomeRecommendIndicatorAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/user/adapter/PhotoAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/user/adapter/SkillPicsAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/ui/user/adapter/UserCpListAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/ui/user/adapter/UserGiftAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoAlbumAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoCpListAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoDynamicAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoGameTeamAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoGiftAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoIndicatorAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoLabelAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoMedalAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoTopAlbumAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/ui/user/adapter/UserJoinWorldAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/user/adapter/UserLabelAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/ui/user/adapter/UserLabelDialogAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/ui/user/adapter/UserModifyLabelAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/ui/user/adapter/UserModifyPhotosAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/user/adapter/UserPhotoAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/user/adapter/UserTabBaseAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/user/decorationsend/DSAttentionFragment.java create mode 100644 app/src/main/java/com/chwl/app/ui/user/decorationsend/DSAttentionListAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/user/decorationsend/DSBaseListAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/user/decorationsend/DSFansListFragment.java create mode 100644 app/src/main/java/com/chwl/app/ui/user/decorationsend/DSFansViewAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/user/decorationsend/DSFriendListAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/user/decorationsend/DSFriendListFragment.java create mode 100644 app/src/main/java/com/chwl/app/ui/user/decorationsend/DecorationSendActivity.java create mode 100644 app/src/main/java/com/chwl/app/ui/user/decorationsend/UserInfoSkillDecoration.kt create mode 100644 app/src/main/java/com/chwl/app/ui/user/dialog/CpRelationChangeDialog.kt create mode 100644 app/src/main/java/com/chwl/app/ui/user/dialog/UserAreaDialog.kt create mode 100644 app/src/main/java/com/chwl/app/ui/user/event/LabelEvent.kt create mode 100644 app/src/main/java/com/chwl/app/ui/user/event/UserLabelEvent.kt create mode 100644 app/src/main/java/com/chwl/app/ui/user/fragment/LabelFragment.kt create mode 100644 app/src/main/java/com/chwl/app/ui/user/fragment/UserInfoDataFragment.kt create mode 100644 app/src/main/java/com/chwl/app/ui/user/fragment/UserInfoDynamicFragment.kt create mode 100644 app/src/main/java/com/chwl/app/ui/user/fragment/UserInfoGiftFragment.java create mode 100644 app/src/main/java/com/chwl/app/ui/user/viewmodel/UserInfoViewModel.kt create mode 100644 app/src/main/java/com/chwl/app/ui/utils/CpUtils.kt create mode 100644 app/src/main/java/com/chwl/app/ui/utils/DesignUtils.java create mode 100644 app/src/main/java/com/chwl/app/ui/utils/GameUtil.kt create mode 100644 app/src/main/java/com/chwl/app/ui/utils/GlideCacheUtil.java create mode 100644 app/src/main/java/com/chwl/app/ui/utils/ImageLoad.kt create mode 100644 app/src/main/java/com/chwl/app/ui/utils/ImageLoadUtils.java create mode 100644 app/src/main/java/com/chwl/app/ui/utils/ImageLoadUtilsV2.java create mode 100644 app/src/main/java/com/chwl/app/ui/utils/NinePatchBitmapFactory.java create mode 100644 app/src/main/java/com/chwl/app/ui/utils/RVDelegate.java create mode 100644 app/src/main/java/com/chwl/app/ui/utils/SoftPool.kt create mode 100644 app/src/main/java/com/chwl/app/ui/utils/SurfaceViewAnimation.java create mode 100644 app/src/main/java/com/chwl/app/ui/utils/VipUtil.kt create mode 100644 app/src/main/java/com/chwl/app/ui/utils/sys/InstallUtil.java create mode 100644 app/src/main/java/com/chwl/app/ui/utils/sys/PermissionUtil.kt create mode 100644 app/src/main/java/com/chwl/app/ui/wallet/WalletActivity.kt create mode 100644 app/src/main/java/com/chwl/app/ui/wallet/WalletCoinsFragment.kt create mode 100644 app/src/main/java/com/chwl/app/ui/wallet/WalletDiamondFragment.kt create mode 100644 app/src/main/java/com/chwl/app/ui/wallet/WalletIndicatorAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/wallet/WalletViewModel.kt create mode 100644 app/src/main/java/com/chwl/app/ui/wallet/payment/GPaymentClient.kt create mode 100644 app/src/main/java/com/chwl/app/ui/wallet/payment/IPaymentClient.kt create mode 100644 app/src/main/java/com/chwl/app/ui/wallet/payment/PaymentException.kt create mode 100644 app/src/main/java/com/chwl/app/ui/wallet/payment/PaymentIntent.kt create mode 100644 app/src/main/java/com/chwl/app/ui/wallet/payment/PaymentResult.kt create mode 100644 app/src/main/java/com/chwl/app/ui/webview/CommonWebViewActivity.java create mode 100644 app/src/main/java/com/chwl/app/ui/webview/CommonWebViewFragment.java create mode 100644 app/src/main/java/com/chwl/app/ui/webview/DatingRuleWebViewActivity.java create mode 100644 app/src/main/java/com/chwl/app/ui/webview/DialogWebViewActivity.java create mode 100644 app/src/main/java/com/chwl/app/ui/webview/DialogWebViewCenterActivity.java create mode 100644 app/src/main/java/com/chwl/app/ui/webview/FairyDialogWebViewActivity.java create mode 100644 app/src/main/java/com/chwl/app/ui/webview/JSInterface.java create mode 100644 app/src/main/java/com/chwl/app/ui/webview/ShareH5Event.java create mode 100644 app/src/main/java/com/chwl/app/ui/webview/SimpleJSInterface.java create mode 100644 app/src/main/java/com/chwl/app/ui/webview/SimpleWebViewActivity.java create mode 100644 app/src/main/java/com/chwl/app/ui/webview/TarotPayWebViewActivity.java create mode 100644 app/src/main/java/com/chwl/app/ui/webview/baishun/BaiShunGameJSBridge.kt create mode 100644 app/src/main/java/com/chwl/app/ui/webview/baishun/BaiShunGameWebActivity.kt create mode 100644 app/src/main/java/com/chwl/app/ui/webview/baishun/BaiShunGameWebFragment.kt create mode 100644 app/src/main/java/com/chwl/app/ui/webview/baishun/IBaiShunGameListener.kt create mode 100644 app/src/main/java/com/chwl/app/ui/webview/baishun/IBaiShunGameView.kt create mode 100644 app/src/main/java/com/chwl/app/ui/webview/baishun/JoyPlayGameWebFragment.kt create mode 100644 app/src/main/java/com/chwl/app/ui/webview/baishun/JoyPlayJSBridge.kt create mode 100644 app/src/main/java/com/chwl/app/ui/webview/baishun/LeaderccGameWebFragment.kt create mode 100644 app/src/main/java/com/chwl/app/ui/webview/baishun/LeaderccJSBridge.kt create mode 100644 app/src/main/java/com/chwl/app/ui/webview/event/CloseDialogWebViewEvent.java create mode 100644 app/src/main/java/com/chwl/app/ui/webview/event/H5NotifyClientEvent.java create mode 100644 app/src/main/java/com/chwl/app/ui/webview/event/ShowNavEvent.java create mode 100644 app/src/main/java/com/chwl/app/ui/webview/event/TaroPayResultEvent.java create mode 100644 app/src/main/java/com/chwl/app/ui/webview/room_banner/RoomBannerTabAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/ui/webview/room_banner/RoomBannerWebDialogActivity.kt create mode 100644 app/src/main/java/com/chwl/app/ui/webview/room_banner/RoomWebDialogActivity.kt create mode 100644 app/src/main/java/com/chwl/app/ui/widget/Anticlockwise.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/AppBarLayoutBehavior.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/BonsellaJoinAttackButtonView.kt create mode 100644 app/src/main/java/com/chwl/app/ui/widget/BonsellaJoinAttackLayout.kt create mode 100644 app/src/main/java/com/chwl/app/ui/widget/ButtonItem.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/CharAlignTextView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/ColorfulRingProgressView.kt create mode 100644 app/src/main/java/com/chwl/app/ui/widget/CustomExpandableText.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/DatingSelectDialog.kt create mode 100644 app/src/main/java/com/chwl/app/ui/widget/DefaultToolBar.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/DividerItemDecoration.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/DividerUtil.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/EdgeTransparentView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/FixedTouchViewPager.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/FlickerAvatarView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/GiftAvatarAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/GiftDialog.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/GiftRecyclerView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/GridViewWithoutScroll.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/InterceptTouchLayout.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/LeftNotiDialog.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/LevelHeadView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/LevelUpDialog.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/LinearLayoutManagerWrapper.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/ListViewWithoutScroll.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/LivingIconView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/LoadingAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/LoadingDialog.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/MagicAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/MagicRecyclerView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/MainRedPointTab.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/MainTab.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/MainTabLayout.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/MarqueeLayout.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/MarqueeTextView.kt create mode 100644 app/src/main/java/com/chwl/app/ui/widget/MicSelectDialog.kt create mode 100644 app/src/main/java/com/chwl/app/ui/widget/MultipleGraduallyTextView.kt create mode 100644 app/src/main/java/com/chwl/app/ui/widget/MyItemAnimator.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/NobleAvatarView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/NobleOpenNoticeView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/NumView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/ObservableScrollView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/OnPageSelectedListener.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/ParentClickHorizontalScrollView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/PinEntryEditText.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/RecallDialog.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/RectLayout.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/RecyclerRefreshLayout.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/RecyclerViewNoBugLinearLayoutManager.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/RecyclerViewNoViewpagerScroll.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/RedPointView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/ScollLinearLayoutManager.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/ShareRedBagDialog.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/SideBarView.kt create mode 100644 app/src/main/java/com/chwl/app/ui/widget/SimpleAnimListener.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/SquareImageView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/SquareLayout.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/SuperEditText.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/TextSpannableBuilder.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/TextWatcherSimple.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/TopRoundLinearLayout.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/UserInfoDialog.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/UserInfoView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/UserInfoWrapContentPager.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/UserMagicIndicator.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/WrapContentViewPager.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/XRecyclerView/ScaleTransitionPagerTitleView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/adapter/GiftDialogNumberAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/ui/widget/bubble/LeBubbleTextView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/bubble/LeBubbleTextViewHelper.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/bubble/LeBubbleTextViews.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/bubble/LeBubbleTitleTextView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/bubble/LeBubbleView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/bubble/LeRoundRectDrawable2.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/bubble/LeStateColorDrawable.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/bubble/TintedBitmapDrawable.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/dialog/AllPlayEffectDialog.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/dialog/AllServiceGiftGoRoomTipsDialog.kt create mode 100644 app/src/main/java/com/chwl/app/ui/widget/dialog/AllServiceGiftLevelDialog.kt create mode 100644 app/src/main/java/com/chwl/app/ui/widget/dialog/AllServiceVipLevelUPDialog.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/dialog/BaseDialog.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/dialog/CommonDialog.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/dialog/CommonLoadingDialog.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/dialog/CommonMessageDialog.kt create mode 100644 app/src/main/java/com/chwl/app/ui/widget/dialog/CommonTipDialog.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/dialog/ExchangeDiamondTipDialog.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/dialog/GiftManualQuantityDialog.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/dialog/GiveDiamondTipDialog.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/dialog/MonsterDialog.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/dialog/OpenNobleDialog.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/dialog/OpenNobleGlobalNoticeDialog.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/drawgift/DrawGiftHelper.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/drawgift/DrawGiftModel.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/drawgift/DrawGiftPlayHelper.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/drawgift/DrawGiftPlayView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/drawgift/DrawGiftView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/dynamicface/DynamicFaceAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/dynamicface/DynamicFaceAdapterNew.kt create mode 100644 app/src/main/java/com/chwl/app/ui/widget/dynamicface/DynamicFaceBuilder.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/dynamicface/DynamicFaceDialog.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/dynamicface/FaceItem.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/dynamicface/FaceResultItem.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/higuide/GuideUtils.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/higuide/GuideView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/higuide/HiGuide.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/higuide/HiLightInfo.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/higuide/LightConfig.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/higuide/OverLayer.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/higuide/Overlay.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/higuide/TuTuGuideHelper.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/higuide/TuTuGuideView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/interfacex/MicListItem.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/magicindicator/FragmentContainerHelper.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/magicindicator/GiftIndicator.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/magicindicator/MagicIndicator.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/magicindicator/NavigatorHelper.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/magicindicator/ScrollState.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/magicindicator/ViewPagerHelper.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/magicindicator/abs/IPagerNavigator.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/ArgbEvaluatorHolder.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/UIUtil.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/circlenavigator/CircleNavigator.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/CommonNavigator.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/abs/CommonNavigatorAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/abs/IMeasurablePagerTitleView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/abs/IPagerIndicator.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/abs/IPagerTitleView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/indicators/BezierPagerIndicator.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/indicators/GradientLinePagerIndicator.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/indicators/GradientLineRoundPagerIndicator.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/indicators/LinePagerIndicator.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/indicators/TestPagerIndicator.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/indicators/TriangularPagerIndicator.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/indicators/WrapPagerIndicator.kt create mode 100644 app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/model/PositionData.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/titles/ClipPagerTitleView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/titles/ColorTransitionPagerTitleView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/titles/CommonPagerTitleView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/titles/DummyPagerTitleView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/titles/SimplePagerTitleView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/titles/badge/BadgeAnchor.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/titles/badge/BadgePagerTitleView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/titles/badge/BadgeRule.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/magicindicator/ext/FontChangePagerTitleView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/magicindicator/ext/MainCommonNavigatorAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/marqueeview/AvRoomNobleWelcomeView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/marqueeview/BetterMarqueeView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/marqueeview/MarqueeView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/password/PassWordFragment.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/password/PasswordEvent.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/password/PasswordKeyboardView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/password/PasswordView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/ColorDecoration.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/DatingItemDecoration.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/GridSpacingItemDecoration.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/GridSpacingItemNewDecoration.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/GridVItemDecoration.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/HorizontalDecoration.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/SpacingDecoration.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/TagItemDecoration.kt create mode 100644 app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/VerticalDecoration.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/recyclerview/layoutmanager/BoosRoomLayoutManager.kt create mode 100644 app/src/main/java/com/chwl/app/ui/widget/recyclerview/layoutmanager/FullyGridLayoutManager.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/recyclerview/layoutmanager/FullyLinearLayoutManager.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/rollviewpager/HintView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/rollviewpager/OnRollViewClickListener.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/rollviewpager/RollPagerView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/rollviewpager/Util.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/rollviewpager/adapter/DynamicPagerAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/rollviewpager/adapter/LoopPagerAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/rollviewpager/adapter/StaticPagerAdapter.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/rollviewpager/adapter/StaticPagerAdapterWrapper.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/rollviewpager/hintview/ColorPointHintView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/rollviewpager/hintview/IconHintView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/rollviewpager/hintview/ShapeHintView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/rollviewpager/hintview/TextHintView.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/viewpager/NoScrollViewPager.java create mode 100644 app/src/main/java/com/chwl/app/ui/widget/viewpager/ScrollViewPager.java create mode 100644 app/src/main/java/com/chwl/app/utils/ActWhiteListMrg.java create mode 100644 app/src/main/java/com/chwl/app/utils/AnimLoadUtil.kt create mode 100644 app/src/main/java/com/chwl/app/utils/AppBarStateChangeListener.java create mode 100644 app/src/main/java/com/chwl/app/utils/AvatarHelper.kt create mode 100644 app/src/main/java/com/chwl/app/utils/BlurTransformation.java create mode 100644 app/src/main/java/com/chwl/app/utils/CertificateHelper.java create mode 100644 app/src/main/java/com/chwl/app/utils/CleanLeakUtils.java create mode 100644 app/src/main/java/com/chwl/app/utils/ClipboardUtils.java create mode 100644 app/src/main/java/com/chwl/app/utils/CommonJumpHelper.java create mode 100644 app/src/main/java/com/chwl/app/utils/DoubleClickCheckListener.java create mode 100644 app/src/main/java/com/chwl/app/utils/FastBlur.java create mode 100644 app/src/main/java/com/chwl/app/utils/FloatManager.java create mode 100644 app/src/main/java/com/chwl/app/utils/FontTextView.java create mode 100644 app/src/main/java/com/chwl/app/utils/GiftAnimUtil.java create mode 100644 app/src/main/java/com/chwl/app/utils/HomeUIManager.kt create mode 100644 app/src/main/java/com/chwl/app/utils/KeyBoardUtils.java create mode 100644 app/src/main/java/com/chwl/app/utils/LimitInputFliter.java create mode 100644 app/src/main/java/com/chwl/app/utils/LoginSuccessManager.kt create mode 100644 app/src/main/java/com/chwl/app/utils/MsgBuilder.kt create mode 100644 app/src/main/java/com/chwl/app/utils/NamePlateHelper.kt create mode 100644 app/src/main/java/com/chwl/app/utils/NotificationsUtils.java create mode 100644 app/src/main/java/com/chwl/app/utils/NumberFormatUtil.java create mode 100644 app/src/main/java/com/chwl/app/utils/NumberUtils.kt create mode 100644 app/src/main/java/com/chwl/app/utils/OSUtils.java create mode 100644 app/src/main/java/com/chwl/app/utils/ObjectTypeHelper.java create mode 100644 app/src/main/java/com/chwl/app/utils/PermissionUtil.kt create mode 100644 app/src/main/java/com/chwl/app/utils/PushMessageHandler.java create mode 100644 app/src/main/java/com/chwl/app/utils/RSBlur.java create mode 100644 app/src/main/java/com/chwl/app/utils/RegexUtil.java create mode 100644 app/src/main/java/com/chwl/app/utils/ResourceManager.kt create mode 100644 app/src/main/java/com/chwl/app/utils/RoomBoomManager.kt create mode 100644 app/src/main/java/com/chwl/app/utils/RoomHelperManager.kt create mode 100644 app/src/main/java/com/chwl/app/utils/RoomNotifyDialogManager.kt create mode 100644 app/src/main/java/com/chwl/app/utils/ShareManager.kt create mode 100644 app/src/main/java/com/chwl/app/utils/SpannableBuilder.java create mode 100644 app/src/main/java/com/chwl/app/utils/ThreadUtil.java create mode 100644 app/src/main/java/com/chwl/app/utils/TimeUiUtils.java create mode 100644 app/src/main/java/com/chwl/app/utils/UserUtils.java create mode 100644 app/src/main/java/com/chwl/app/utils/VapAnimListener.java create mode 100644 app/src/main/java/com/chwl/app/utils/VpSwipeRefreshLayout.java create mode 100644 app/src/main/java/com/chwl/app/utils/WeakPool.kt create mode 100644 app/src/main/java/com/chwl/app/utils/WebViewUtils.java create mode 100644 app/src/main/java/com/chwl/app/view/AutoMirroredAnimView.kt create mode 100644 app/src/main/java/com/chwl/app/view/AutoMirroredImageView.kt create mode 100644 app/src/main/java/com/chwl/app/view/AutoMirroredShapeableImageView.kt create mode 100644 app/src/main/java/com/chwl/app/view/EffectView.kt create mode 100644 app/src/main/java/com/chwl/app/view/GenderAgeTextView.kt create mode 100644 app/src/main/java/com/chwl/app/view/MyCircleIndicator.java create mode 100644 app/src/main/java/com/chwl/app/view/NestedScrollableHost.kt create mode 100644 app/src/main/java/com/chwl/app/view/ShadowFrameLayout.java create mode 100644 app/src/main/java/com/chwl/app/view/WrapHeightViewPager.kt create mode 100644 app/src/main/java/com/chwl/app/view/layoutmanager/AutoPlayRecyclerView.java create mode 100644 app/src/main/java/com/chwl/app/view/layoutmanager/AutoPlaySnapHelper.java create mode 100644 app/src/main/java/com/chwl/app/view/layoutmanager/CarouselLayoutManager.java create mode 100644 app/src/main/java/com/chwl/app/view/layoutmanager/CenterSnapHelper.java create mode 100644 app/src/main/java/com/chwl/app/view/layoutmanager/CircleLayoutManager.java create mode 100644 app/src/main/java/com/chwl/app/view/layoutmanager/CircleScaleLayoutManager.java create mode 100644 app/src/main/java/com/chwl/app/view/layoutmanager/GalleryLayoutManager.java create mode 100644 app/src/main/java/com/chwl/app/view/layoutmanager/OrientationHelper.java create mode 100644 app/src/main/java/com/chwl/app/view/layoutmanager/PageSnapHelper.java create mode 100644 app/src/main/java/com/chwl/app/view/layoutmanager/RotateLayoutManager.java create mode 100644 app/src/main/java/com/chwl/app/view/layoutmanager/ScaleLayoutManager.java create mode 100644 app/src/main/java/com/chwl/app/view/layoutmanager/ScrollHelper.java create mode 100644 app/src/main/java/com/chwl/app/view/layoutmanager/ViewPagerLayoutManager.java create mode 100644 app/src/main/java/com/chwl/app/vip/VipBroadcastView.kt create mode 100644 app/src/main/java/com/chwl/app/vip/VipCenterActivity.kt create mode 100644 app/src/main/java/com/chwl/app/vip/VipSettingActivity.kt create mode 100644 app/src/main/java/com/chwl/app/vip/VipViewModel.kt create mode 100644 app/src/main/java/com/chwl/app/vip/adapter/PayAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/vip/adapter/VipAuthAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/vip/adapter/VipCenterBannerAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/vip/adapter/VipCenterIdentificationsAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/vip/adapter/VipMagicIndicatorAdapter.java create mode 100644 app/src/main/java/com/chwl/app/vip/adapter/VipRebateAdapter.kt create mode 100644 app/src/main/java/com/chwl/app/vip/bean/PayInfo.kt create mode 100644 app/src/main/java/com/chwl/app/vip/dialog/PaymentDialog.kt create mode 100644 app/src/main/java/com/chwl/app/vip/dialog/SelectPayTypeDialog.kt create mode 100644 app/src/main/java/com/chwl/app/vip/dialog/VipAuthDetailsDialog.kt create mode 100644 app/src/main/java/com/chwl/app/vip/dialog/VipBroadcastDialog.kt create mode 100644 app/src/main/java/com/chwl/app/vip/dialog/VipRemainTimeDialog.kt create mode 100644 app/src/main/java/com/chwl/app/vip/dialog/VipUpgradeDialog.kt create mode 100644 app/src/main/java/com/chwl/app/vip/util/VipHelper.java create mode 100644 app/src/main/java/com/chwl/app/vip/view/VipBroadcastView.kt create mode 100644 app/src/main/java/com/chwl/app/vip/view/VipTabView.kt diff --git a/app/src/main/java/com/chwl/app/AgentActivity.java b/app/src/main/java/com/chwl/app/AgentActivity.java new file mode 100644 index 0000000..c3294a6 --- /dev/null +++ b/app/src/main/java/com/chwl/app/AgentActivity.java @@ -0,0 +1,110 @@ +package com.chwl.app; + +import android.app.ActivityManager; +import android.content.ComponentName; +import android.content.Intent; +import android.os.Build; + +import androidx.appcompat.app.AppCompatActivity; + +import java.util.List; + +public class AgentActivity extends AppCompatActivity { +// implements SceneRestorable { + + + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + setIntent(intent); +// MobLink.updateNewIntent(getIntent(), this); + } + +// @Override +// public void onReturnSceneData(Scene scene) { +// +// try { +// HashMap hashMap = scene.getParams(); +// +// LogUtil.print("linkedme", hashMap); +// //根据key获取传入的参数的值,该key关键字View可为任意值,由集成方规定,请与web端商议,一致即可 +// LinkedInfo linkedInfo = new LinkedInfo(); +// String roomuid = (String) hashMap.get("roomuid"); +// String uid = (String) hashMap.get("uid"); +// String type = String.valueOf(hashMap.get("type")); +// String familyId = (String) hashMap.get("familyId"); +// String url = (String) hashMap.get("url"); +// String worldId = (String) hashMap.get("worldId"); +// String dynamicId = (String) hashMap.get("dynamicId"); +// String inviteCode = (String) hashMap.get("inviteCode"); +// if (roomuid != null) { +// linkedInfo.setRoomUid(roomuid); +// } +// if (TextUtils.isEmptyText(roomuid) && uid != null) { +// linkedInfo.setRoomUid(uid); +// } +// if (uid != null) { +// linkedInfo.setUid(uid); +// } +// linkedInfo.setType(type); +// if (familyId != null) { +// linkedInfo.setFamilyId(familyId); +// } +// if (url != null) { +// linkedInfo.setUrl(url); +// } +// if (worldId != null) { +// linkedInfo.setWorldId(worldId); +// } +// if (dynamicId != null) { +// linkedInfo.setDynamicId(dynamicId); +// } +// +// linkedInfo.setInviteCode(inviteCode); +// +// LinkedModel.get().setLinkedInfo(linkedInfo); +// +// } catch (Exception e) { +// } +// +// +// if (isExistMainActivity(MainActivity.class) && UserModel.get().getCacheLoginUserInfo() != null) {//应用已开启&用户信息以获取 +// MainActivity.handleLinkedJump(this); +// } else {//应用未开启 +// SplashActivity.start(this); +// } +// finish(); +// } + + public boolean isExistMainActivity(Class activity) { + try { + Intent intent = new Intent(this, activity); + ComponentName cmpName = intent.resolveActivity(getPackageManager()); + boolean flag = false; + if (cmpName != null) { + ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + List taskInfoList = am.getAppTasks(); + for (ActivityManager.AppTask taskInfo : taskInfoList) { + if (taskInfo.getTaskInfo().baseActivity.equals(cmpName)) { + flag = true; + break; + } + } + } else { + List taskInfoList = am.getRunningTasks(10); + for (ActivityManager.RunningTaskInfo taskInfo : taskInfoList) { + if (taskInfo.baseActivity.equals(cmpName)) { + flag = true; + break; + } + } + } + + } + return flag; + } catch (Throwable e) { + return false; + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/DemoActivity.kt b/app/src/main/java/com/chwl/app/DemoActivity.kt new file mode 100644 index 0000000..95b9b17 --- /dev/null +++ b/app/src/main/java/com/chwl/app/DemoActivity.kt @@ -0,0 +1,55 @@ +package com.chwl.app + +import android.content.Context +import android.content.Intent +import android.view.ViewGroup +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.bindadapter.BaseBindingAdapter +import com.chwl.app.bindadapter.BaseBindingViewHolder +import com.chwl.app.databinding.ActivityDemoBinding +import com.chwl.app.databinding.ListItemMicroBinding +import com.chwl.core.widget.layoutmanager.pagergridlayoutmanager.PagerGridLayoutManager.LayoutParams +import com.chwl.library.common.util.ClickUtils.click +import com.chwl.library.common.util.setViewWH +import com.chwl.library.common.util.setVis + + +class DemoActivity : BaseViewBindingActivity() { + + companion object{ + @JvmStatic + fun start(context: Context) { + val starter = Intent(context, DemoActivity::class.java) + context.startActivity(starter) + } + } + + + override fun init() { + + var isOpen = false + binding.b1.click { + binding.btnLayout.setViewWH(height = if (!isOpen) ViewGroup.LayoutParams.WRAP_CONTENT else 1 , isDP = false) + isOpen = !isOpen + } + } + + + class DemoAdapter : BaseBindingAdapter() { + + + + override fun convert(helper: BaseBindingViewHolder, item: Int) { + val bindingAdapterPosition = helper.bindingAdapterPosition + + helper.binding.root.setViewWH(width = LayoutParams.MATCH_PARENT, height = LayoutParams.MATCH_PARENT , false) + + helper.binding.avatar.setVis(true) + helper.binding.avatar.setImageResource(R.drawable.user_info_ic_id) + helper.binding.llCharmClick.setVis(true) + helper.binding.tvCharmValue.setVis(true) + helper.binding.tvCharmValue.text = "${ bindingAdapterPosition + 1}" + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/GuideAdapter.java b/app/src/main/java/com/chwl/app/GuideAdapter.java new file mode 100644 index 0000000..462d095 --- /dev/null +++ b/app/src/main/java/com/chwl/app/GuideAdapter.java @@ -0,0 +1,68 @@ +package com.chwl.app; + +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; + +import androidx.viewpager.widget.PagerAdapter; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by Administrator on 2017/7/12 0012. + */ + +public class GuideAdapter extends PagerAdapter { + private List mData=new ArrayList(); + public GuideAdapter(Context context){ + initData(context); + } + + //取得适配器装配的数据 + public List getData(){ + return mData; + } + //添加视图项 + public void addItem(ImageView imageView){ + mData.add(imageView); + } + + //初始化视图项的数据 + private void initData(Context context) { + ImageView imageView=new ImageView(context); +// imageView.setImageResource(resId);//设置ImageView的前景图片 +// imageView.setBackgroundResource(R.drawable.guide_one);//设置背景 + mData.add(imageView); + imageView=new ImageView(context); +// imageView.setBackgroundResource(R.drawable.guide_two);//设置背景 + mData.add(imageView); + imageView=new ImageView(context); +// imageView.setBackgroundResource(R.drawable.guide_three);//设置背景 + mData.add(imageView); + + } + //取得视图项的数量 + @Override + public int getCount() { + return mData.size(); + } + @Override + public boolean isViewFromObject(View arg0, Object arg1) { + return arg0==arg1; + } + //销毁视图项 + @Override + public void destroyItem(ViewGroup container, int position, Object object) { + //从父控件中移除子控件 + container.removeView((View)object); + } + //初始化视图项 + @Override + public Object instantiateItem(ViewGroup container, int position) { + //容器(ViewPager--它是ViewGroup的子类) + container.addView(mData.get(position)); + return mData.get(position); + } +} diff --git a/app/src/main/java/com/chwl/app/MainActivity.java b/app/src/main/java/com/chwl/app/MainActivity.java new file mode 100644 index 0000000..4548511 --- /dev/null +++ b/app/src/main/java/com/chwl/app/MainActivity.java @@ -0,0 +1,989 @@ +package com.chwl.app; + +import static com.chwl.core.channel_page.model.ChannelPageModel.KEY_FLAG_VALID_CHANNEL_PAGE; + +import android.animation.ObjectAnimator; +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.graphics.Color; +import android.os.Bundle; +import android.os.Handler; +import android.text.TextUtils; +import android.util.SparseArray; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.View; +import android.view.animation.LinearInterpolator; + +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentTransaction; +import androidx.lifecycle.ViewModelProvider; + +import com.chwl.app.application.App; +import com.chwl.app.application.IReportConstants; +import com.chwl.app.application.ReportManager; +import com.chwl.app.avroom.activity.AVRoomActivity; +import com.chwl.app.base.BaseActivity; +import com.chwl.app.base.BaseMvpActivity; +import com.chwl.app.base.GlobalViewModelOwner; +import com.chwl.app.common.widget.CircleImageView; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.app.community.square.SquareFragment; +import com.chwl.app.game.core.GameStateAbility; +import com.chwl.app.game.data.GameModel2; +import com.chwl.app.game.ui.game.GameActivity; +import com.chwl.app.game.ui.game.GameIntent; +import com.chwl.app.game.ui.home.GameHomeFragment; +import com.chwl.app.home.HomeViewModel; +import com.chwl.app.home.dialog.NewUserHelloDialog; +import com.chwl.app.home.dialog.ProtocolUpdateDialog; +import com.chwl.app.home.fragment.ContactsListFragment; +import com.chwl.app.home.fragment.HomeFragment; +import com.chwl.app.home.fragment.MeFragment; +import com.chwl.app.home.presenter.MainPresenter; +import com.chwl.app.home.view.IMainView; +import com.chwl.app.home.widget.AnchorCardView; +import com.chwl.app.module.Extras; +import com.chwl.app.module_hall.secretcode.PwdCodeMgr; +import com.chwl.app.service.DaemonService; +import com.chwl.app.support.PreloadResourceViewModel; +import com.chwl.app.ui.im.ImInitHelper; +import com.chwl.app.ui.im.avtivity.NimP2PMessageActivity; +import com.chwl.app.ui.login.BindPhoneActivity; +import com.chwl.app.ui.login.LoginPasswordActivity; +import com.chwl.app.ui.login.fragment.AddUserInfoFragment; +import com.chwl.app.ui.patriarch.help.LimitEnterRoomHelper; +import com.chwl.app.ui.patriarch.help.PmDialogShowMrg; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.app.ui.utils.ImageLoadUtilsV2; +import com.chwl.app.ui.webview.CommonWebViewActivity; +import com.chwl.app.ui.widget.LivingIconView; +import com.chwl.app.ui.widget.MainTabLayout; +import com.chwl.app.utils.CleanLeakUtils; +import com.chwl.app.utils.HomeUIManager; +import com.chwl.app.utils.LoginSuccessManager; +import com.chwl.app.utils.PushMessageHandler; +import com.chwl.app.utils.ResourceManager; +import com.chwl.app.utils.ShareManager; +import com.chwl.core.Constants; +import com.chwl.core.DemoCache; +import com.chwl.core.UriProvider; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.auth.event.KickOutEvent; +import com.chwl.core.auth.event.LoginEvent; +import com.chwl.core.auth.event.LogoutEvent; +import com.chwl.core.channel_page.model.ChannelPageModel; +import com.chwl.core.community.event.SquareTaskEvent; +import com.chwl.core.community.event.UnReadCountEvent; +import com.chwl.core.home.bean.BannerInfo; +import com.chwl.core.home.bean.MainTabInfo; +import com.chwl.core.home.bean.MainTabType; +import com.chwl.core.home.event.VisitorUnreadCountEvent; +import com.chwl.core.home.model.GameHomeModel; +import com.chwl.core.home.model.HomeModel; +import com.chwl.core.initial.InitialModel; +import com.chwl.core.linked.LinkedModel; +import com.chwl.core.linked.bean.LinkedInfo; +import com.chwl.core.manager.AudioEngineManager; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.manager.IMBroadcastManager; +import com.chwl.core.manager.IMMessageManager; +import com.chwl.core.manager.RoomEvent; +import com.chwl.core.patriarch.event.CloseMinRoomEvent; +import com.chwl.core.patriarch.event.ImPushMsgPmLimitTimeEvent; +import com.chwl.core.patriarch.event.PmDismissAllLimitDialogEvent; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.core.settings.SettingsModel; +import com.chwl.core.user.UserModel; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.core.user.event.LoadLoginUserInfoEvent; +import com.chwl.core.user.event.LoginUserInfoUpdateEvent; +import com.chwl.core.user.event.NeedBindPhoneEvent; +import com.chwl.core.user.event.NeedCompleteInfoEvent; +import com.chwl.core.utils.SharedPreferenceUtils; +import com.chwl.core.utils.StringFormatUtils; +import com.chwl.core.utils.WLog; +import com.chwl.core.utils.myutil.MyUtil; +import com.chwl.library.base.factory.CreatePresenter; +import com.chwl.library.common.util.OtherExtKt; +import com.chwl.library.threadmgr.ThreadPoolManager; +import com.chwl.library.utils.JavaUtil; +import com.chwl.library.utils.ResUtil; +import com.netease.nim.uikit.StatusBarUtil; +import com.netease.nim.uikit.common.util.log.LogUtil; +import com.netease.nim.uikit.common.util.string.StringUtil; +import com.netease.nimlib.sdk.NIMClient; +import com.netease.nimlib.sdk.chatroom.model.ChatRoomKickOutEvent; +import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum; +import com.netease.nimlib.sdk.msg.model.RecentContact; +import com.netease.nimlib.sdk.team.TeamService; +import com.netease.nimlib.sdk.team.constant.TeamMessageNotifyTypeEnum; +import com.netease.nimlib.sdk.team.model.Team; +import com.orhanobut.logger.Logger; +import com.trello.rxlifecycle3.android.ActivityEvent; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; +import org.jetbrains.annotations.NotNull; + +import java.lang.ref.WeakReference; +import java.util.HashMap; +import java.util.List; + +/** + * @author Administrator + */ +@CreatePresenter(MainPresenter.class) +public class MainActivity extends BaseMvpActivity + implements MainTabLayout.OnTabClickListener, IMainView, View.OnClickListener { + + public static final String MSG_TAB = "msgTab"; + private static final String TAG = "MainActivity"; + private static final String EXTRA_APP_QUIT = "APP_QUIT"; + private final SparseArray fragmentArray = new SparseArray<>(); + private View avatarLayout; + private CircleImageView avatarImage; + private LivingIconView userLivingView; + private MainTabLayout mMainTabLayout; + private AnchorCardView anchorCardView; + private View viewClose; + private int mCurrentTabType = MainTabType.TAB_TYPE_HOME; + /** + * 房间最小化动画,换成属性动画,原先的补间动画影响了activity的生命周期 + */ + private ObjectAnimator roomMinAnim; + /** + * 管理限制进房 + */ + private LimitEnterRoomHelper limitEnterRoomHelper; + private HomeViewModel homeViewModel; + private boolean mResumed = false; + @Nullable + private Fragment tempFragment = null; + private DialogManager resumeGameDialogManager; + + private PreloadResourceViewModel mPreLoadViewModel; + + @Nullable + private Runnable touchRunnable; + + { + fragmentArray.put(MainTabType.TAB_TYPE_HOME, new HomeFragment()); + fragmentArray.put(MainTabType.TAB_TYPE_GAME, new GameHomeFragment()); + fragmentArray.put(MainTabType.TAB_TYPE_SQUARE, new SquareFragment()); + fragmentArray.put(MainTabType.TAB_TYPE_MSG, new ContactsListFragment()); + fragmentArray.put(MainTabType.TAB_TYPE_ME, new MeFragment()); + } + + public static void start(Context context) { + start(context, null); + } + + public static void start(Context context, Intent extras) { + Intent intent = new Intent(); + intent.setClass(context, MainActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); + if (extras != null) { + intent.putExtras(extras); + } + context.startActivity(intent); + } + + /** + * @return true 如果处理了跳转 + */ + public static boolean handleLinkedJump(BaseActivity context) { + LinkedInfo linkedInfo = LinkedModel.get().getLinkedInfo(); + LinkedModel.get().setLinkedInfo(null); + + if (linkedInfo != null && linkedInfo.getType() != null && !linkedInfo.getType().equals("null")) { + LogUtil.print(ResUtil.getString(R.string.yizhuan_erban_mainactivity_01)); + // 跳转 + if (!StringUtil.isEmpty(linkedInfo.getRoomUid()) && linkedInfo.getType().equals("2")) { + AVRoomActivity.start(context, Long.parseLong(linkedInfo.getRoomUid())); + } else if (!TextUtils.isEmpty(linkedInfo.getUrl()) && linkedInfo.getType().equals("3")) { + CommonWebViewActivity.start(context, UriProvider.getLinkUrl(linkedInfo.getUrl())); + } else if (linkedInfo.getType().equals("7") && !TextUtils.isEmpty(linkedInfo.getUid())) { + NimP2PMessageActivity.start(context, linkedInfo.getUid()); + } else { + return false; + } + } else { + //执行新分享逻辑 + ShareManager.INSTANCE.shareRoomGet(context,s -> { + + return null; + }); + return false; + } + return true; + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putInt(Constants.KEY_MAIN_POSITION, mCurrentTabType); + } + + @Override + protected void onRestoreInstanceState(@NotNull Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + mCurrentTabType = savedInstanceState.getInt(Constants.KEY_MAIN_POSITION); + } + + @SuppressLint("CheckResult") + @Override + protected void onCreate(Bundle savedInstanceState) { + OtherExtKt.doLog("MainActivity onCreate()"); + super.onCreate(savedInstanceState); + ViewModelProvider viewModelProvider = new ViewModelProvider(this); + homeViewModel = viewModelProvider.get(HomeViewModel.class); + + NimMiddleActivity.firstEnter = false; + if (savedInstanceState != null) { + mCurrentTabType = savedInstanceState.getInt(Constants.KEY_MAIN_POSITION); + } + setContentView(R.layout.activity_main); + //自动登录 + AuthModel.get().autoLogin() + .doOnError(throwable -> onNeedLogin()) + .subscribe(); + initView(); + + List homeTabIcons = HomeUIManager.INSTANCE.getHomeTabIcons(); + if (homeTabIcons != null && !homeTabIcons.isEmpty()) { + mMainTabLayout.setMainTabInfoList(homeTabIcons); + } else { + List mainTabInfo = InitialModel.get().getMainTabInfosLiveData().getValue(); + if (mainTabInfo != null) { + mMainTabLayout.setMainTabInfoList(mainTabInfo); + } + } + + initMaterialView(); + onParseIntent(); + updateDatas(); + updateRoomState(); + ImInitHelper.get().init(); + EventBus.getDefault().register(this); + otherModelInit(); + + homeViewModel.getAnchorInfoLiveData().observe(this, anchorInfo -> { + if (anchorInfo != null) { + anchorCardView.setAnchorInfo(anchorInfo); + DemoCache.saveAnchorCardView(2); + } + }); + checkResumeGame(); + + WLog.INSTANCE.init(context,"logFile.txt"); + + HomeUIManager.INSTANCE.setHomeTabBg(findViewById(R.id.main_tab_layout_bg)); + ResourceManager.INSTANCE.initResource(); + } + + @Override + protected void onNewIntent(Intent intent) { + OtherExtKt.doLog("MainActivity onNewIntent()"); + super.onNewIntent(intent); + setIntent(intent); + //这里退出登录,实际上mainActivity是没有销毁的,当从linkme 调起来时候这里需要检查一下登录状态。 + if (TextUtils.isEmpty(AuthModel.get().getTicket())) { + onNeedLogin(); + return; + } + onParseIntent(); + updateDatas(); + InitialModel.get().regionCheck(); + } + + + + private void otherModelInit() { + PwdCodeMgr.get().onCreateInit(); + //初始化线程池 + ThreadPoolManager.instance().init(); + IMBroadcastManager.get().onCreate(); + ImageLoadUtilsV2.init(context); + SettingsModel.get().checkSysAccount(); + initPreloadResource(); + } + + @SuppressLint("CheckResult") + private void checkResumeGame() { + GameModel2.INSTANCE.getResumeGameRoomInfo().compose(bindToLifecycle()) + .doOnSuccess(gameRoomInfo -> { + if (gameRoomInfo != null && gameRoomInfo.getData() != null) { + Integer state = gameRoomInfo.getData().getMatchStatus(); + if (state != null && (state == GameStateAbility.STATE_MATCH_SUCCESS || state == GameStateAbility.STATE_MATCHING)) { + if (resumeGameDialogManager == null) { + resumeGameDialogManager = new DialogManager(this); + } + resumeGameDialogManager.showOkCancelDialog(getString(R.string.resume_game_tips), getString(R.string.join_organization_ok), getString(R.string.join_organization_no), false, new DialogManager.OkCancelDialogListener() { + @Override + public void onOk() { + long gameId = JavaUtil.str2long(gameRoomInfo.getData().getMgId()); + int gameMode = 0; + GameActivity.Companion.start(context, new GameIntent(gameId, gameMode)); + } + + @Override + public void onCancel() { + DialogManager.OkCancelDialogListener.super.onCancel(); + Long roomId = gameRoomInfo.getRoomId(); + if (roomId != null) { + GameModel2.INSTANCE.closeGameRx(roomId).compose(bindToLifecycle()).subscribe(s -> { + }, throwable -> { + }); + } + } + }); + } + } + }).doOnError(e->{ + + }).subscribe(); + } + + private void initPreloadResource() { + mPreLoadViewModel = new ViewModelProvider( + GlobalViewModelOwner.Companion.getInstance() + ).get(PreloadResourceViewModel.class); + mPreLoadViewModel.start(context); + } + + @Override + protected void onReceiveChatRoomEvent(RoomEvent roomEvent) { + super.onReceiveChatRoomEvent(roomEvent); + if (roomEvent == null || roomEvent.getEvent() == RoomEvent.NONE) return; + int event = roomEvent.getEvent(); + if (event == RoomEvent.ENTER_ROOM) { + onEnter(AvRoomDataManager.get().mCurrentRoomInfo); + } else if (event == RoomEvent.KICK_OUT_ROOM) { + + ChatRoomKickOutEvent reason = roomEvent.getReason(); + if (reason == null) return; + //加入黑名单,踢出房间回调 + ChatRoomKickOutEvent.ChatRoomKickOutReason reasonReason = reason.getReason(); + if (reasonReason == ChatRoomKickOutEvent.ChatRoomKickOutReason.BE_BLACKLISTED + || reasonReason == ChatRoomKickOutEvent.ChatRoomKickOutReason.KICK_OUT_BY_MANAGER + || reasonReason == ChatRoomKickOutEvent.ChatRoomKickOutReason.KICK_OUT_BY_CONFLICT_LOGIN + || reasonReason == ChatRoomKickOutEvent.ChatRoomKickOutReason.CHAT_ROOM_INVALID) { + exitRoom(AvRoomDataManager.get().mCurrentRoomInfo); + } + } else if (event == RoomEvent.ROOM_EXIT) { + exitRoom(roomEvent.getRoomInfo()); + } else if (event == RoomEvent.ROOM_CHAT_RECONNECTION) { + updateRoomState(); + } else if (event == RoomEvent.MY_SELF_KICK_OUT_ROOM_BY_S_ADMIN) { + AvRoomDataManager.get().addCurrentRoomLimitEnter(); + toast(R.string.kick_out_room_by_s_admin); + getMvpPresenter().exitRoom(); + } + } + + private void closeOpenRoomAnimation() { + stopRoomMinAnim(); + avatarLayout.setVisibility(View.GONE); + } + + @Override + protected void onResume() { + super.onResume(); + mResumed = true; + if (avatarLayout.getVisibility() == View.VISIBLE) { + userLivingView.start(); + } + //这里是为了处理APP后台运行的情况下点击分享房间等LinkedMe链接的情况 + UserInfo userInfo = UserModel.get().getCacheLoginUserInfo(); + if (userInfo != null) { + handleLinkedJump(this); + } + } + + @Override + protected void onPause() { + super.onPause(); + mResumed = false; + if (avatarLayout.getVisibility() == View.VISIBLE) { + userLivingView.stop(); + } + mMainTabLayout.removeCallbacks(touchRunnable); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (touchRunnable == null) return super.onTouchEvent(event); + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + mMainTabLayout.removeCallbacks(touchRunnable); + break; + case MotionEvent.ACTION_UP: + mMainTabLayout.postDelayed(touchRunnable, 5000); + break; + } + return super.onTouchEvent(event); + } + + private void initView() { + mMainTabLayout = findViewById(R.id.main_tab_layout); + avatarLayout = findViewById(R.id.avatar_image_layout); + viewClose = findViewById(R.id.view_close); + avatarImage = findViewById(R.id.avatar_image); + userLivingView = findViewById(R.id.liv_user); + userLivingView.setColor(Color.WHITE); + mMainTabLayout.setOnTabClickListener(this); + anchorCardView = findViewById(R.id.vs_anchor_card); + mMainTabLayout.setDefaultTabType(mCurrentTabType); + MyUtil.INSTANCE.initAppWidth(findViewById(R.id.rootWidth)); + } + + private void updateDatas() { + handleNimIntent(); + } + + + private void onParseIntent() { + Intent intent = getIntent(); + if (intent.hasExtra(EXTRA_APP_QUIT)) { + onLogout(); + } else if (intent.hasExtra(Extras.EXTRA_JUMP_P2P)) { + Intent data = intent.getParcelableExtra(Extras.EXTRA_DATA); + String account = data.getStringExtra(Extras.EXTRA_ACCOUNT); + if (!TextUtils.isEmpty(account)) { + NimP2PMessageActivity.start(this, account); + } + } else if (intent.hasExtra(MSG_TAB) && intent.getBooleanExtra(MSG_TAB, false)) { + if (mMainTabLayout != null) { + mMainTabLayout.setDefaultTabType(MainTabType.TAB_TYPE_MSG); + } + } + } + + private void initMaterialView() { + avatarLayout.setVisibility(View.GONE); + avatarImage.setOnClickListener(this); + viewClose.setOnClickListener(this); + } + + @Override + protected void onDestroy() { + OtherExtKt.doLog("MainActivity onDestroy()"); + CleanLeakUtils.fixInputMethodManagerLeak(MainActivity.this); + if (mPreLoadViewModel != null) { + mPreLoadViewModel.stopPreLoad(); + } + super.onDestroy(); + if (resumeGameDialogManager != null) { + resumeGameDialogManager.dismissDialog(); + } + ImInitHelper.get().unInit(); + EventBus.getDefault().unregister(this); + stopRoomMinAnim(); + if (limitEnterRoomHelper != null) { + limitEnterRoomHelper.release(); + } + IMBroadcastManager.get().onDestroy(); + } + + /** + * 双击返回键退出 + */ + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + + if (keyCode == KeyEvent.KEYCODE_BACK) { + + /** + * 防止华为机型未加入白名单时按返回键回到桌面再锁屏后几秒钟进程被杀 + */ + try { + Intent launcherIntent = new Intent(Intent.ACTION_MAIN); + launcherIntent.addCategory(Intent.CATEGORY_HOME); + startActivity(launcherIntent); + } catch (Throwable e) { + e.printStackTrace(); + } + + try { + moveTaskToBack(false); + } catch (Exception e) { + return super.onKeyDown(keyCode, event); + } + } + return super.onKeyDown(keyCode, event); + } + + @Override + public void onBackPressed() { + try { + moveTaskToBack(false); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onLoginEvent(LoginEvent event) { + onLogin(AuthModel.get().getCurrentUid()); +// UserModel.get().getUserInfoDetailCache(AuthModel.get().getCurrentUid()).subscribe(); + } + + /** + * 检查是否绑定手机 + */ + private void checkBindPhone() { + BindPhoneActivity.start(context); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onLogoutEvent(LogoutEvent event) { + PwdCodeMgr.get().onLogout(); + onLogout(); + } + + @SuppressLint("CheckResult") + public void onLogin(long uid) { + OtherExtKt.doLogW("onLogin Success ~~~~"); + OtherExtKt.doLogW("onLogin"); + + int unreadCount = IMMessageManager.get().queryUnreadMsg(); + mMainTabLayout.setMsgNum(unreadCount); + openCommunityNotice(); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onLoadLoginUserInfoEvent(LoadLoginUserInfoEvent event) { + OtherExtKt.doLog("消息时间 接收到 LoadLoginUserInfoEvent 消息"); + UserModel.get().updateCurrentUserInfo(); + firstLoadedUserInfo(); + InitialModel.get().regionCheck(); + LoginSuccessManager.Companion.getInstance().onLoadLoginUserInfoEvent(this); + } + + public void onLogout() { + Logger.e(TAG, "onLogout Success ~~~~"); + getMvpPresenter().exitRoom(); + LoginPasswordActivity.start(MainActivity.this); + PmDialogShowMrg.get().onLogout(); + finish(); + } + + public void onNeedLogin() { + NimMiddleActivity.openCommunity = false; + LoginPasswordActivity.start(MainActivity.this); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onKickedOutEvent(KickOutEvent event) { + toast(getString(R.string.you_have_been_kicked_offline)); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onReceiveRecentContactChanged(List imMessages) { + + int countIgnore = 0; + for (RecentContact recentContact : imMessages) { + + if (recentContact.getSessionType() == SessionTypeEnum.Team) { + Team team = NIMClient.getService(TeamService.class).queryTeamBlock(recentContact.getContactId()); + if (team != null && team.getMessageNotifyType() == TeamMessageNotifyTypeEnum.Mute) { + countIgnore += recentContact.getUnreadCount(); + } + + } + + } + int unreadCount = IMMessageManager.get().queryUnreadMsg() + countIgnore; + mMainTabLayout.setMsgNum(unreadCount); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onNeedCompleteInfo(NeedCompleteInfoEvent event) { + getDialogManager().dismissDialog(); + UIHelper.showAddInfoAct(this); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onLoginUserInfoUpdateEvent(LoginUserInfoUpdateEvent event) { + int unreadCount = IMMessageManager.get().queryUnreadMsg(); + mMainTabLayout.setMsgNum(unreadCount); + } + + @SuppressLint("CheckResult") + private void updateRoomState() { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo != null) { + displayAvatarLayout(roomInfo.getAvatar(), roomInfo.getTitle(), roomInfo.getUid()); + } + } + + private void startRoomMinAnim() { + roomMinAnim = ObjectAnimator.ofFloat(avatarImage, "rotation", 0f, 360f); + roomMinAnim.setDuration(10000); + roomMinAnim.setRepeatCount(-1); + roomMinAnim.setInterpolator(new LinearInterpolator()); + roomMinAnim.start(); + } + + private void stopRoomMinAnim() { + if (roomMinAnim != null) { + roomMinAnim.cancel(); + roomMinAnim = null; + } + } + + @SuppressLint("SetTextI18n") + private void displayAvatarLayout(String avatar, String nickName, long uid) { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo != null) { + avatarLayout.clearAnimation(); + avatarLayout.setVisibility(View.VISIBLE); + userLivingView.start(); + stopRoomMinAnim(); + startRoomMinAnim(); + ImageLoadUtils.loadAvatar(MainActivity.this, avatar, avatarImage); + } + } + + public void onEnter(RoomInfo roomInfo) { + updateRoomState(); + DaemonService.start(this, roomInfo); + } + + @SuppressLint("RestrictedApi") + @Override + public void onTabClick(int tabType) { + + Fragment showFragment = fragmentArray.get(tabType); + if (showFragment == tempFragment) return; + + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + if (!showFragment.isAdded()) { + transaction.add(R.id.main_fragment, showFragment, null); + } + transaction.show(showFragment); + if (tempFragment != null) { + transaction.hide(tempFragment); + } + tempFragment = showFragment; + if (!isDestroyed()) { + transaction.commitNowAllowingStateLoss(); + } + mCurrentTabType = tabType; + + //每次点击我的都更新当前用户信息 + if (mCurrentTabType == MainTabType.TAB_TYPE_ME) { + UserModel.get().updateCurrentUserInfo().subscribe(); + } + + switch (tabType) { + case MainTabType.TAB_TYPE_HOME: + reportTabClick(IReportConstants.ELEVEN); + break; + case MainTabType.TAB_TYPE_MSG: + reportTabClick(IReportConstants.THIRTEEN); + break; + case MainTabType.TAB_TYPE_ME: + reportTabClick(IReportConstants.FOURTEEN); + break; + } + } + + /** + * 导航栏tab板块点击 + * + * @param type + */ + private void reportTabClick(int type) { + //登录页展示时 + HashMap map = new HashMap<>(3); + map.put(IReportConstants.HOMEPAGE_TYPE, type); + map.put(IReportConstants.MODULE, IReportConstants.MOLISTAR_HOMEPAGE); + ReportManager.get().reportEvent(IReportConstants.MODULE_HOMEPAGE_CLICK, map); + } + + @Override + public void exitRoom(RoomInfo roomInfo) { + AudioEngineManager.get().setNotRecord(false); + closeOpenRoomAnimation(); + DaemonService.stop(MainActivity.this); + } + + /** + * 第一次加载到用户信息 + */ + @SuppressLint("CheckResult") + private void firstLoadedUserInfo() { + //青少年弹窗处理 + PmDialogShowMrg.get().handle(new WeakReference<>(this)); + + handleChannelPageInfo(); + + checkProtocolUpdate(); + + // 互动消息未读数量 + HomeModel.INSTANCE.getUnreadCount(AuthModel.get().getCurrentUid()) + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .subscribe((integer, throwable) -> { + if (integer != null) { + EventBus.getDefault().post(new UnReadCountEvent(integer)); + } + }); +// checkShowAnchorCardView(); + } + + @SuppressLint("CheckResult") + private void checkProtocolUpdate() { + UserModel.get() + .getProtocolInfo() + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .subscribe(protocolInfo -> { + float version = (float) SharedPreferenceUtils.get(ProtocolUpdateDialog.SP_KEY, 0f); + //第一次打开APP不弹,因为闪屏页已经弹了! + if (version == 0f) { + SharedPreferenceUtils.put(ProtocolUpdateDialog.SP_KEY, protocolInfo.getVer()); + } else if (version < protocolInfo.getVer()) { + new ProtocolUpdateDialog(MainActivity.this, protocolInfo).show(); + } + }); + } + + /** + * 跳转优先级 闪屏→linkedMe→邀请码→新用户打招呼引导→渠道指定房间 + */ + @SuppressLint("CheckResult") + private void handleChannelPageInfo() { + + if (handleSplashJump()) return; + if (handleLinkedJump(this)) return; + + //渠道落地页和邀请码跳转只需要完善资料后处理一次 + String spKey = KEY_FLAG_VALID_CHANNEL_PAGE + AuthModel.get().getCurrentUid(); + if ((boolean) SharedPreferenceUtils.get(spKey, true)) { + SharedPreferenceUtils.put(spKey, false); + checkInviteUserInRoom(); + } + + + } + + /** + * 检查邀请码跳转 + */ + @SuppressLint("CheckResult") + private void checkInviteUserInRoom() { + if (!TextUtils.isEmpty(AddUserInfoFragment.INVITE_USER_CODE)) { + ChannelPageModel.get().checkInviteUserInRoom(AddUserInfoFragment.INVITE_USER_CODE) + .subscribe(inviteUserInfo -> { + if (inviteUserInfo.isInRoom()) { + if (inviteUserInfo.getFromType() == 0) { + AVRoomActivity.start(context, inviteUserInfo.getRoomUid()); + } else { + AVRoomActivity.startForFromType(context, + inviteUserInfo.getRoomUid(), + inviteUserInfo.getFromType(), + inviteUserInfo.getInviteNick(), + String.valueOf(inviteUserInfo.getInviteUid())); + } + } else { + checkNewUserInRoom(); + } + }, throwable -> checkNewUserInRoom()); + AddUserInfoFragment.INVITE_USER_CODE = ""; + } else { + checkNewUserInRoom(); + } + } + + @SuppressLint("CheckResult") + private void checkNewUserInRoom() { + ChannelPageModel.get().checkNewUserInRoom() + .subscribe(newUserHelloInfo -> { + if (newUserHelloInfo.getSayHello()) { + NewUserHelloDialog.Companion.newInstance(newUserHelloInfo).show(context); + } else { + checkChannelPageInRoom(); + } + }, throwable -> checkChannelPageInRoom()); + } + + /** + * 处理渠道落地页 + */ + @SuppressLint("CheckResult") + private void checkChannelPageInRoom() { + GameHomeModel.get().getRoomShortcut() + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .subscribe(uid -> { + if (StringFormatUtils.toLong(uid) != 0) { + AVRoomActivity.start(context, StringFormatUtils.toLong(uid)); + } + }, + Throwable::printStackTrace); + } + + /** + * @return true 如果处理了跳转 + */ + private boolean handleSplashJump() { + OtherExtKt.doLog("闪屏页 -> handleSplashJump 处理 闪屏页跳转"); + if (getIntent().hasExtra("url") && getIntent().hasExtra("type")) { + LogUtil.print(getString(R.string.clicked_the_splash_screen)); + //如果没有渠道页,就按原来的逻辑即可 + int type = getIntent().getIntExtra("type", 0); + String url = getIntent().getStringExtra("url"); + if (type == BannerInfo.SKIP_TYP_H5 || type == BannerInfo.SKIP_TYP_H5_CP || type == BannerInfo.SKIP_TYP_H5_WEE_STAR || type == BannerInfo.SKIP_TYP_H5_CUSTOM) { + Intent intent = new Intent(context, CommonWebViewActivity.class); + intent.putExtra("url", url); + startActivity(intent); + } else if (type == BannerInfo.SKIP_TYP_CHAT_ROOM) { + AVRoomActivity.start(context, Long.parseLong(url)); + } else { + return false; + } + getIntent().putExtra("type",0); + return true; + } + return false; + } + + public LimitEnterRoomHelper getLimitEnterRoomHelper() { + if (limitEnterRoomHelper == null) { + limitEnterRoomHelper = new LimitEnterRoomHelper(); + } + return limitEnterRoomHelper; + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onImPushMsgPmLimitTimeEvent(ImPushMsgPmLimitTimeEvent event) { + //先判断Avroom存不存在,存在的话则不处理,avroom会处理 + Activity reference = App.gStack.getAvRoomActivity(); + if (reference != null) { + return; + } + getLimitEnterRoomHelper().handleThisContext(this, event.getData(), true, this::handlePmExitRoom); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onPmDismissAllLimitDialogEvent(PmDismissAllLimitDialogEvent event) { + if (limitEnterRoomHelper != null) { + limitEnterRoomHelper.dismissDialog(); + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void SquarePublish(SquareTaskEvent event) { + } + + private void handlePmExitRoom() { + if (AvRoomDataManager.get().mCurrentRoomInfo != null) { + closeOpenRoomAnimation(); + getMvpPresenter().exitRoom(); + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onCloseMinRoomEvent(CloseMinRoomEvent event) { + //如果房间存在,就关闭 + if (AvRoomDataManager.get().mCurrentRoomInfo != null) { + handlePmExitRoom(); + } + } + + /** + * 处理开房限制时长 + */ + public void handleOpenRoomWhenPmLimit(String error) { + getLimitEnterRoomHelper().handleThisContext(this, error, false, this::handlePmExitRoom); + } + + /** + * 云信通知栏跳转的处理 + */ + private void handleNimIntent() { + openCommunityNotice(); + + Intent intent = getIntent(); + if (intent == null) { + return; + } + boolean isNimPush = intent.getBooleanExtra(NimMiddleActivity.EXTRA_IS_NIM_PUSH, false); + if (isNimPush && mMainTabLayout != null) { + mMainTabLayout.setDefaultTabType(MainTabType.TAB_TYPE_MSG); + } + } + + /** + * 点击互动通知通知栏,重启进程打开互动通知页 + */ + private void openCommunityNotice() { + if (NimMiddleActivity.delayOpenCommunity) { + return; + } + if (NimMiddleActivity.openCommunity) { + NimMiddleActivity.openCommunity = false; + if (NimMiddleActivity.skipType == 0) return; + new Handler().postDelayed(() -> { + if (NimMiddleActivity.skipType == PushMessageHandler.PAYLOAD_SKIPTYPE_INVITE_FANS && + NimMiddleActivity.payloadUid > 0) { + AVRoomActivity.start(MainActivity.this, NimMiddleActivity.payloadUid); + } else if (NimMiddleActivity.skipType == PushMessageHandler.PAYLOAD_SKIPTYPE_PRIVATE_MSG && + NimMiddleActivity.payloadUid > 0) { + NimP2PMessageActivity.start(MainActivity.this, NimMiddleActivity.payloadUid + ""); + } else if (NimMiddleActivity.skipType == PushMessageHandler.PAYLOAD_SKIPTYPE_H5 && + !TextUtils.isEmpty(NimMiddleActivity.payloadUrl)) { + CommonWebViewActivity.start(MainActivity.this, NimMiddleActivity.payloadUrl); + } + }, 2000); + } + } + + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onNeedBindPhoneEvent(NeedBindPhoneEvent event) { +// checkBindPhone(); + } + + @Subscribe(threadMode = ThreadMode.MAIN, sticky = true) + public void onVisitorUnreadCountEvent(VisitorUnreadCountEvent event) { + if (mMainTabLayout != null) { + mMainTabLayout.setUnreadVisitorCount(event.getVisitNum()); + } + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.avatar_image: + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo != null) { + AVRoomActivity.start(MainActivity.this, roomInfo.getUid()); + } else { + toast(getString(R.string.room_information_is_empty)); + } + + break; + case R.id.view_close: + MainActivity.this.getMvpPresenter().exitRoom(); + break; + } + } + + @Override + protected boolean needSteepStateBar() { + return true; + } + + @Override + protected void setStatusBar() { + super.setStatusBar(); + StatusBarUtil.transparencyBar(this); + StatusBarUtil.StatusBarLightMode(this); + } + +} diff --git a/app/src/main/java/com/chwl/app/MainTabContentView.kt b/app/src/main/java/com/chwl/app/MainTabContentView.kt new file mode 100644 index 0000000..9c0ff9d --- /dev/null +++ b/app/src/main/java/com/chwl/app/MainTabContentView.kt @@ -0,0 +1,4 @@ +package com.chwl.app + +interface MainTabContentView { +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/NimMiddleActivity.java b/app/src/main/java/com/chwl/app/NimMiddleActivity.java new file mode 100644 index 0000000..c03124f --- /dev/null +++ b/app/src/main/java/com/chwl/app/NimMiddleActivity.java @@ -0,0 +1,196 @@ +package com.chwl.app; + +import android.content.Intent; +import android.os.Bundle; +import android.util.Log; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.coorchice.library.utils.LogUtils; +import com.netease.nimlib.sdk.NimIntent; +import com.netease.nimlib.sdk.msg.constant.MsgTypeEnum; +import com.netease.nimlib.sdk.msg.model.IMMessage; +import com.chwl.app.avroom.activity.AVRoomActivity; +import com.chwl.app.base.BaseActivity; +import com.chwl.app.ui.im.avtivity.NimP2PMessageActivity; +import com.chwl.app.ui.webview.CommonWebViewActivity; +import com.chwl.app.utils.PushMessageHandler; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.im.custom.bean.CustomAttachment; +import com.chwl.core.im.custom.bean.OpenRoomNotiAttachment; +import com.chwl.core.im.custom.bean.OpenSignInAttachment; +import com.chwl.core.im.custom.bean.RedPackageAttachment; +import com.chwl.core.im.custom.bean.RoomInviteFansAttachment; +import com.chwl.library.utils.UIUtils; + +import java.util.ArrayList; +import java.util.Map; +import java.util.Objects; + +/** + * Created by chenran on 2017/8/5. + */ + +public class NimMiddleActivity extends BaseActivity { + + private static final String TAG = "mix_push"; + /** + * 通知栏启动Main后,自动跳转到 msg tab + */ + public final static String EXTRA_IS_NIM_PUSH = "is_nim_push"; + + public static String EXTRA_FROM_NOTIFICATION = "from_notification"; + public static final String INTENT_ACTION_AVCHAT = "INTENT_ACTION_AVCHAT"; + + public static boolean firstEnter = true; // 是否首次进入 + + /** + * 用于点击动态通知栏跳转到CommunityNoticeAct + * openCommunity:打开CommunityNoticeAct + *

+ * delayOpenCommunity:控制CommunityNoticeAct打开时机: + * 原因:部分机型可以直接打开NimMiddleActivity; 可以直接调用MainActivity.openCommunityNotice启动CommunityNoticeAct; + * 部分机型(魅蓝Note5(android7.0,Flyme7.3.0.0A))会先打开Splash,再打开NimMiddleActivity; 会导致Splash启动MainActivity.onNewIntent; + * 所以添加delayOpenCommunity字段让CommunityNoticeAct在MainActivity.onNewIntent再启动; + */ + public static boolean openCommunity = false; + public static boolean delayOpenCommunity = false; + public static long payloadUid; + public static int skipType; + public static String payloadUrl; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Log.i(TAG, "NimMiddleActivity"); + Intent intent = getIntent(); + if (intent != null) { + try { + Map payload = (Map) intent.getSerializableExtra(PushMessageHandler.PAYLOAD_DATA); + if (intent.hasExtra(NimIntent.EXTRA_NOTIFY_CONTENT)) { + parseNotifyIntent(intent); + } else if (intent.hasExtra(EXTRA_FROM_NOTIFICATION) || intent.hasExtra(INTENT_ACTION_AVCHAT)) { + parseNormalIntent(intent); + } else if (payload != null) { + parsePayloadData(payload); + } else { + parseNormalIntent(null); + } + } catch (Exception e) { + LogUtils.e("NimMiddleActivity:" + e); + } + } + } + + /** + * 推送通知栏点击 + * + * @param intent + */ + private void parseNotifyIntent(Intent intent) { + if (intent == null) { + return; + } + intent.putExtra(EXTRA_IS_NIM_PUSH, true); + MainActivity.start(NimMiddleActivity.this, intent); + ArrayList messages = (ArrayList) intent.getSerializableExtra(NimIntent.EXTRA_NOTIFY_CONTENT); + if (messages != null && messages.size() > 0) { + IMMessage imMessage = messages.get(messages.size() - 1); + LogUtils.i("getMsgType:" + imMessage.getMsgType()); + if (imMessage.getMsgType() == MsgTypeEnum.custom) { + CustomAttachment attachment = (CustomAttachment) imMessage.getAttachment(); + if (attachment != null) { + if (attachment.getFirst() == CustomAttachment.CUSTOM_MSG_HEADER_TYPE_OPEN_ROOM_NOTI) { + OpenRoomNotiAttachment noticeAttachment = (OpenRoomNotiAttachment) attachment; + if (noticeAttachment.getUid() > 0) { + AVRoomActivity.start(this, noticeAttachment.getUid()); + } + } else if (attachment.getFirst() == CustomAttachment.CUSTOM_MSG_RED_PACKAGE) { + if (attachment.getSecond() == CustomAttachment.CUSTOM_MSG_SUB_RED_PACKAGE_RECEIVE_ALL_DIAMOND) { + RedPackageAttachment redPackageAttachment = (RedPackageAttachment) attachment; + AVRoomActivity.start(this, redPackageAttachment.getRedPackageNotifyInfo().getRoomUid()); + } + } else if (attachment.getFirst() == CustomAttachment.CUSTOM_MSG_PUSH_NOTIFIFICATION) { + if (attachment.getSecond() == CustomAttachment.CUSTOM_MSG_SUB_PUSH_NOTIFICATION_IN_ROOM) { + RoomInviteFansAttachment noticeAttachment = (RoomInviteFansAttachment) attachment; + if (noticeAttachment.getRoomInviteFansInfo() == null) { + return; + } + AVRoomActivity.start(this, noticeAttachment.getRoomInviteFansInfo().getData().getData().getRoomUid()); + } + } else { + NimP2PMessageActivity.start(this, imMessage.getFromAccount() + ""); + } + } + } else if (imMessage.getMsgType() == MsgTypeEnum.notification) { + LogUtils.i("MsgTypeEnum.notification"); + } else if (imMessage.getMsgType() == MsgTypeEnum.text) { + LogUtils.i("MsgTypeEnum.text"); + NimP2PMessageActivity.start(this, imMessage.getFromAccount() + ""); + } + } + finish(); + } + + private void parseNormalIntent(Intent intent) { + MainActivity.start(NimMiddleActivity.this, intent); + finish(); + } + + private void parsePayloadData(Map payload) { + skipType = Integer.parseInt(Objects.requireNonNull(payload.get(PushMessageHandler.PAYLOAD_SKIPTYPE))); + String payloadData = payload.get(PushMessageHandler.PAYLOAD_DATA); + try { + long uid = 0; + if (skipType == PushMessageHandler.PAYLOAD_SKIPTYPE_H5) { + payloadUrl = payloadData; + } else { + JSONObject object = JSON.parseObject(payloadData); + uid = object.getLong("uid"); + payloadUid = uid; + } + + if (AuthModel.get().getCurrentUid() > 0) { + if (!firstEnter) { + LogUtils.e("rev pushMessage payload true:" + uid); + switch (skipType) { + case PushMessageHandler.PAYLOAD_SKIPTYPE_INVITE_FANS: + AVRoomActivity.start(this, uid); + finish(); + break; + + case PushMessageHandler.PAYLOAD_SKIPTYPE_H5: + CommonWebViewActivity.start(this, payloadData); + finish(); + break; + + case PushMessageHandler.PAYLOAD_SKIPTYPE_PRIVATE_MSG: + NimP2PMessageActivity.start(this, uid + ""); + finish(); + break; + + default: + break; + } + } else { + openCommunity = true; + parseNormalIntent(null); + } + } else { + if (firstEnter) { + parseNormalIntent(null); + } else { + finish(); + } + } + } catch (Exception ex) { + ex.printStackTrace(); + if (firstEnter) { + parseNormalIntent(null); + } else { + finish(); + } + } + + } +} diff --git a/app/src/main/java/com/chwl/app/UIHelper.java b/app/src/main/java/com/chwl/app/UIHelper.java new file mode 100644 index 0000000..d054b88 --- /dev/null +++ b/app/src/main/java/com/chwl/app/UIHelper.java @@ -0,0 +1,136 @@ +package com.chwl.app; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; + +import com.chwl.app.audio.MyVoiceActivity; +import com.chwl.app.audio.RecordingVoiceActivity; +import com.chwl.app.audio.SoundSignatureActivity; +import com.chwl.app.ui.login.AddUserInfoActivity; +import com.chwl.app.ui.login.ModifyInfoActivity; +import com.chwl.app.ui.setting.SettingActivity; +import com.chwl.app.ui.user.activity.UserInfoActivity; +import com.chwl.app.ui.user.activity.UserInfoModifyActivity; +import com.chwl.app.ui.user.activity.UserModifyPhotosActivity; +import com.chwl.app.ui.webview.CommonWebViewActivity; +import com.chwl.core.UriProvider; +import com.chwl.core.user.bean.UserInfo; + + +/** + * ************************************************************************* + * + * @Version 1.0 + * @ClassName: UIHelper + * @Description: 应用程序UI工具包:封装UI相关的一些操作 + * @Author zhouxiangfeng + * @date 2013-8-6 下午1:39:11 + * ************************************************************************** + */ +public class UIHelper { + + public static void showUserGuideAct(Context mContext) { + mContext.startActivity(new Intent(mContext, UserGuideActivity.class)); + } + + public static void showSettingAct(Context mContext) { + mContext.startActivity(new Intent(mContext, SettingActivity.class)); + } + + public static void showAddInfoAct(Context mContext) { + Intent intent = new Intent(mContext, AddUserInfoActivity.class); + mContext.startActivity(intent); + + } + + //修改用户资料 + public static void showUserInfoModifyAct(Context mContext, long userId) { + Intent intent = new Intent(mContext, UserInfoModifyActivity.class); + intent.putExtra("userId", userId); + mContext.startActivity(intent); + } + + //修改用户资料 + public static void showUserInfoModifyAct(Activity mActivity, int requestCode, long userId) { + Intent intent = new Intent(mActivity, UserInfoModifyActivity.class); + intent.putExtra("userId", userId); + mActivity.startActivityForResult(intent, requestCode); + } + + //侧边栏===>帮助 + public static void showUsinghelp(Context mContext) { + CommonWebViewActivity.start(mContext, UriProvider.getHelp()); + } + + + public static void showUserInfoAct(Context mContext, long userId) { + Intent intent = new Intent(mContext, UserInfoActivity.class); + intent.putExtra("userId", userId); + mContext.startActivity(intent); + } + + public static void showRecordVoiceAct(Activity mActivity, int requestCode, long voiceId) { + Intent intent = new Intent(mActivity, RecordingVoiceActivity.class); + intent.putExtra(RecordingVoiceActivity.EXTRA_VOICE_ID, voiceId); + mActivity.startActivityForResult(intent, requestCode); + } + + public static void showMyVoiceAct(Activity mActivity, int requestCode, String label) { + Intent intent = new Intent(mActivity, MyVoiceActivity.class); + mActivity.startActivityForResult(intent, requestCode); + } + + public static void showSoundAct(Activity mActivity, int requestCode, String label, UserInfo.SoundBean audioCard) { + Intent intent = new Intent(mActivity, SoundSignatureActivity.class); + intent.putExtra(SoundSignatureActivity.AUDIO_BEAN, audioCard); + mActivity.startActivityForResult(intent, requestCode); + } + + public static void showModifyInfoAct(Activity mActivity, int requestCode, String title) { + Intent intent = new Intent(mActivity, ModifyInfoActivity.class); + intent.putExtra("title", title); + mActivity.startActivityForResult(intent, requestCode); + } + + public static void showModifyInfoAct(Activity mActivity, int requestCode, int modifyType) { + Intent intent = new Intent(mActivity, ModifyInfoActivity.class); + intent.putExtra(ModifyInfoActivity.MODIFY_TYPE, modifyType); + mActivity.startActivityForResult(intent, requestCode); + } + + public static void showModifyPhotosAct(Activity mActivity, long userId) { + Intent intent = new Intent(mActivity, UserModifyPhotosActivity.class); + intent.putExtra("userId", userId); + mActivity.startActivity(intent); + } + + public static void showMonsterResult(Context context, String monsterId) { + CommonWebViewActivity.start(context, UriProvider.IM_SERVER_URL + + "/molistar/modules/monster/index.html?monsterId=" + monsterId); + } + + /** + * 跳转到举报页 + * + * @param uid 被举报人 + */ + public static void showReportPage(Context context, long uid, String source) { + //被举报人的id + String url = UriProvider.getUserReportUrl() + "?reportUid=" + uid + "&source=" + source; + CommonWebViewActivity.start(context, url); + } + + /** + * 跳转推荐页h5 + */ + public static void showRecommendPosH5(Context context) { + String cardUrl = UriProvider.JAVA_WEB_URL + + "/molistar/modules/recommend-card/index.html"; + CommonWebViewActivity.start(context, cardUrl); + } + + public static void openContactUs(Context context) { + CommonWebViewActivity.start(context, UriProvider.IM_SERVER_URL + "/molistar/modules/contact/contact.html"); + } +} diff --git a/app/src/main/java/com/chwl/app/UserGuideActivity.java b/app/src/main/java/com/chwl/app/UserGuideActivity.java new file mode 100644 index 0000000..b6e836d --- /dev/null +++ b/app/src/main/java/com/chwl/app/UserGuideActivity.java @@ -0,0 +1,70 @@ +package com.chwl.app; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.ImageView; + +import androidx.viewpager.widget.ViewPager; + +import com.chwl.app.base.BaseActivity; +import com.chwl.core.PreferencesUtils; + + +public class UserGuideActivity extends BaseActivity { +// private static final int[] images = {R.drawable.guide_one, R.drawable.guide_two, R.drawable.guide_three,}; + protected static final String TAG = "UserGuide"; + private ViewPager mViewPage; + private ImageView enterHome; + private GuideAdapter adapter; + + public static void start(Context context) { + Intent intent = new Intent(context, UserGuideActivity.class); + context.startActivity(intent); + } + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_user_guide); + initView(); + } + + private void initView() { + mViewPage = (ViewPager) findViewById(R.id.view_page); + enterHome = (ImageView) findViewById(R.id.enter_home); + adapter = new GuideAdapter(this); + mViewPage.setAdapter(new GuideAdapter(this)); + mViewPage.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + + } + + @Override + public void onPageSelected(int position) { + if(position == adapter.getCount()-1){ + enterHome.setVisibility(View.VISIBLE); + }else{ + enterHome.setVisibility(View.GONE); + } + } + + @Override + public void onPageScrollStateChanged(int state) { + + } + }); + enterHome.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + PreferencesUtils.setFristUser(false); + MainActivity.start(UserGuideActivity.this); + finish(); + } + }); + + } + + +} diff --git a/app/src/main/java/com/chwl/app/application/App.java b/app/src/main/java/com/chwl/app/application/App.java new file mode 100644 index 0000000..a0e48e3 --- /dev/null +++ b/app/src/main/java/com/chwl/app/application/App.java @@ -0,0 +1,657 @@ +package com.chwl.app.application; + +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_HEADER_TYPE_OPEN_ROOM_NOTI; + +import android.annotation.SuppressLint; +import android.app.Application; +import android.content.Context; +import android.content.res.Configuration; +import android.graphics.Color; +import android.net.http.HttpResponseCache; +import android.os.Build; +import android.os.Environment; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.multidex.MultiDex; + +import com.alibaba.android.arouter.launcher.ARouter; +import com.bumptech.glide.request.target.ViewTarget; +import com.chwl.app.BuildConfig; +import com.chwl.app.NimMiddleActivity; +import com.chwl.app.R; +import com.chwl.app.common.app.ActivityStack; +import com.chwl.app.common.util.AppLifeCycleHelper; +import com.chwl.app.module_hall.HallDataManager; +import com.chwl.app.radish.wallet.RadishWalletManager; +import com.chwl.app.support.IMUserInfoProvider; +import com.chwl.app.utils.PushMessageHandler; +import com.chwl.core.Constants; +import com.chwl.core.DemoCache; +import com.chwl.core.UriProvider; +import com.chwl.core.XConstants; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.bean.response.ServiceResult; +import com.chwl.core.channel.ChannelModel; +import com.chwl.core.family.model.FamilyModel; +import com.chwl.core.gift.GiftModel; +import com.chwl.core.im.custom.bean.CustomAttachment; +import com.chwl.core.im.custom.bean.OpenSignInAttachment; +import com.chwl.core.initial.InitialModel; +import com.chwl.core.interceptor.NoParamsInterceptor; +import com.chwl.core.interceptor.ParamsInterceptor; +import com.chwl.core.interceptor.TimeSyncInterceptor; +import com.chwl.core.manager.IMMessageManager; +import com.chwl.core.manager.IMSystemMsgManager; +import com.chwl.core.market_verify.MarketVerifyModel; +import com.chwl.core.pay.PayModel; +import com.chwl.core.radish.RadishModel; +import com.chwl.core.radish.signin.bean.ImNotice; +import com.chwl.core.room.face.DynamicFaceModel; +import com.chwl.core.user.UserModel; +import com.chwl.core.user.event.NeedCompleteInfoEvent; +import com.chwl.core.utils.SharedPreferenceUtils; +import com.chwl.core.utils.net.ServerException; +import com.chwl.library.common.application.BaseApp; +import com.chwl.library.common.application.Env; +import com.chwl.library.common.file.FileHelper; +import com.chwl.library.common.util.OtherExtKt; +import com.chwl.library.error.CrashCat; +import com.chwl.library.language.LanguageHelper; +import com.chwl.library.net.rxnet.RxNet; +import com.chwl.library.net.rxnet.converter.GsonConverterPlugins; +import com.chwl.library.net.rxnet.utils.NetworkLatencyChecker; +import com.chwl.library.utils.AppMetaDataUtil; +import com.chwl.library.utils.DeviceUuidFactory; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; +import com.chwl.library.utils.SystemUtils; +import com.chwl.library.utils.VersionUtil; +import com.chwl.library.utils.codec.MD5Utils; +import com.chwl.library.utils.config.BasicConfig; +import com.coorchice.library.utils.LogUtils; +import com.example.lib_utils.ServiceTime; +import com.hjq.toast.ToastUtils; +import com.netease.nim.uikit.api.NimUIKit; +import com.netease.nim.uikit.common.util.log.LogUtil; +import com.netease.nimlib.sdk.NIMClient; +import com.netease.nimlib.sdk.NotificationFoldStyle; +import com.netease.nimlib.sdk.SDKOptions; +import com.netease.nimlib.sdk.StatusBarNotificationConfig; +import com.netease.nimlib.sdk.mixpush.MixPushConfig; +import com.netease.nimlib.sdk.mixpush.NIMPushClient; +import com.netease.nimlib.sdk.msg.MessageNotifierCustomization; +import com.netease.nimlib.sdk.msg.constant.MsgTypeEnum; +import com.netease.nimlib.sdk.msg.model.IMMessage; +import com.netease.nimlib.sdk.util.NIMUtil; +import com.opensource.svgaplayer.SVGAParser; +import com.orhanobut.logger.AndroidLogAdapter; +import com.orhanobut.logger.Logger; +import com.scwang.smart.refresh.footer.ClassicsFooter; +import com.scwang.smart.refresh.header.MaterialHeader; +import com.scwang.smart.refresh.layout.SmartRefreshLayout; +import com.scwang.smart.refresh.layout.api.RefreshFooter; +import com.scwang.smart.refresh.layout.api.RefreshHeader; +import com.scwang.smart.refresh.layout.api.RefreshLayout; +import com.scwang.smart.refresh.layout.listener.DefaultRefreshFooterCreator; +import com.scwang.smart.refresh.layout.listener.DefaultRefreshHeaderCreator; +import com.tencent.vasdolly.helper.ChannelReaderUtil; + +import org.greenrobot.eventbus.EventBus; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import io.reactivex.plugins.RxJavaPlugins; +import io.realm.Realm; +import io.realm.RealmConfiguration; + +/** + * @author chenran + * @date 2017/2/11 + */ + +public class App extends BaseApp { + public static final String TAG = "XChatApplication"; + public static Application gContext; + + //static 代码段可以防止内存泄露 + static { + //设置全局的Header构建器 + SmartRefreshLayout.setDefaultRefreshHeaderCreator(new DefaultRefreshHeaderCreator() { + @Override + public RefreshHeader createRefreshHeader(Context context, RefreshLayout layout) { + layout.setPrimaryColorsId(R.color.colorPrimary, android.R.color.white);//全局设置主题颜色 + return new MaterialHeader(context);//.setTimeFormat(new DynamicTimeFormat("更新于 %s"));//指定为经典Header,默认是 贝塞尔雷达Header + } + }); + //设置全局的Footer构建器 + SmartRefreshLayout.setDefaultRefreshFooterCreator(new DefaultRefreshFooterCreator() { + @Override + public RefreshFooter createRefreshFooter(Context context, RefreshLayout layout) { + //指定为经典Footer,默认是 BallPulseFooter + return new ClassicsFooter(context).setDrawableSize(20); + } + }); + } + + + // 接收到退出登录事件(跳转到登录页了) + private static long logoutEventTime = 0; + + private static final MessageNotifierCustomization messageNotifierCustomization = new MessageNotifierCustomization() { + @Override + public String makeNotifyContent(String nick, IMMessage message) { + if (message.getMsgType() == MsgTypeEnum.custom) { + CustomAttachment customAttachment = (CustomAttachment) message.getAttachment(); + if (customAttachment.getFirst() == CUSTOM_MSG_HEADER_TYPE_OPEN_ROOM_NOTI) { + return message.getFromNick(); + } else if (customAttachment instanceof OpenSignInAttachment) { + return getContentFromOpenSignIn(customAttachment); + } + } + // 采用SDK默认文案 + return ResUtil.getString(R.string.erban_application_xchatapplication_01); + } + + @Override + public String makeTicker(String nick, IMMessage message) { + if (message.getMsgType() == MsgTypeEnum.custom) { + CustomAttachment customAttachment = (CustomAttachment) message.getAttachment(); + if (customAttachment != null) { + if (customAttachment.getFirst() == CUSTOM_MSG_HEADER_TYPE_OPEN_ROOM_NOTI) { + return message.getFromNick(); + } else if (customAttachment instanceof OpenSignInAttachment) { + return getContentFromOpenSignIn(customAttachment); + } + } + } + // 采用SDK默认文案 + return ResUtil.getString(R.string.erban_application_xchatapplication_02); + } + + private String getContentFromOpenSignIn(CustomAttachment attachment) { + String result = null; + if (attachment instanceof OpenSignInAttachment) { + ImNotice notice = ((OpenSignInAttachment) attachment).getImNotice(); + if (notice != null) { + result = notice.getContent(); + } + } + if (TextUtils.isEmpty(result)) { + result = ResUtil.getString(R.string.erban_application_xchatapplication_03); + } + return result; + } + + @Override + public String makeRevokeMsgTip(String s, IMMessage imMessage) { + return null; + } + + @Override + public String makeCategory(IMMessage message) { + return null; + } + }; + private static App instance; + //生命周期监听 + private static AppLifeCycleHelper lifeCycleHelper; + public static ActivityStack gStack = new ActivityStack(); + private static boolean isInitOtherSDK = false; + + + public static App instance() { + return instance; + } + + public static void initOtherSDK() { + if (isInitOtherSDK) return; + isInitOtherSDK = true; + Context context = BasicConfig.INSTANCE.getAppContext(); + Application application = (Application) context.getApplicationContext(); + // 初始化 sp + long startTime = System.currentTimeMillis(); + + String channel = ""; + channel = ChannelReaderUtil.getChannel(instance); + Log.d("APP", "localChannel:" + channel); + if (TextUtils.isEmpty(channel)) { + channel = Constants.GOOGLE; + } + Log.d("APP", "finalChannel:" + channel); + BasicConfig.INSTANCE.setOriginalChannel(channel); + + BasicConfig.INSTANCE.setChannel(channel); + + initEnv(); + + // ARouter + if (isDebug()) { // These two lines must be written before init, otherwise these configurations will be invalid in the init process + ARouter.openLog(); // Print log + ARouter.openDebug(); // Turn on debugging mode (If you are running in InstantRun mode, you must turn on debug mode! Online version needs to be closed, otherwise there is a security risk) + } + ARouter.init(application); // As early as possible, it is recommended to initialize in the Application + + //延迟初始化云信 + NIMClient.init(context, null, options()); + + //logger 配置 + Logger.addLogAdapter(new AndroidLogAdapter() { + @Override + public boolean isLoggable(int priority, String tag) { + return BuildConfig.DEBUG; + } + }); + + ToastUtils.init(application); + + if (inMainProcess(context)) { + DemoCache.saveLaunchCount(); + // 注册自定义推送消息处理,这个是可选项 + NIMPushClient.registerMixPushMessageHandler(new PushMessageHandler()); + + RxJavaPlugins.setErrorHandler(throwable -> { + if (BuildConfig.DEBUG) { + Log.e(TAG, "the subscribe() method default error handler", throwable); + } + }); + + //需要完善资料错误码全局处理 + GsonConverterPlugins.setResultHandler(result -> { + if (result instanceof ServiceResult) { + ServiceResult serviceResult = (ServiceResult) result; + if (serviceResult.getCode() == ServiceResult.CODE_NEED_COMPLETE_USER_INFO) { + SingleToastUtil.showToast(serviceResult.getMessage()); + EventBus.getDefault().post(new NeedCompleteInfoEvent()); + throw new ServerException(serviceResult.getMessage(), serviceResult.getCode()); + } else if (serviceResult.getCode() == 401) { + if ((ServiceTime.INSTANCE.getTime() - logoutEventTime) > 800) { + logoutEventTime = ServiceTime.INSTANCE.getTime(); + SingleToastUtil.showToast(serviceResult.getMessage()); + AuthModel.get().cleanLogInfo(); + } + throw new ServerException(serviceResult.getMessage(), serviceResult.getCode()); + }else if (serviceResult.getCode() == ServiceResult.CODE_ROOM_MANAGER_LIMIT) { + throw new ServerException(serviceResult.getMessage(), serviceResult.getCode()); + } + } + return null; + }); + GsonConverterPlugins.lockdown(); + + + //fixed: Glide Exception:"You must not call setTag() on a view Glide is targeting" + ViewTarget.setTagId(R.id.tag_glide); + + init(channel); + + //生命周期监听 + if (lifeCycleHelper == null) { + lifeCycleHelper = new AppLifeCycleHelper(); + } + registerActivityLifecycleCallback(lifeCycleHelper); +// initLinkedMe(); +// MobSDK.init(context); +// MobSDK.submitPolicyGrantResult(true); + } +// SVGALogger.INSTANCE.setLogEnabled(BuildConfig.DEBUG); +// SVGASoundManager.INSTANCE.init(); + LogUtils.d("init time = " + (System.currentTimeMillis() - startTime) + "ms"); + + } + + public static void registerActivityLifecycleCallback(Application.ActivityLifecycleCallbacks callbacks) { + ((Application) BasicConfig.INSTANCE.getAppContext().getApplicationContext()).registerActivityLifecycleCallbacks(callbacks); + } + +// /** +// * 初始化linkedMe +// */ +// private static void initLinkedMe() { +// MobSDK.init(instance, "32fd2f8457880", "ef796ca85e8cd95a76929663de133214"); +// MobLink.setRestoreSceneListener(new RestoreSceneListener() { +// @Override +// public Class willRestoreScene(Scene scene) { +// return AgentActivity.class; +// } +// +// @Override +// public void completeRestore(Scene scene) { +// } +// +// @Override +// public void notFoundScene(Scene scene) { +// } +// }); +// } + + + private static void initEnv() { + //首先初始化环境 + Env.initEnv(BuildConfig.BUILD_TYPE, BuildConfig.DEBUG); + //切换生产坏境和测试环境 true/测试环境 false/生产环境 + BasicConfig.INSTANCE.setDebuggable(Env.isDebug()); + BasicConfig.INSTANCE.setRootDir(Constants.ERBAN_DIR_NAME); + BasicConfig.INSTANCE.setLogDir(Constants.LOG_DIR); + BasicConfig.INSTANCE.setConfigDir(Constants.CONFIG_DIR); + BasicConfig.INSTANCE.setVoiceDir(Constants.VOICE_DIR); + BasicConfig.INSTANCE.setCacheDir(Constants.CACHE_DIR); + BasicConfig.INSTANCE.setImageDir(Constants.IMAGE_CACHE_DIR); + com.example.lib_utils.log.LogUtil.INSTANCE.setConsolePrinterEnabled(BuildConfig.DEBUG); + } + + /** + * 云信配置 + * + * @return + */ + public static SDKOptions options() { + SDKOptions options = new SDKOptions(); + options.disableAwake = true; + options.asyncInitSDK = true; +// options.customPushContentType = ""; + if (isDebug()) { + options.checkManifestConfig = true; + } + // 如果将新消息通知提醒托管给 SDK 完成,需要添加以下配置。否则无需设置。 + StatusBarNotificationConfig config = new StatusBarNotificationConfig(); + // 点击通知栏跳转到该Activity + config.notificationEntrance = NimMiddleActivity.class; +// config.notificationSmallIconId = R.drawable.icon_msg_normal; + // 呼吸灯配置 + config.ledARGB = Color.GREEN; + config.ledOnMs = 1000; + config.ledOffMs = 1500; + config.notificationFoldStyle = NotificationFoldStyle.CONTACT; + // 通知铃声的uri字符串 + config.notificationSound = "android.resource://com.netease.nim.demo/raw/msg"; + options.statusBarNotificationConfig = config; + // 定制通知栏提醒文案(可选,如果不定制将采用SDK默认文案) + options.messageNotifierCustomization = messageNotifierCustomization; + + options.appKey = Constants.nimAppKey; + + // 配置保存图片,文件,log 等数据的目录 + // 如果 options 中没有设置这个值,SDK 会使用下面代码示例中的位置作为 SDK 的数据目录。 + // 该目录目前包含 log, file, image, audio, video, thumb 这6个目录。 + // 如果第三方 APP 需要缓存清理功能, 清理这个目录下面个子目录的内容即可。 + String sdkPath = null; + try { + sdkPath = FileHelper.getRootCacheDir().getAbsolutePath() + "/nim"; + } catch (ArrayIndexOutOfBoundsException e) { + + } + options.sdkStorageRootPath = sdkPath; + + // 配置是否需要预下载附件缩略图,默认为 true + options.preloadAttach = true; + + // 配置附件缩略图的尺寸大小。表示向服务器请求缩略图文件的大小 + // 该值一般应根据屏幕尺寸来确定, 默认值为 Screen.width / 2 + int widthPixels = BasicConfig.INSTANCE.getAppContext().getResources().getDisplayMetrics().widthPixels; + options.thumbnailSize = widthPixels / 2; +// // save cache,留做切换账号备用 + DemoCache.setNotificationConfig(config); + + MixPushConfig mixPushConfig = new MixPushConfig(); + + + options.mixPushConfig = mixPushConfig; + + return options; + } + + /** + * 判断当前进程是否主进程 + * + * @param context + * @return + */ + private static boolean inMainProcess(Context context) { + String packageName = context.getPackageName(); + String processName = NIMUtil.getProcessName(context); + return packageName.equals(processName); + } + + + + private static void init(String channel) { + initNimUIKit(); + + + UriProvider.initUri(BuildConfig.BASE_URL_DEBUG, BuildConfig.BASE_URL_STAGING, BuildConfig.BASE_URL_RELEASE); + initRxNet(BasicConfig.INSTANCE.getAppContext(), UriProvider.JAVA_WEB_URL); + + Env.EnvType envType = Env.getCurrentEnv(); + if (envType == Env.EnvType.Release || (!BuildConfig.DEBUG)) { + OtherExtKt.doLog(" 域名 ping 环境:正式---->, 准备执行域名池相关逻辑"); + List firstUrls = new ArrayList<>(); + firstUrls.add("api.molistar.xyz"); +// firstUrls.add("api.molistar.xyzz"); + NetworkLatencyChecker.INSTANCE.use(firstUrls,443,5000, firstUrl -> { + if (OtherExtKt.isVerify(firstUrl)){ + OtherExtKt.doLog(" 域名 ping--> , 当前域名最优为 "+firstUrl +" 是默认优先域名,不做其他处理"); + NetworkLatencyChecker.INSTANCE.checkFinishes(); + }else { + OtherExtKt.doLog(" 域名 ping--> , 默认优先域名出现异常 , 执行检测 次级域名 逻辑"); + List secondUrls = new ArrayList<>(); + secondUrls.add("api.molistars.com"); + NetworkLatencyChecker.INSTANCE.use(secondUrls,443,5000, secondUrl -> { + if (OtherExtKt.isVerify(secondUrl)){ + String newBaseUrl = "https://"+secondUrl+"/"; + OtherExtKt.doLog(" 域名 ping--> , 次级域名检测-正常, 执行刷新域名操作 "+secondUrl); + UriProvider.initUri(BuildConfig.BASE_URL_DEBUG, BuildConfig.BASE_URL_STAGING, newBaseUrl); + RxNet.refreshBaseUrl(newBaseUrl); + refreshApi(); + NetworkLatencyChecker.INSTANCE.checkFinishes(); + }else { + OtherExtKt.doLog(" 域名 ping--> , 次级域名检测-异常!, 没有后续操作.. "); + NetworkLatencyChecker.INSTANCE.checkFinishes(); + } + return null; + }); + } + return null; + }); + }else { + OtherExtKt.doLog(" 域名 ping--> 环境:测试---->, 无需执行域名池"); + NetworkLatencyChecker.INSTANCE.checkFinishes(); + } + + + + + SVGAParser.Companion.shareParser().init(BasicConfig.INSTANCE.getAppContext()); + try { + /** svga动画缓存路径 */ + String cacheDirPath = FileHelper.getRootCacheDir().getAbsolutePath(); + File cacheFie = new File(cacheDirPath, "cacheDir"); + HttpResponseCache.install(cacheFie, 1024 * 1024 * 128); + } catch (IOException e) { + Log.e(TAG, "HttpResponseCache install error :" + e.getMessage()); + } + + + /** + * 使用到realm 数据库,这里配置数据库 这里必须先于模块初始化前进行初始化配置 + */ + Realm.init(BasicConfig.INSTANCE.getAppContext()); + RealmConfiguration config = new RealmConfiguration.Builder() + .name("accompany.realm") + .deleteRealmIfMigrationNeeded() + .build(); + Realm.setDefaultConfiguration(config); + + LogUtil.i(TAG, channel); + } + + /** + * 初始化RxNet + * + * @param context + * @param url + */ + @SuppressLint("CheckResult") + public static void initRxNet(Context context, String url) { + Map httpParams = new ConcurrentHashMap<>(); + httpParams.put("os", "android"); + httpParams.put("osVersion", Build.VERSION.RELEASE); + httpParams.put("app", XConstants.APP_MARK); + httpParams.put("ispType", String.valueOf(SystemUtils.getIspType(context))); + httpParams.put("netType", String.valueOf(SystemUtils.getNetworkType(context))); + httpParams.put("model", SystemUtils.getPhoneModel()); + httpParams.put("appVersion", VersionUtil.getLocalName(context)); + httpParams.put("appVersionCode", String.valueOf(VersionUtil.getVersionCode(context))); + httpParams.put("deviceId", DeviceUuidFactory.getDeviceId(context)); + httpParams.put("androidId", MD5Utils.getMD5String(Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID))); + httpParams.put("channel", AppMetaDataUtil.getChannelID()); + httpParams.put("lang", LanguageHelper.INSTANCE.getSystemLanguage().toLanguageTag()); + RxNet.init(context) + .debug(Env.isRealDebug()) + .setBaseUrl(url) + .addInterceptors(new ParamsInterceptor(httpParams)) + .addInterceptors(new NoParamsInterceptor())//注意:拦截器的添加顺序,请求的拦截顺序 + .addInterceptors(new TimeSyncInterceptor()) + .certificates() + .build(); + //单例的model 初始化 + initModel(); + } + + /** + * 一些单例的 model + */ + private static void initModel() { + DynamicFaceModel.get().init(); + PayModel.get(); + UserModel.get(); + //ui层的萝卜钱包 + RadishWalletManager.get(); + //model层的 + RadishModel.get(); + + IMMessageManager.get().init(); + IMSystemMsgManager.get().init(); + + FamilyModel.Instance(); + AuthModel.get(); + + ChannelModel.get(); + MarketVerifyModel.get(); + GiftModel.get(); + // 模厅 + HallDataManager.get().application(); + //全局处理 + GlobalHandleManager.get().init(); + + InitialModel.get().init(true).subscribe(); + + //上报平台初始化 + ReportManager.get().init(); + } + + private static void refreshApi() { + PayModel.get().refreshApi(); + UserModel.get().refreshApi(); + RadishModel.get().refreshApi(); + FamilyModel.Instance().refreshApi(); + AuthModel.get().refreshApi(); + MarketVerifyModel.get().refreshApi(); + GiftModel.get().refreshApi(); + HallDataManager.get().refreshApi(); + InitialModel.get().refreshApi(); + InitialModel.get().init(false); + } + + private static void initNimUIKit() { + // 初始化 + NimUIKit.init(BasicConfig.INSTANCE.getAppContext(), new IMUserInfoProvider(), null); + } + + /** + * debug 环境 受到实验室模式影响 + */ + public static boolean isDebug() { + return Env.isDebug(); + } + + /** + * 是否是真实的debug的环境 不受实验室模式影响 + * + * @return + */ + public static boolean isRealDebug() { + return Env.isRealDebug(); + } + + + /** + * 用户没同意隐私协议之前,啥也不干!! + */ + @Override + public void onCreate() { + super.onCreate(); + OtherExtKt.doLog("App onCreate() -- 启动"); + instance = this; + BaseApp.init(this); + BasicConfig.INSTANCE.setAppContext(this.getApplicationContext()); + SharedPreferenceUtils.init(this); + ResUtil.init(this); + ResUtil.contextSupplier = () -> App.gStack.getTopContext(); + LanguageHelper.INSTANCE.wrapContext(instance); + initOtherSDK(); + initContext(this); + //首次启动事件 + HashMap map = new HashMap<>(2); + map.put(IReportConstants.MODULE, IReportConstants.MOLISTAR_ACTIVATE); + ReportManager.get().reportEvent(IReportConstants.ACTIVATE_FIRST, map); + + //xxx 崩溃日志拦截 + if (BuildConfig.DEBUG) { + CrashCat.getInstance(getApplicationContext(), Environment.getExternalStorageDirectory().getPath()+ "/Log","log.txt").start(); + } + } + + /** + * 初始化Application实例 + */ + public void initContext(Application application) { + gContext = application; + } + + /** + * @return 获取Application实例 + */ + public static Application getApplication() { + return gContext; + } + + @Override + protected void attachBaseContext(Context base) { + super.attachBaseContext(base); + MultiDex.install(base); + } + + @Override + public void onConfigurationChanged(@NonNull Configuration newConfig) { + super.onConfigurationChanged(newConfig); + LanguageHelper.INSTANCE.wrapContext(this); + } + + @Override + public void onTerminate() { + super.onTerminate(); + GlobalHandleManager.get().unInit(); + if (lifeCycleHelper != null) { + unregisterActivityLifecycleCallbacks(lifeCycleHelper); + } + } +} diff --git a/app/src/main/java/com/chwl/app/application/GlobalHandleManager.java b/app/src/main/java/com/chwl/app/application/GlobalHandleManager.java new file mode 100644 index 0000000..5929655 --- /dev/null +++ b/app/src/main/java/com/chwl/app/application/GlobalHandleManager.java @@ -0,0 +1,115 @@ +package com.chwl.app.application; + +import android.app.Activity; + +import com.chwl.app.avroom.newuserchargegift.NewUserChargePrizeDialog; +import com.chwl.app.relation.cp.dialog.CpGlobalDialog; +import com.chwl.app.ui.widget.LevelUpDialog; +import com.chwl.app.ui.widget.RecallDialog; +import com.chwl.app.vip.dialog.VipUpgradeDialog; +import com.chwl.core.level.event.CharmLevelUpEvent; +import com.chwl.core.level.event.LevelUpEvent; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.pay.event.NewUserChargeEvent; +import com.chwl.core.recall.bean.CheckLostUserInfo; +import com.chwl.core.recall.event.CheckLostUserEvent; +import com.chwl.core.relation.cp.bean.CpInviteInfo; +import com.chwl.core.upgrade.event.ImPushUpdateAppEvent; +import com.chwl.core.user.UserModel; +import com.chwl.core.utils.SharedPreferenceUtils; +import com.chwl.core.vip.VipUpgradeEvent; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +/** + * 全局处理,比如App弹窗 + * create by lvzebiao @2019/8/14 + */ +public class GlobalHandleManager { + + private GlobalHandleManager() { + + } + + public static GlobalHandleManager get() { + return Helper.INSTANCE; + } + + public void init() { + EventBus.getDefault().register(this); + } + + public void unInit() { + EventBus.getDefault().unregister(this); + } + + public Activity getActivity() { + return App.gStack.getTopActivity(); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onImPushUpdateAppEvent(ImPushUpdateAppEvent event) { + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onVipUpgradeEvent(VipUpgradeEvent vipUpgradeEvent) { + Activity activity = getActivity(); + if (activity == null) return; + UserModel.get().onlyUpdateLoginUserInfoCache(); + VipUpgradeDialog.newInstance(vipUpgradeEvent.getVipInfo()).show(activity); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onCpInviteEvent(CpInviteInfo entity) { + Activity activity = getActivity(); + if (activity == null) return; + CpGlobalDialog.newInstance(entity, activity).openDialog(); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onNewUserChargeEvent(NewUserChargeEvent event) { + Activity activity = getActivity(); + if (activity == null) return; + new NewUserChargePrizeDialog(activity, event.getChargeProdTitle(), event.getFirstChargeRewardList()).openDialog(); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onReceiveRecallStatus(CheckLostUserEvent event) { + Activity activity = getActivity(); + if (activity == null) return; + //如果没有获取到当前登录用户的信息,不弹出提示 + if (UserModel.get().getCacheLoginUserInfo() == null) { + return; + } + + CheckLostUserInfo checkLostUserInfo = (CheckLostUserInfo) event.getData(); + + boolean goBackOnce = (boolean) SharedPreferenceUtils.get(RecallDialog.GO_BACK_ONCE, false); + + if (!goBackOnce && !event.isFailed() && checkLostUserInfo.isLostUser() && !checkLostUserInfo.isClaimedAward()) + RecallDialog.start(activity); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onReceiveLevelUpActivity(LevelUpEvent event) { + Activity activity = getActivity(); + if (activity == null) return; + if (AvRoomDataManager.get().isSelfGamePlaying()) return; +// LevelUpDialog.start(activity, event.getLevelName(), true); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onReceiveCharmLevelUpActivity(CharmLevelUpEvent event) { + Activity activity = getActivity(); + if (activity == null) return; + if (AvRoomDataManager.get().isSelfGamePlaying()) return; +// LevelUpDialog.start(activity, event.getLevelName(), false); + } + + private static final class Helper { + private static final GlobalHandleManager INSTANCE = new GlobalHandleManager(); + } + +} diff --git a/app/src/main/java/com/chwl/app/application/IReportConstants.java b/app/src/main/java/com/chwl/app/application/IReportConstants.java new file mode 100644 index 0000000..5b97f7c --- /dev/null +++ b/app/src/main/java/com/chwl/app/application/IReportConstants.java @@ -0,0 +1,60 @@ +package com.chwl.app.application; + +/** + * Created by wushaocheng on 2022/11/10. + */ +public interface IReportConstants { + + //Adjust + String ADJUST_REGISTER = "yly8k0"; + String ADJUST_LOGIN = "ygtnu5"; + + String CHANNEL = "channel"; + String UID = "uid"; + String APPV = "appv"; + + String MODULE = "module"; + int ZERO = 0; + int ONE = 1; + int TWO = 2; + int THREE = 3; + int FOUR = 4; + int FIVE = 5; + int SIX = 6; + int SEVEN = 7; + int EIGHT = 8; + int NINE = 9; + int TEN = 10; + int ELEVEN = 11; + int TWELVE = 12; + int THIRTEEN = 13; + int FOURTEEN = 14; + int FIFTEEN = 15; + + String ACTIVATE_FIRST = "activate_first"; + String MOLISTAR_ACTIVATE = "molistar_activate"; + String AGREEMENT_SHOW = "agreement_show"; + String MOLISTAR_LOGIN = "molistar_login"; + String AGREEMENT_CLICK = "agreement_click"; + String CLICK_TYPE = "click_type"; + String PAGE = "page"; + String LOGIN_SHOW = "login_show"; + String LOGIN_CLICK = "login_click"; + String LOGIN_REQUEST = "login_request"; + String LOGIN_TYPE = "login_type"; + String LOGIN_RESULT = "login_result"; + String RESULT = "result"; + String FAIL_DETAIL = "fail_detail"; + String MODULE_HOMEPAGE_CLICK = "module_homepage_click"; + String HOMEPAGE_TYPE = "homepage_type"; + String MOLISTAR_HOMEPAGE = "molistar_homepage"; + String TAB_HOMEPAGE_CLICK = "tab_homepage_click"; + String HOMEPAGE_TAB = "homepage_tab"; + String PAYPAGE_SHOW = "paypage_show"; + String PAYPAGE_TYPE = "paypage_type"; + String ACCOUNT_BALANCE = "account_balance"; + String PAY_CLICK = "pay_click"; + String MONEY = "money"; + String MOLISTAR_PAY = "molistar_pay"; + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/application/IReportService.java b/app/src/main/java/com/chwl/app/application/IReportService.java new file mode 100644 index 0000000..9a12c71 --- /dev/null +++ b/app/src/main/java/com/chwl/app/application/IReportService.java @@ -0,0 +1,41 @@ +package com.chwl.app.application; + +import android.os.Bundle; + +import java.util.Map; + +/** + * Created by logwee on 2018/10/10. + */ +public interface IReportService { + + /** + * 设置FirebaseAnalytics公共属性 + * + * @param bundle 公共属性 + */ + void setFirebaseAnalyticsDefaultEventParameters(Bundle bundle); + + /** + * 埋点,不需要字事件 + * + * @param eventId 事件名称 + */ + void reportEvent(String eventId); + + /** + * 埋点 + * + * @param eventId 事件名称 + * @param map 事件参数和值 + */ + void reportEvent(String eventId, Map map); + + /** + * Adjust埋点 + * + * @param eventId 事件名称 + */ + void reportAdjustEvent(String eventId); + +} diff --git a/app/src/main/java/com/chwl/app/application/ReportManager.java b/app/src/main/java/com/chwl/app/application/ReportManager.java new file mode 100644 index 0000000..eb7e7b4 --- /dev/null +++ b/app/src/main/java/com/chwl/app/application/ReportManager.java @@ -0,0 +1,63 @@ +package com.chwl.app.application; + +import android.os.Bundle; +import java.util.Map; + +/** + * 统一埋点事件 + * create by lvzebiao @2019/8/14 + */ +public class ReportManager implements IReportService { + + private static final String TAG = "ReportManager"; + + private ReportManager() { + } + + private static final class Helper { + private static final ReportManager INSTANCE = new ReportManager(); + } + + public static ReportManager get() { + return Helper.INSTANCE; + } + + public void init() { + } + + + /** + * 设置FirebaseAnalytics公共属性 + * + * @param bundle 公共属性 + */ + @Override + public void setFirebaseAnalyticsDefaultEventParameters(Bundle bundle) { + } + + /** + * 埋点,不需要上报网络质量和事件耗时 + * + * @param eventId 事件名称 + */ + @Override + public void reportEvent(String eventId) { + reportEvent(eventId, null); + } + + /** + * 埋点 + * + * @param eventId 事件名称 + * @param map 事件参数和值 + */ + @Override + public void reportEvent(String eventId, Map map) { + } + + @Override + public void reportAdjustEvent(String eventId) { + } + + +} diff --git a/app/src/main/java/com/chwl/app/audio/AudioRecordActivity.java b/app/src/main/java/com/chwl/app/audio/AudioRecordActivity.java new file mode 100644 index 0000000..ce275f6 --- /dev/null +++ b/app/src/main/java/com/chwl/app/audio/AudioRecordActivity.java @@ -0,0 +1,373 @@ +package com.chwl.app.audio; + +import android.annotation.SuppressLint; +import android.content.Intent; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; +import android.widget.Chronometer; + +import com.netease.nimlib.sdk.media.player.AudioPlayer; +import com.netease.nimlib.sdk.media.player.OnPlayListener; +import com.netease.nimlib.sdk.media.record.AudioRecorder; +import com.netease.nimlib.sdk.media.record.IAudioRecordCallback; +import com.netease.nimlib.sdk.media.record.RecordType; +import com.chwl.app.R; +import com.chwl.app.base.BaseViewBindingActivity; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.app.databinding.ActivityAudiorecordBinding; +import com.chwl.core.audio.AudioPlayAndRecordManager; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.file.FileModel; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.core.room.model.AvRoomModel; +import com.chwl.core.user.UserModel; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.log.MLog; + +import java.io.File; + +import io.reactivex.SingleObserver; +import io.reactivex.disposables.Disposable; + +/** + * @author zhouxiangfeng + * @date 2017/5/25 + */ +public class AudioRecordActivity extends BaseViewBindingActivity implements View.OnClickListener { + + private static final String TAG = "AudioRecordActivity"; + + public static final String AUDIO_FILE = "AUDIO_FILE"; + public static final String AUDIO_DURA = "AUDIO_DURA"; + + private String audioUrl; + private AudioPlayer audioPlayer; + private AudioPlayAndRecordManager audioManager; + private AudioRecorder recorder; + + @Override + public void init() { + audioManager = AudioPlayAndRecordManager.getInstance(); + audioPlayer = audioManager.getAudioPlayer(null, onPlayListener); + onSetListener(); + } + + @SuppressLint("ClickableViewAccessibility") + private void onSetListener() { + binding.llRecord.setOnClickListener(this); + binding.ivTryListen.setOnClickListener(this); + binding.ivRetryRecord.setOnClickListener(this); + binding.ivRecordSave.setOnClickListener(this); + binding.ivRecord.setOnTouchListener((v, event) -> { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + RoomInfo current = AvRoomDataManager.get().mCurrentRoomInfo; + if (current != null) { + getDialogManager().showOkCancelDialog(ResUtil.getString(R.string.erban_audio_audiorecordactivity_01), + true, new DialogManager.OkCancelDialogListener() { + @Override + public void onCancel() { + } + + @Override + public void onOk() { + AvRoomModel.get().exitRoom(null); + } + }); + } else { + startVoice(); + } + return true; + case MotionEvent.ACTION_UP: + audioManager.stopRecord(false); + return true; + default: + } + return false; + }); + + binding.imgBack.setOnClickListener(v -> finish()); + } + + private void startVoice() { + if (audioState == STATE_RECORD_RECORDING) { + toast(ResUtil.getString(R.string.erban_audio_audiorecordactivity_02)); + } else if (audioState == STATE_RECORD_NORMAL) { + audioState = STATE_RECORD_RECORDING; + showByState(audioState); + startChronometer(); + recorder = audioManager.getAudioRecorder(AudioRecordActivity.this, onRecordCallback); + audioManager.startRecord(); + } + } + + private void startChronometer() { + binding.tvChronometer.setVisibility(View.VISIBLE); + binding.tvChronometer.setFormat(""); + value = -1; + binding.tvChronometer.setOnChronometerTickListener(chronometerTickListener); + binding.tvChronometer.setBase(0); + binding.tvChronometer.start(); + } + + + private int audioState = STATE_RECORD_NORMAL; + + public static final int STATE_RECORD_RECORDING = 1; + public static final int STATE_RECORD_SUCCESS = 2; + public static final int STATE_RECORD_NORMAL = 0; + + private File audioFile; + + private int audioDura; + + IAudioRecordCallback onRecordCallback = new IAudioRecordCallback() { + @Override + public void onRecordReady() { + Log.d(TAG, "onRecordReady"); + } + + @Override + public void onRecordStart(File file, RecordType recordType) { + Log.d(TAG, "onRecordStart : " + file.getPath() + "type: " + recordType.name()); + } + + @Override + public void onRecordSuccess(File file, long l, RecordType recordType) { + double dura = (double) l / 1000; + audioDura = (int) Math.round(dura); + Log.d(TAG, "onRecordSuccess : " + file.getPath() + "lenth :" + audioDura + "type : " + recordType.name()); + toast(ResUtil.getString(R.string.erban_audio_audiorecordactivity_03)); + audioFile = file; + audioState = STATE_RECORD_SUCCESS; + showByState(audioState); + } + + @Override + public void onRecordFail() { + Log.d(TAG, "onRecordFail"); + toast(ResUtil.getString(R.string.erban_audio_audiorecordactivity_04)); + + audioState = STATE_RECORD_NORMAL; + showByState(audioState); + } + + @Override + public void onRecordCancel() { + Log.d(TAG, "onRecordCancel"); + audioState = STATE_RECORD_NORMAL; + showByState(audioState); + } + + @Override + public void onRecordReachedMaxTime(int i) { + Log.d(TAG, "onRecordReachedMaxTime"); + double dura = (double) i / 1000; + int max = (int) Math.round(dura); + toast(ResUtil.getString(R.string.erban_audio_audiorecordactivity_05)); + } + }; + + private void showByState(int state) { + if (state == STATE_RECORD_NORMAL) { + + binding.ivRecord.setImageResource(R.drawable.icon_record); + binding.ivRecord.setVisibility(View.VISIBLE); + binding.ivRecordSave.setVisibility(View.GONE); + binding.tvState.setVisibility(View.VISIBLE); + binding.tvState.setText(ResUtil.getString(R.string.erban_audio_audiorecordactivity_06)); + binding.tvChronometer.setVisibility(View.INVISIBLE); + binding.ivRetryRecord.setVisibility(View.GONE); + binding.ivTryListen.setVisibility(View.GONE); + + } else if (state == STATE_RECORD_RECORDING) { + + binding.ivRecord.setImageResource(R.drawable.icon_recording); + binding.ivRecord.setVisibility(View.VISIBLE); + binding.ivRecordSave.setVisibility(View.GONE); + binding.tvState.setVisibility(View.VISIBLE); + binding.tvState.setText(ResUtil.getString(R.string.erban_audio_audiorecordactivity_07)); + binding.tvChronometer.setVisibility(View.VISIBLE); + binding.ivRetryRecord.setVisibility(View.GONE); + binding.ivTryListen.setVisibility(View.GONE); + + } else if (state == STATE_RECORD_SUCCESS) { + binding.ivRecord.setVisibility(View.GONE); + binding.ivRecordSave.setVisibility(View.VISIBLE); + binding.tvState.setVisibility(View.INVISIBLE); + binding.ivRetryRecord.setVisibility(View.VISIBLE); + binding.tvChronometer.setVisibility(View.INVISIBLE); + binding.tvChronometer.stop(); + binding.ivTryListen.setVisibility(View.VISIBLE); + + } + } + + OnPlayListener onPlayListener = new OnPlayListener() { + + @Override + public void onPrepared() { + Log.d(TAG, "onPrepared"); + binding.ivTryListen.setImageResource(R.drawable.icon_try_listen_pause); + } + + @Override + public void onCompletion() { + Log.d(TAG, "onCompletion"); + binding.ivTryListen.setImageResource(R.drawable.icon_try_listen); + } + + @Override + public void onInterrupt() { + Log.d(TAG, "onInterrupt"); + binding.ivTryListen.setImageResource(R.drawable.icon_try_listen_pause); + } + + @Override + public void onError(String s) { + Log.d(TAG, "onError :" + s); + binding.ivTryListen.setImageResource(R.drawable.icon_try_listen); + } + + @Override + public void onPlaying(long l) { + Log.d(TAG, "onPlaying :" + l); + binding.ivTryListen.setImageResource(R.drawable.icon_try_listen_pause); + } + }; + + @SuppressLint("CheckResult") + @Override + public void onClick(View v) { + int id = v.getId(); + if(id == R.id.iv_retry_record){ + audioState = STATE_RECORD_NORMAL; + showByState(audioState); + if (null != recorder) { + recorder.destroyAudioRecorder(); + recorder = null; + } + } else if(id == R.id.iv_try_listen){ + if (!audioManager.isPlaying()) { + if (null != audioFile && audioFile.exists()) { + MLog.debug(TAG, "play audioFilePath: " + audioFile.getPath()); + audioPlayer.setDataSource(audioFile.getPath()); + audioManager.play(); + binding.ivTryListen.setImageResource(R.drawable.icon_try_listen_pause); + } + } else { + audioManager.stopPlay(); + binding.ivTryListen.setImageResource(R.drawable.icon_try_listen); + } + } else if(id == R.id.iv_record_save){ + if (null != audioFile) { + Log.i("result_url", "upload before:" + audioFile.getAbsolutePath()); + getDialogManager().showProgressDialog(AudioRecordActivity.this, ResUtil.getString(R.string.erban_audio_audiorecordactivity_08)); + FileModel.get() + .uploadFile(audioFile.getAbsolutePath()) + .compose(bindToLifecycle()) + .subscribe((url, throwable) -> { + if (throwable != null) { + onUploadFail(); + } else { + onUpload(url); + } + }); + } + } + } + + long value = -1; + + Chronometer.OnChronometerTickListener chronometerTickListener = new Chronometer.OnChronometerTickListener() { + + @Override + public void onChronometerTick(Chronometer chronometer) { + if (value == -1) { + // chronometer.setBase(0); // the base time value + value = chronometer.getBase(); + } else { + value++; // timer add + } + if (value > 10) { + audioManager.stopRecord(false); + return; + } + + String time; + if (value < 10) { + time = "00:0" + value; + } else { + time = "00:" + value; + } + chronometer.setText(time); + } + }; + + @Override + protected void onDestroy() { + if (audioManager.isPlaying()) { + audioManager.stopPlay(); + } + if (onPlayListener != null) { + onPlayListener = null; + } + if (audioPlayer != null) { + audioPlayer.setOnPlayListener(null); + } + if (audioManager != null) + audioManager.release(); + super.onDestroy(); + } + + private void onUpload(String url) { + audioUrl = url; + Log.i("result_url", "upload success:" + audioUrl); + UserInfo user = new UserInfo(); + user.setUid(AuthModel.get().getCurrentUid()); + user.setUserVoice(audioUrl); + user.setVoiceDura(audioDura); + UserModel.get().requestUpdateUserInfo(user).subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) { + mCompositeDisposable.add(d); + } + + @Override + public void onSuccess(UserInfo userInfo) { + onRequestUserInfoUpdate(); + } + + @Override + public void onError(Throwable e) { + onRequestUserInfoUpdateError(e.getMessage()); + } + }); + } + + private void onUploadFail() { + toast(ResUtil.getString(R.string.erban_audio_audiorecordactivity_09)); + getDialogManager().dismissDialog(); + } + + private void onRequestUserInfoUpdate() { + audioState = STATE_RECORD_NORMAL; + showByState(audioState); + getDialogManager().dismissDialog(); + + Intent intent = new Intent(); + intent.putExtra(AUDIO_FILE, audioUrl); + intent.putExtra(AUDIO_DURA, audioDura); + setResult(RESULT_OK, intent); + finish(); + } + + private void onRequestUserInfoUpdateError(String error) { + toast(error); + getDialogManager().dismissDialog(); + } + +} diff --git a/app/src/main/java/com/chwl/app/audio/MyVoiceActivity.java b/app/src/main/java/com/chwl/app/audio/MyVoiceActivity.java new file mode 100644 index 0000000..11fde30 --- /dev/null +++ b/app/src/main/java/com/chwl/app/audio/MyVoiceActivity.java @@ -0,0 +1,227 @@ +package com.chwl.app.audio; + +import android.Manifest; +import android.annotation.SuppressLint; +import android.content.Intent; +import android.graphics.Color; +import android.os.Bundle; +import android.view.View; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.chwl.app.R; +import com.chwl.app.UIHelper; +import com.chwl.app.audio.adapter.MyVoiceListAdapter; +import com.chwl.app.audio.helper.AudioPlayerHelper; +import com.chwl.app.audio.presenter.MyVoicePresenter; +import com.chwl.app.audio.view.IMyVoiceView; +import com.chwl.app.base.BaseMvpActivity; +import com.chwl.app.common.NoDataFragment; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.ui.widget.recyclerview.decoration.HorizontalDecoration; +import com.chwl.core.audio.bean.UserVoiceInfo; +import com.chwl.library.base.factory.CreatePresenter; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.log.MLog; + +import java.util.List; + +/** + * 我的声音页面 + */ +@CreatePresenter(MyVoicePresenter.class) +public class MyVoiceActivity extends BaseMvpActivity + implements IMyVoiceView { + + public static final int REQUEST_CODE_RECORDING_VOICE = 1; + + private RecyclerView recyclerView; + + private MyVoiceListAdapter adapter;// 审核通过列表 + private boolean isPlaying; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_my_voice); + getMvpPresenter().attachMvpView(this); + + AudioPlayerHelper.get().onCreate(); + initTitleBar(ResUtil.getString(R.string.erban_audio_myvoiceactivity_01)); + findView(); + initView(); + getMvpPresenter().getUserVoiceInfo(); + } + + private void findView() { + recyclerView = findViewById(R.id.recycler_view); + } + + @SuppressLint("CheckResult") + private void initView() { + if (adapter == null) { + adapter = new MyVoiceListAdapter(null); + } + recyclerView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)); + recyclerView.addItemDecoration(new HorizontalDecoration(UIUtil.dip2px(context, 15), false, false)); + recyclerView.setAdapter(adapter); + adapter.setOnVerifiedVoiceItemClickListener((isChange, voice) -> { + if (AudioPlayerHelper.get().isPlaying()) { + // 正在播放声音时:点了同一个声音,则停止播放;点了别的声音,则先停止播放 再播放新点击的声音 + stopVoice(); + isPlaying = false; + if (isChange) { + playVoice(voice); + } + } else { + isPlaying = true; + // 没有在播放声音时候,即正常状态 + playVoice(voice); + } + }); + adapter.setOnItemChildClickListener((adapter1, view, position) -> { + UserVoiceInfo item = (UserVoiceInfo) adapter1.getItem(position); + if (view.getId() == R.id.tv_re_recording) { + checkPermission(Manifest.permission.RECORD_AUDIO) + .subscribe(result -> { + if (result) { + UIHelper.showRecordVoiceAct(MyVoiceActivity.this, + MyVoiceActivity.REQUEST_CODE_RECORDING_VOICE, item.getId());// 点击跳转到录制声音页面 + } + }); + } + }); + } + + private void playVoice(String voice) { +// AudioEngineManager.get().setOpenVoiceMatchActivity(true); +// PlayerModel.get().pause(); + AudioPlayerHelper.get().playInThread(voice, new com.chwl.app.audio.helper.OnPlayListener() { + @Override + public void onError(String error) { + if (adapter != null) { + adapter.changePlayState(false);// 播放出错 + } + } + + @Override + public void onPrepared() { + if (adapter != null) { + adapter.changePlayState(true);// 准备完毕开始播放 + } + } + + @Override + public void onPlaying(long currDuration) { + + } + + @Override + public void onCompletion() { +// AudioEngineManager.get().setOpenVoiceMatchActivity(false); +// PlayerModel.get().play(null); + if (adapter != null) { + adapter.changePlayState(false);// 播放完成 + } + } + }); + } + + private void stopVoice() { +// AudioEngineManager.get().setOpenVoiceMatchActivity(false); +// PlayerModel.get().play(null); + AudioPlayerHelper.get().endPlay(); + adapter.changePlayState(false);// 点击停止播放 + } + + @Override + public void initTitleBar(String title) { + mTitleBar = findViewById(R.id.title_bar); + if (mTitleBar != null) { + if (needSteepStateBar()) { + mTitleBar.setImmersive(true); + } else { + mTitleBar.setImmersive(false); + } + mTitleBar.setTitle(title); + mTitleBar.setBackgroundColor(Color.TRANSPARENT); + mTitleBar.setTitleColor(Color.WHITE); + mTitleBar.setLeftImageResource(R.drawable.arrow_left); + mTitleBar.setLeftClickListener(v -> onLeftClickListener()); + } + } + + @Override + public void showNoData() { + if (!checkActivityValid()) { + return; + } + View status = findViewById(R.id.status_layout); + if (status == null) { + MLog.error(this, "xuwakao, had not set layout id "); + return; + } + @SuppressLint("CheckResult") NoDataFragment fragment = NoDataFragment.newInstance(R.layout.fragment_no_data_green_with_button, + R.drawable.icon_common_failure_green, ResUtil.getString(R.string.erban_audio_myvoiceactivity_03), () -> { + checkPermission(Manifest.permission.RECORD_AUDIO) + .subscribe(result -> { + if (result) { + // 录制入口 + UIHelper.showRecordVoiceAct(this, REQUEST_CODE_RECORDING_VOICE, -1); + } + }); + }); + getSupportFragmentManager().beginTransaction().replace(status.getId(), fragment, STATUS_TAG).commitAllowingStateLoss(); + } + + @Override + protected void onPause() { + super.onPause(); + AudioPlayerHelper.get().onPause(); + adapter.changePlayState(false);// onPause() 停止播放 + } + + @Override + protected void onDestroy() { + super.onDestroy(); +// if (isPlaying) { +// PlayerModel.get().play(null); +// } +// AudioEngineManager.get().setOpenVoiceMatchActivity(false); + AudioPlayerHelper.get().onDestroy(); + adapter.changePlayState(false);// onDestroy() 停止播放 + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (resultCode == RESULT_OK) { + if (requestCode == REQUEST_CODE_RECORDING_VOICE) { + setResult(RESULT_OK, data);// 传给上一个 + getMvpPresenter().getUserVoiceInfo(); + } + } + } + + @Override + public void showVoiceInfo(List voiceList) { + if (ListUtils.isListEmpty(voiceList)) { + showNoData(); + } else { + hideStatus(); + adapter.setNewData(voiceList);// 审核通过列表 + } + } + + @Override + public void showLoadingView() { + getDialogManager().showProgressDialog(context, ResUtil.getString(R.string.erban_audio_myvoiceactivity_05)); + } + + @Override + public void hideLoadingView() { + getDialogManager().dismissDialog(); + } +} diff --git a/app/src/main/java/com/chwl/app/audio/RecordingVoiceActivity.java b/app/src/main/java/com/chwl/app/audio/RecordingVoiceActivity.java new file mode 100644 index 0000000..d114a07 --- /dev/null +++ b/app/src/main/java/com/chwl/app/audio/RecordingVoiceActivity.java @@ -0,0 +1,478 @@ +package com.chwl.app.audio; + +import static com.chwl.app.audio.presenter.RecordingVoicePresenter.STATE_RECORD_NORMAL; +import static com.chwl.app.audio.presenter.RecordingVoicePresenter.STATE_RECORD_RECORDING; +import static com.chwl.app.audio.presenter.RecordingVoicePresenter.STATE_RECORD_SUCCESS; + +import android.Manifest; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.annotation.SuppressLint; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.os.SystemClock; +import android.util.Log; +import android.view.View; +import android.widget.Chronometer; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.core.content.ContextCompat; +import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.recyclerview.widget.ItemTouchHelper; +import androidx.recyclerview.widget.RecyclerView; + +import com.chwl.app.R; +import com.chwl.app.audio.adapter.CardAdapter; +import com.chwl.app.audio.helper.AudioPlayerHelper; +import com.chwl.app.audio.presenter.RecordingVoicePresenter; +import com.chwl.app.audio.view.IRecordingVoiceView; +import com.chwl.app.audio.widget.OnSwipeListener; +import com.chwl.app.audio.widget.RingProgressView; +import com.chwl.app.audio.widget.VoiceCardConfig; +import com.chwl.app.audio.widget.VoiceCardItemTouchHelperCallback; +import com.chwl.app.audio.widget.VoiceCardLayoutManager; +import com.chwl.app.audio.widget.VoiceCardRecyclerView; +import com.chwl.app.audio.widget.VoiceWave; +import com.chwl.app.base.BaseMvpActivity; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.core.audio.bean.VoiceCardInfo; +import com.chwl.core.room.model.AvRoomModel; +import com.chwl.library.base.factory.CreatePresenter; +import com.chwl.library.utils.ResUtil; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +/** + * 录制声音页面 + */ +@CreatePresenter(RecordingVoicePresenter.class) +public class RecordingVoiceActivity extends BaseMvpActivity + implements IRecordingVoiceView, View.OnClickListener { + + public static final String EXTRA_VOICE_ID = "voice_id"; + + public static final String AUDIO_FILE = "AUDIO_FILE"; + public static final String AUDIO_DURA = "AUDIO_DURA"; + + /*时长限制:大于等于5s,小于等于60s*/ + public static final int MIN_RECORD_VOICE_DURATION = 5;// 最少5秒 + public static final int MAX_RECORD_VOICE_DURATION = 60;// 最多60秒 + + private VoiceCardRecyclerView recyclerViewCard; + private TextView tvRecordHint; + private Chronometer tvRecordChronometer; + private TextView tvRecordLeftIcon; + private RingProgressView viewProgress; + private ImageView ivRecordCenterIcon; + private TextView tvRecordRightIcon; + private VoiceWave voiceWave; + + private CardAdapter cardAdapter; + private long lastClickTime; + private List voiceCardInfoList; + + private Drawable playDrawable, pauseDrawable; + private ItemTouchHelper touchHelper; + private VoiceCardItemTouchHelperCallback itemTouchHelperCallback; + + private long changeVoiceId = -1;// 被重新录制的声音的ID + private RecordingVoiceHandler voiceHandler; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_recording_voice); + getMvpPresenter().attachMvpView(this); + + AudioPlayerHelper.get().onCreate(); + initTitleBar(ResUtil.getString(R.string.erban_audio_recordingvoiceactivity_01)); + + findView(); + initView(); + initData(); + setListener(); + } + + private void findView() { + recyclerViewCard = findViewById(R.id.recycler_view_card); + tvRecordHint = findViewById(R.id.tv_record_hint); + tvRecordChronometer = findViewById(R.id.tv_record_chronometer); + tvRecordLeftIcon = findViewById(R.id.tv_record_left_icon); + viewProgress = findViewById(R.id.view_progress); + ivRecordCenterIcon = findViewById(R.id.iv_record_center_icon); + tvRecordRightIcon = findViewById(R.id.tv_record_right_icon); + voiceWave = findViewById(R.id.voice_wave); + } + + private void initView() { + lastClickTime = System.currentTimeMillis(); + voiceCardInfoList = new ArrayList<>(); + cardAdapter = new CardAdapter(voiceCardInfoList); + recyclerViewCard.setItemAnimator(new DefaultItemAnimator()); + recyclerViewCard.setAdapter(cardAdapter); + itemTouchHelperCallback = new VoiceCardItemTouchHelperCallback(); + itemTouchHelperCallback.setOnSwipedListener(new OnSwipeListener() { + @Override + public void onSwiping(RecyclerView.ViewHolder viewHolder, float ratio, int direction) { + Log.e("OnSwipeListener", "onSwiping--->" + "VH = " + viewHolder + + ResUtil.getString(R.string.erban_audio_recordingvoiceactivity_02) + ratio + + ResUtil.getString(R.string.erban_audio_recordingvoiceactivity_03) + (direction == VoiceCardConfig.SWIPING_LEFT ? ResUtil.getString(R.string.erban_audio_recordingvoiceactivity_04) : direction == VoiceCardConfig.SWIPING_RIGHT ? ResUtil.getString(R.string.erban_audio_recordingvoiceactivity_05) : ResUtil.getString(R.string.erban_audio_recordingvoiceactivity_06))); + viewHolder.itemView.setAlpha(1 - Math.abs(ratio) * 0.2f); + } + + @Override + public void onSwiped(RecyclerView.ViewHolder viewHolder, int pos, int direction) { + Log.e("OnSwipeListener", "onSwiped--->" + "VH = " + viewHolder + + ResUtil.getString(R.string.erban_audio_recordingvoiceactivity_07) + pos + + ResUtil.getString(R.string.erban_audio_recordingvoiceactivity_08) + (direction == VoiceCardConfig.SWIPED_LEFT ? ResUtil.getString(R.string.erban_audio_recordingvoiceactivity_09) : direction == VoiceCardConfig.SWIPED_RIGHT ? ResUtil.getString(R.string.erban_audio_recordingvoiceactivity_010) : ResUtil.getString(R.string.erban_audio_recordingvoiceactivity_011))); + viewHolder.itemView.setAlpha(1f); + cardAdapter.removeItem(pos); + if (cardAdapter.getItemCount() < VoiceCardConfig.DEFAULT_SHOW_ITEM) { + recyclerViewCard.post(() -> getMvpPresenter().getCardInfo()); + } + } + }); + touchHelper = new ItemTouchHelper(itemTouchHelperCallback); + VoiceCardLayoutManager cardLayoutManager = new VoiceCardLayoutManager(recyclerViewCard, touchHelper); + recyclerViewCard.setLayoutManager(cardLayoutManager); + // 这里开始就把 它 自己的 onTouchListener 给 RecyclerView,然后用 GestureDetectorCompat 来处理那些分发下来的事件。 + // 也就是说要防止快速点击,1要防止按钮的快速点击 2要防止动画过程中 GestureDetectorCompat 继续响应你的快速点击手势 + // 1处理就直接disable那个按钮 2就是拦截掉 RecyclerView 的 onTouchEvent 方法 用 mLayoutFrozen 属性,直接用这个就行了 我试试看 + touchHelper.attachToRecyclerView(recyclerViewCard); + cardAdapter.setOnVoiceCardChangeButtonClickListener(new CardAdapter.OnVoiceCardChangeButtonClickListener() { + @Override + public void onVoiceCardChange(RecyclerView.ViewHolder viewHolder) { + long currTime = System.currentTimeMillis(); + if (currTime - lastClickTime < 1000) { + return; + } + lastClickTime = currTime; + recyclerViewCard.setLayoutFrozen(true); + recyclerViewCard.post(new Runnable() { + @Override + public void run() { + ValueAnimator mValueAnimator = ValueAnimator.ofFloat(0.0F, 1.0F); + mValueAnimator.setTarget(viewHolder.itemView); + mValueAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + super.onAnimationStart(animation); + touchHelper.startSwipe(viewHolder); + } + + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + } + }); + mValueAnimator.addUpdateListener(valueAnimator -> { + float fraction = valueAnimator.getAnimatedFraction(); + if (fraction == 1) { + itemTouchHelperCallback.onSwiped(viewHolder, ItemTouchHelper.LEFT); + recyclerViewCard.setLayoutFrozen(false); + } else { + itemTouchHelperCallback.onChildDraw(recyclerViewCard.getCanvas(), + recyclerViewCard, viewHolder, + -viewHolder.itemView.getWidth() * fraction, + viewHolder.itemView.getTranslationY(), 1, false); + } + }); + mValueAnimator.setDuration(500); + mValueAnimator.start(); + } + }); + } + }); + + playDrawable = ContextCompat.getDrawable(context, R.drawable.ic_recording_listener); + pauseDrawable = ContextCompat.getDrawable(context, R.drawable.ic_recording_pause); + + refreshButtonView(STATE_RECORD_NORMAL); + } + + private void initData() { + if (getIntent() != null) { + changeVoiceId = getIntent().getLongExtra(EXTRA_VOICE_ID, changeVoiceId); + } + + getMvpPresenter().initResource(); + getMvpPresenter().getCardInfo(); + } + + private void setListener() { + tvRecordLeftIcon.setOnClickListener(this); + ivRecordCenterIcon.setOnClickListener(this); + tvRecordRightIcon.setOnClickListener(this); + } + + @Override + public void initTitleBar(String title) { + mTitleBar = findViewById(R.id.title_bar); + if (mTitleBar != null) { + if (needSteepStateBar()) { + mTitleBar.setImmersive(true); + } else { + mTitleBar.setImmersive(false); + } + mTitleBar.setTitle(title); + mTitleBar.setBackgroundColor(Color.TRANSPARENT); + mTitleBar.setTitleColor(Color.WHITE); + mTitleBar.setLeftImageResource(R.drawable.arrow_left); + mTitleBar.setLeftClickListener(v -> onLeftClickListener()); + } + } + + @Override + protected void onLeftClickListener() { + getMvpPresenter().leaveThePage(); + } + + @Override + public void onBackPressed() { + onLeftClickListener();// 物理返回 + } + + @Override + protected void onPause() { + super.onPause(); + getMvpPresenter().pausePage(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + getMvpPresenter().releaseResource(); + } + + @SuppressLint("CheckResult") + @Override + public void onClick(View view) { + int id = view.getId(); + if (id == R.id.tv_record_left_icon) { + getMvpPresenter().reRecord(); + } else if (id == R.id.iv_record_center_icon) { + if (!(ContextCompat.checkSelfPermission(context, Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED)) { + checkPermission(Manifest.permission.RECORD_AUDIO) + .subscribe(aBoolean -> { + if (aBoolean) { + getMvpPresenter().clickCenterIcon(); + } else { + toast(ResUtil.getString(R.string.erban_audio_recordingvoiceactivity_013)); + } + }); + return; + } + getMvpPresenter().clickCenterIcon(); + } else if (id == R.id.tv_record_right_icon) { + getMvpPresenter().clickRightIcon(); + } + } + + @Override + public void addCardInfo(List cardInfoList) { + voiceCardInfoList.addAll(cardInfoList); + cardAdapter.notifyDataSetChanged(); + } + + @Override + public Long getCardPiaId() { + VoiceCardInfo itemInfo = cardAdapter.getFistItemInfo(); + if (itemInfo == null) { + return null; + } else { + return itemInfo.getId(); + } + } + + @Override + public void refreshButtonView(int state) { + switch (state) { + case STATE_RECORD_NORMAL:// 正常默认情况下 + viewProgress.setVisibility(View.INVISIBLE); + ivRecordCenterIcon.post(() -> ivRecordCenterIcon.setImageResource(R.drawable.ic_recording)); + tvRecordHint.setText(ResUtil.getString(R.string.erban_audio_recordingvoiceactivity_014)); + tvRecordHint.setVisibility(View.VISIBLE); + tvRecordChronometer.setVisibility(View.INVISIBLE); + tvRecordLeftIcon.setVisibility(View.INVISIBLE); + tvRecordRightIcon.setVisibility(View.INVISIBLE); + break; + case STATE_RECORD_RECORDING:// 正在录音时 + viewProgress.setVisibility(View.VISIBLE); + ivRecordCenterIcon.post(() -> ivRecordCenterIcon.setImageResource(R.drawable.ic_recording_end)); + tvRecordHint.setVisibility(View.GONE); + tvRecordChronometer.setVisibility(View.VISIBLE); + tvRecordLeftIcon.setVisibility(View.INVISIBLE); + tvRecordRightIcon.setVisibility(View.INVISIBLE); + break; + case STATE_RECORD_SUCCESS:// 已经录制时 + viewProgress.setVisibility(View.INVISIBLE); + ivRecordCenterIcon.post(() -> ivRecordCenterIcon.setImageResource(R.drawable.ic_recording_finish)); + tvRecordHint.setVisibility(View.GONE); + tvRecordChronometer.setVisibility(View.VISIBLE); + tvRecordLeftIcon.setVisibility(View.VISIBLE); + tvRecordRightIcon.post(() -> + tvRecordRightIcon.setCompoundDrawablesWithIntrinsicBounds(null, playDrawable, null, null)); + tvRecordRightIcon.setText(ResUtil.getString(R.string.erban_audio_recordingvoiceactivity_015)); + tvRecordRightIcon.setVisibility(View.VISIBLE); + break; + } + } + + @Override + public void refreshListenerButton(boolean isPlaying) { + tvRecordRightIcon.setText(isPlaying ? ResUtil.getString(R.string.erban_audio_recordingvoiceactivity_016) : ResUtil.getString(R.string.erban_audio_recordingvoiceactivity_017)); + tvRecordRightIcon.post(() -> + tvRecordRightIcon.setCompoundDrawablesWithIntrinsicBounds(null, isPlaying ? pauseDrawable : playDrawable, null, null)); + } + + @Override + public void startChronometer() { + tvRecordHint.setVisibility(View.GONE); + tvRecordChronometer.setVisibility(View.VISIBLE); +// tvRecordChronometer.setFormat(""); + tvRecordChronometer.setOnChronometerTickListener(chronometer -> { + long elapsedMillis = SystemClock.elapsedRealtime() - chronometer.getBase(); + int second = (int) (elapsedMillis / 1000); + String showStr = String.format(Locale.getDefault(), "%ds / %ds", second, MAX_RECORD_VOICE_DURATION); + chronometer.setText(showStr); +// Log.e("RecordingView", "elapsedMillis = " + elapsedMillis +// + " second = " + second +// + " show = " + showStr); + viewProgress.post(() -> { + int currentProgress = 100 * second / MAX_RECORD_VOICE_DURATION; + viewProgress.setCurrentProgress(currentProgress); + }); + + if (second >= MAX_RECORD_VOICE_DURATION) { + getMvpPresenter().stopRecord();// 录制时长超过上限时,停止录制 + } + + }); + tvRecordChronometer.setBase(SystemClock.elapsedRealtime()); + tvRecordChronometer.start(); + } + + @Override + public void stopChronometer() { + tvRecordChronometer.stop(); + } + + @Override + public void showConfirmDialogWithLeave() { + getDialogManager().showOkCancelDialog(ResUtil.getString(R.string.erban_audio_recordingvoiceactivity_018), + getString(R.string.voice_tips_save_voice), + ResUtil.getString(R.string.erban_audio_recordingvoiceactivity_019), ResUtil.getString(R.string.erban_audio_recordingvoiceactivity_020), false, true, new DialogManager.OkCancelDialogListener() { + @Override + public void onOk() { + + } + + @Override + public void onCancel() { + finishView(null);// 声音未保存确认退出页面 + } + }); + } + + @Override + public void finishView(Intent intent) { + if (intent != null) { + setResult(RESULT_OK, intent); + } + finish(); + } + + @Override + public void showConfirmDialogWithExitRoom() { + getDialogManager().showOkCancelDialog(ResUtil.getString(R.string.erban_audio_recordingvoiceactivity_021), + true, new DialogManager.OkCancelDialogListener() { + @Override + public void onCancel() { + } + + @Override + public void onOk() { + AvRoomModel.get().exitRoom(null); + } + }); + } + + @Override + public void showLoadingView() { + runOnUiThread(() -> getDialogManager().showProgressDialog(context, ResUtil.getString(R.string.erban_audio_recordingvoiceactivity_022))); + } + + @Override + public void hideLoadingView() { + runOnUiThread(() -> getDialogManager().dismissDialog()); + } + + @Override + public Long getChangeVoiceId() { + if (changeVoiceId == -1) { + return null; + } + return changeVoiceId; + } + + @Override + public void refreshVoiceWave(double db) { + if (voiceHandler != null) { + voiceHandler.sendEmptyMessage((int) db); + } + } + + @Override + public void showVoiceWave() { + voiceWave.setVisibility(View.VISIBLE); + voiceWave.startAnim(); + voiceHandler = new RecordingVoiceHandler(this); + // 解决了内存泄漏,延迟5分钟后发送 + voiceHandler.sendEmptyMessage(0); + } + + @Override + public void hideVoiceWave() { + voiceWave.stopAnim(); + voiceWave.setVisibility(View.INVISIBLE); + if (voiceHandler != null) { + voiceHandler.removeCallbacksAndMessages(null); + } + } + + @Override + public void showCountDown(int duration) { + tvRecordChronometer.setVisibility(View.VISIBLE); + String showStr = String.format(Locale.getDefault(), "%ds / %ds", duration, MAX_RECORD_VOICE_DURATION); + tvRecordChronometer.setText(showStr); + } + + private static class RecordingVoiceHandler extends Handler { + // 持有弱引用 Activity,GC回收时会被回收掉. + private final WeakReference mActivity; + + RecordingVoiceHandler(RecordingVoiceActivity activityWeakReference) { + mActivity = new WeakReference<>(activityWeakReference); + } + + @Override + public void handleMessage(Message msg) { + RecordingVoiceActivity activity = mActivity.get(); + super.handleMessage(msg); + if (activity != null) { + activity.voiceWave.setVolume(msg.what); + } + } + } + +} diff --git a/app/src/main/java/com/chwl/app/audio/SoundSignatureActivity.kt b/app/src/main/java/com/chwl/app/audio/SoundSignatureActivity.kt new file mode 100644 index 0000000..242a6f0 --- /dev/null +++ b/app/src/main/java/com/chwl/app/audio/SoundSignatureActivity.kt @@ -0,0 +1,533 @@ +package com.chwl.app.audio + +import android.Manifest +import android.annotation.SuppressLint +import android.content.Intent +import android.content.pm.PackageManager +import android.graphics.drawable.Drawable +import android.os.SystemClock +import android.util.Log +import android.view.View +import android.widget.Chronometer +import android.widget.Chronometer.OnChronometerTickListener +import androidx.activity.viewModels +import androidx.core.content.ContextCompat +import com.netease.nim.uikit.StatusBarUtil +import com.opensource.svgaplayer.SVGADrawable +import com.opensource.svgaplayer.SVGAImageView +import com.opensource.svgaplayer.SVGAParser +import com.opensource.svgaplayer.SVGAVideoEntity +import com.chwl.app.R +import com.chwl.app.audio.helper.AudioPlayerHelper +import com.chwl.app.audio.viewmodel.SoundViewModel +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.databinding.ActivitySoundSignatureBinding +import com.chwl.app.ui.widget.dialog.CommonDialog +import com.chwl.core.file.FileModel +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.user.bean.UserInfo.SoundBean +import com.chwl.library.utils.ResUtil +import com.chwl.library.utils.SingleToastUtil +import io.reactivex.SingleObserver +import io.reactivex.disposables.Disposable +import java.util.* + + +/** + * @author wushaocheng + * 声音签名 + */ +class SoundSignatureActivity : BaseViewBindingActivity(), + View.OnClickListener { + + companion object { + const val AUDIO_BEAN = "audio_bean" + const val AUDIO_FILE = "audio_file" + const val AUDIO_DURA = "audio_dura" + const val MIN_RECORD_VOICE_DURATION = 1 // 最少1秒 + var MAX_RECORD_VOICE_DURATION = 60 //最多60s + } + + private val soundViewModel: SoundViewModel by viewModels() + + private var playDrawable: Drawable? = null + private var pauseDrawable: Drawable? = null + + private var mCountDownTime = 0 + + private var timer: Timer? = null + + override fun init() { + AudioPlayerHelper.get().onCreate() + initWhiteTitleBar(getString(R.string.sound_signature)) + + initView() + setListener() + initModel() + } + + private fun initView() { + playDrawable = ContextCompat.getDrawable(context, R.drawable.ic_pause_record) + pauseDrawable = ContextCompat.getDrawable(context, R.drawable.ic_resume_record) + + val audioCard = intent.getSerializableExtra(AUDIO_BEAN) as SoundBean + when (audioCard.status ?: 0) { + 0 -> { + refreshButtonView(SoundViewModel.STATE_RECORD_NORMAL) + } + 1 -> { + MAX_RECORD_VOICE_DURATION = audioCard.second ?: 60 + binding.roundProgress.setTotalProgress((audioCard.second ?: 60) * 1000) + val showStr = String.format( + Locale.getDefault(), + "%ds / %ds", + 0, + MAX_RECORD_VOICE_DURATION + ) + binding.tvSoundTime.text = showStr + soundViewModel.audioState = SoundViewModel.STATE_RECORD_SAVE_SUCCESS + soundViewModel.audioUrl = audioCard.audioUrl ?: "" + refreshButtonView(SoundViewModel.STATE_RECORD_SAVE_SUCCESS) + } + 2 -> { + MAX_RECORD_VOICE_DURATION = audioCard.second ?: 60 + binding.roundProgress.setTotalProgress((audioCard.second ?: 60) * 1000) + val showStr = String.format( + Locale.getDefault(), + "%ds / %ds", + 0, + MAX_RECORD_VOICE_DURATION + ) + binding.tvSoundTime.text = showStr + soundViewModel.audioState = SoundViewModel.STATE_RECORD_AUDIT_SUCCESS + soundViewModel.audioUrl = audioCard.audioUrl ?: "" + refreshButtonView(SoundViewModel.STATE_RECORD_AUDIT_SUCCESS) + } + else -> { + refreshButtonView(SoundViewModel.STATE_RECORD_NORMAL) + } + } + } + + private fun setListener() { + binding.ivSoundStatus.setOnClickListener(this)//中间按钮 + binding.frSaveRecord.setOnClickListener(this)//保存按钮 + binding.frDeleteBg.setOnClickListener(this)//删除按钮 + binding.frRestartBg.setOnClickListener(this)//重新录制按钮 + } + + private fun initModel() { + soundViewModel.showConfirmLiveData.observe(this) { + if(AvRoomDataManager.get().isOwnerOnMic) { + toast(getString(R.string.on_the_mic_not_record)) + } else { + soundViewModel.stopRoomSound() + soundViewModel.showRecordingState() + } + } + + soundViewModel.refreshLiveData.observe(this) { + refreshButtonView(it) + } + + soundViewModel.startChronometerLiveData.observe(this) { + startChronometer() + } + + soundViewModel.stopChronometerLiveData.observe(this) { + stopChronometer() + } + + soundViewModel.refreshPlayStatusLiveData.observe(this) { + refreshListenerButton(it) + } + + soundViewModel.resetStatusLiveData.observe(this) { + resetStatus() + } + + soundViewModel.showCountDownLiveData.observe(this) { + showCountDown(it) + } + + soundViewModel.finishViewLiveData.observe(this) { + finishView(it) + } + + soundViewModel.saveRecordLiveData.observe(this) { + hideLoad() + refreshButtonView(SoundViewModel.STATE_RECORD_SAVE_SUCCESS) + soundViewModel.audioState = SoundViewModel.STATE_RECORD_SAVE_SUCCESS + SingleToastUtil.showToast(getString(R.string.update_success)) + //设置最大计时数 + MAX_RECORD_VOICE_DURATION = soundViewModel.audioDur + binding.roundProgress.setTotalProgress(soundViewModel.audioDur * 1000) + val intent = Intent() + intent.putExtra(AUDIO_FILE, soundViewModel.audioUrl) + intent.putExtra(AUDIO_DURA, soundViewModel.audioDur) + setResult(RESULT_OK, intent)// 上传声音成功之后给上个页面传递信息 + } + + soundViewModel.hideLoadLiveData.observe(this) { + hideLoad() + } + + soundViewModel.loadingLiveData.observe(this) { loading -> + if (loading) dialogManager.showProgressDialog(this) + else dialogManager.dismissDialog() + } + + soundViewModel.deleteRecordLiveData.observe(this) { + val intent = Intent() + intent.putExtra(AUDIO_FILE, "") + intent.putExtra(AUDIO_DURA, 0) + setResult(RESULT_OK, intent)// 上传声音成功之后给上个页面传递信息 + soundViewModel.showNormalState() + } + + soundViewModel.showSaveConfirmDialogLiveData.observe(this) { + CommonDialog(this).apply { + setTipMsg(ResUtil.getString(R.string.sound_has_not_been_saved)) + setOnActionListener( + object : CommonDialog.OnActionListener { + override fun onOk() { + finishView(null) + } + } + ) + show() + } + } + + soundViewModel.showRecordConfirmDialogLiveData.observe(this) { + CommonDialog(this).apply { + setTipMsg(ResUtil.getString(R.string.sound_has_not_been_recorded_yet)) + setOnActionListener( + object : CommonDialog.OnActionListener { + override fun onOk() { + finishView(null) + } + } + ) + show() + } + } + + } + + private fun showLoad() { + runOnUiThread { + dialogManager.showProgressDialog( + context, + ResUtil.getString(R.string.erban_audio_recordingvoiceactivity_022) + ) + } + } + + private fun hideLoad() { + runOnUiThread { dialogManager.dismissDialog() } + } + + @SuppressLint("CheckResult") + override fun onClick(view: View?) { + when (view?.id) { + R.id.ivSoundStatus -> {//中间按钮 + if (ContextCompat.checkSelfPermission( + context, + Manifest.permission.RECORD_AUDIO + ) != PackageManager.PERMISSION_GRANTED + ) { + checkPermission(Manifest.permission.RECORD_AUDIO) + .subscribe { aBoolean: Boolean -> + if (aBoolean) { + soundViewModel.clickCenterIcon() + } else { + toast(ResUtil.getString(R.string.erban_audio_recordingvoiceactivity_013)) + } + } + return + } else { + soundViewModel.clickCenterIcon() + } + } + R.id.frSaveRecord -> {//保存按钮 + finishRecord() + } + R.id.frDeleteBg -> {//删除按钮 + deleteRecord() + } + R.id.frRestartBg -> {//重新录制按钮 + soundViewModel.reRecord() + } + } + } + + private fun deleteRecord() { + CommonDialog(this).apply { + setTipMsg(ResUtil.getString(R.string.sure_to_delete_sound)) + setOnActionListener( + object : CommonDialog.OnActionListener { + override fun onOk() { + soundViewModel.deleteRecord() + } + } + ) + show() + } + } + + /** + * 上传声音,完成录制 + */ + private fun finishRecord() { + soundViewModel.audioFile?.let { + Log.i("result_url", "upload before:" + it.absolutePath) + showLoad() + FileModel.get() + .uploadFile(it.absolutePath) + .compose(bindToLifecycle()) + .subscribe(object : SingleObserver { + override fun onSubscribe(d: Disposable) {} + override fun onSuccess(url: String) { + Log.i("result_url", "upload success:$url") + soundViewModel.saveRecord(url) + } + + override fun onError(e: Throwable) { + SingleToastUtil.showToast(ResUtil.getString(R.string.audio_presenter_recordingvoicepresenter_01)) + hideLoad()// 声音文件上传失败时 + } + }) + } + } + + private fun refreshButtonView(state: Int) { + when (state) { + SoundViewModel.STATE_RECORD_NORMAL -> { + MAX_RECORD_VOICE_DURATION = 60 + binding.roundProgress.setProgress(0) + binding.roundProgress.setTotalProgress(60000) + binding.tvRecordTip.text = getString(R.string.start_record) + val showStr = String.format( + Locale.getDefault(), + "%ds / %ds", + 0, + MAX_RECORD_VOICE_DURATION + ) + binding.tvSoundTime.text = showStr + binding.ivSoundStatus.post { binding.ivSoundStatus.setImageResource(R.drawable.ic_prepare_record) } + binding.groupRsRecord.visibility = View.INVISIBLE + binding.groupSaveSound.visibility = View.INVISIBLE + binding.groupDeleteSound.visibility = View.INVISIBLE + binding.tvUnderReview.visibility = View.INVISIBLE + stopSvga() + mCountDownTime = 0 + } + SoundViewModel.STATE_RECORD_RECORDING -> { + binding.ivSoundStatus.post { binding.ivSoundStatus.setImageResource(R.drawable.ic_start_record) } + binding.tvRecordTip.text = getString(R.string.click_stop) + binding.groupRsRecord.visibility = View.INVISIBLE + binding.groupSaveSound.visibility = View.INVISIBLE + binding.groupDeleteSound.visibility = View.INVISIBLE + binding.tvUnderReview.visibility = View.INVISIBLE + playSvgaBg(binding.svgRecorder, "svga/sound_record.svga") + } + SoundViewModel.STATE_RECORD_SUCCESS -> { + binding.ivSoundStatus.post { binding.ivSoundStatus.setImageResource(R.drawable.ic_pause_record) } + binding.tvRecordTip.text = getString(R.string.click_to_listen) + binding.groupRsRecord.visibility = View.VISIBLE + binding.groupSaveSound.visibility = View.VISIBLE + binding.groupDeleteSound.visibility = View.INVISIBLE + binding.tvUnderReview.visibility = View.INVISIBLE + stopSvga() + } + SoundViewModel.STATE_RECORD_SAVE_SUCCESS -> { + binding.ivSoundStatus.post { binding.ivSoundStatus.setImageResource(R.drawable.ic_pause_record) } + binding.tvRecordTip.text = getString(R.string.click_to_listen) + binding.groupRsRecord.visibility = View.VISIBLE + binding.groupSaveSound.visibility = View.INVISIBLE + binding.groupDeleteSound.visibility = View.VISIBLE + binding.tvUnderReview.visibility = View.VISIBLE + stopSvga() + } + SoundViewModel.STATE_RECORD_AUDIT_SUCCESS -> { + binding.ivSoundStatus.post { binding.ivSoundStatus.setImageResource(R.drawable.ic_pause_record) } + binding.tvRecordTip.text = getString(R.string.click_to_listen) + binding.groupRsRecord.visibility = View.VISIBLE + binding.groupSaveSound.visibility = View.INVISIBLE + binding.groupDeleteSound.visibility = View.VISIBLE + binding.tvUnderReview.visibility = View.GONE + stopSvga() + } + } + } + + private fun playSvgaBg(svgaBg: SVGAImageView, assets: String) { + val mSVGAParser = SVGAParser(svgaBg.context) + mSVGAParser.decodeFromAssets(assets, object : SVGAParser.ParseCompletion { + override fun onComplete(videoItem: SVGAVideoEntity) { + val drawable = SVGADrawable(videoItem) + svgaBg.setImageDrawable(drawable) + svgaBg.stepToFrame(0, true) + } + + override fun onError() { + } + + }, null) + } + + /** + * 开始录音 + */ + private fun startChronometer() { + startProgress() + binding.tvSoundTime.onChronometerTickListener = + OnChronometerTickListener { chronometer: Chronometer -> + val elapsedMillis = + SystemClock.elapsedRealtime() - chronometer.base + val second = (elapsedMillis / 1000).toInt() + val showStr = String.format( + Locale.getDefault(), + "%ds / %ds", + second, + MAX_RECORD_VOICE_DURATION + ) + chronometer.text = showStr + mCountDownTime = second + if (second >= MAX_RECORD_VOICE_DURATION) { + soundViewModel.stopRecord() // 录制时长超过上限时,停止录制 + } + } + binding.tvSoundTime.base = SystemClock.elapsedRealtime() + binding.tvSoundTime.start() + } + + private fun startProgress() { + var progress = 0 //进度条进度值 + timer = Timer() + timer?.schedule(object : TimerTask() { + override fun run() { + runOnUiThread { + progress += 16 + if (progress <= MAX_RECORD_VOICE_DURATION * 1000) { + if(mCountDownTime != 60 && soundViewModel.audioState == 1) { + binding.roundProgress.setProgress(progress) + } + } + } + } + }, 0, 16) //间隔时间(单位为毫秒) + } + + /** + * 停止录音 + */ + private fun stopChronometer() { + binding.tvSoundTime.stop() + timer?.cancel() + val showStr = String.format( + Locale.getDefault(), + "%ds / %ds", + 0, + mCountDownTime + ) + binding.tvSoundTime.text = showStr + binding.roundProgress.setProgress(0) + binding.roundProgress.setTotalProgress(mCountDownTime * 1000) + MAX_RECORD_VOICE_DURATION = mCountDownTime + soundViewModel.audioState = SoundViewModel.STATE_RECORD_SUCCESS + } + + /** + * 刷新试听按钮 + */ + private fun refreshListenerButton(isPlaying: Boolean) { + binding.tvRecordTip.text = if (isPlaying) ResUtil.getString(R.string.click_to_stop_playing) + else ResUtil.getString(R.string.click_to_listen) + binding.ivSoundStatus.post { + if (isPlaying) binding.ivSoundStatus.setImageResource(R.drawable.ic_resume_record) + else binding.ivSoundStatus.setImageResource(R.drawable.ic_pause_record) + if (isPlaying) { + playSvgaBg(binding.svgRecorder, "svga/sound_record.svga") + } else { + stopSvga() + } + } + } + + private fun resetStatus() { + binding.roundProgress.setProgress(0) + val showStr = String.format( + Locale.getDefault(), + "%ds / %ds", + 0, + MAX_RECORD_VOICE_DURATION + ) + binding.tvSoundTime.text = showStr + } + + private fun stopSvga() { + binding.svgRecorder.stopAnimation() + binding.svgRecorder.clear() + } + + /** + * 开始试听 + */ + private fun showCountDown(duration: Int) { + val dur = if (60000L - duration <= 500) { + (duration / 1000) + 1 + } else { + duration / 1000 + } + if (dur <= MAX_RECORD_VOICE_DURATION) { + val showStr = String.format( + Locale.getDefault(), + "%ds / %ds", + dur, + MAX_RECORD_VOICE_DURATION + ) + binding.roundProgress.setProgress(duration) + binding.tvSoundTime.text = showStr + } + } + + fun finishView(intent: Intent?) { + if (intent != null) { + setResult(RESULT_OK, intent) + } + finish() + } + + override fun onLeftClickListener() { + soundViewModel.leaveThePage() + } + + override fun onBackPressed() { + onLeftClickListener() // 物理返回 + } + + override fun onPause() { + super.onPause() + soundViewModel.pausePage() + } + + override fun onDestroy() { + super.onDestroy() + timer?.cancel() + mCountDownTime = 0 + soundViewModel.releaseResource() + stopSvga() + } + + override fun needSteepStateBar(): Boolean { + return true + } + + override fun setStatusBar() { + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/audio/VoiceMatchActivity.java b/app/src/main/java/com/chwl/app/audio/VoiceMatchActivity.java new file mode 100644 index 0000000..65e030d --- /dev/null +++ b/app/src/main/java/com/chwl/app/audio/VoiceMatchActivity.java @@ -0,0 +1,637 @@ +package com.chwl.app.audio; + +import android.content.Context; +import android.content.Intent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.AccelerateDecelerateInterpolator; +import android.view.animation.AlphaAnimation; +import android.view.animation.TranslateAnimation; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.opensource.svgaplayer.SVGACallback; +import com.trello.rxlifecycle3.android.ActivityEvent; +import com.chwl.app.R; +import com.chwl.app.UIHelper; +import com.chwl.app.audio.helper.AudioPlayerHelper; +import com.chwl.app.audio.helper.OnPlayListener; +import com.chwl.app.audio.helper.OnRefreshListener; +import com.chwl.app.audio.helper.SvgaCacheManager; +import com.chwl.app.audio.helper.VmSoundManager; +import com.chwl.app.audio.helper.VoiceMacthHelper; +import com.chwl.app.audio.view.IBottleOpListener; +import com.chwl.app.audio.widget.VoiceBottleFilterGenderBottomDialog; +import com.chwl.app.audio.widget.VoiceLine; +import com.chwl.app.base.BaseViewBindingActivity; +import com.chwl.app.base.TitleBar; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.app.databinding.ActivityVoiceMatchBinding; +import com.chwl.app.ui.im.avtivity.NimP2PMessageActivity; +import com.chwl.app.ui.widget.higuide.TuTuGuideHelper; +import com.chwl.core.audio.AudioModel; +import com.chwl.core.audio.bean.HistoryVoiceInfo; +import com.chwl.core.audio.bean.VoiceMatchInfo; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.music.model.PlayerModel; +import com.chwl.core.user.UserModel; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.core.utils.ActivityUtil; +import com.chwl.core.utils.SharedPreferenceUtils; +import com.chwl.core.utils.net.DontWarnObserver; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; + +import java.util.List; +import java.util.Locale; +import java.util.concurrent.TimeUnit; + +import io.reactivex.SingleSource; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.functions.Function; + +/** + * create by lvzebiao @2019/6/6 + */ +public class VoiceMatchActivity extends BaseViewBindingActivity implements View.OnClickListener { + + public static final String KEY_VOICE_MUST_LIMIT = "voice_must_limit_";// 是否受限,限制喜欢和不喜欢3次 + public static final String KEY_VOICE_LIMIT_COUNT = "voice_limit_count_of_";// 限制不喜欢的次数 + public static final int REQUEST_CODE_RECORDING_VOICE_WITH_HAS_LIMIT = 1; + public static final int REQUEST_CODE_RECORDING_VOICE_WITH_SYNC_HISTORY_VOICE = 2; + public static final int REQUEST_CODE_RECORDING_VOICE_WITH_MY_VOICE = 3; + + private ImageView playIcon; + private VoiceLine voiceLine; + + private boolean isLoading; + private boolean isFirst;// 记录是否首次进入页面 + + private VoiceMacthHelper helper = new VoiceMacthHelper(); + + private int filterGender;// 当前筛选的性别 + private VoiceBottleFilterGenderBottomDialog filterGenderBottomDialog; + private TranslateAnimation showAnim; + private AlphaAnimation alphaAnimation; + + public static void start(Context context) { + Intent intent = new Intent(context, VoiceMatchActivity.class); + context.startActivity(intent); + } + + @Override + public void init() { + VmSoundManager.get().onCreate(); + AudioPlayerHelper.get().onCreate(); + SvgaCacheManager.get().onCreate(); + initWhiteTitleBar(ResUtil.getString(R.string.erban_audio_voicematchactivity_01)); + + initView(); + UserInfo userInfo = UserModel.get().getCacheLoginUserInfo(); + if (userInfo == null) { + hideStatus(); + toast(ResUtil.getString(R.string.erban_audio_voicematchactivity_02)); + finish(); + return; + } + int oppositeGender = userInfo.getGender() == 1 ? 2 : 1; + filterGender = (int) SharedPreferenceUtils.get("voice_match_filter_gender_" + AuthModel.get().getCurrentUid(), oppositeGender); + isFirst = true; + loadingData(filterGender);// 进入页面加载数据 + + /*展示我的声音的入口动画*/ + showMyVoiceEntranceAnim(); + + binding.layoutMyVoiceEntrance.setOnClickListener(this); + + binding.flGroupContent.setOpListener(new IBottleOpListener() { + + @Override + public void onLimit(boolean isRight) { + showDialogWithHasLimit(isRight); + } + + @Override + public void onLikeOrUnLike(VoiceMatchInfo info, boolean isRight, boolean needLoading) { + if (needLoading) { + binding.groupVoiceLayout.setVisibility(View.INVISIBLE); + } + likeOrUnlikeVoice(info, isRight, needLoading); + playLikeOrUnLikeBtnAnim(isRight, false); + } + }); + } + + private void initView() { + binding.ivGroupDontLike.setOnClickListener(this); + binding.svgaGroupVoiceLike.setOnClickListener(this); + } + + private void showMyVoiceEntranceAnim() { + if (binding.layoutMyVoiceEntrance.getAnimation() != null) { + binding.layoutMyVoiceEntrance.getAnimation().cancel(); + binding.layoutMyVoiceEntrance.clearAnimation(); + } + if (binding.tvMyVoiceEntrance.getAnimation() != null) { + binding.tvMyVoiceEntrance.getAnimation().cancel(); + binding.tvMyVoiceEntrance.clearAnimation(); + } + binding.layoutMyVoiceEntrance.post(() -> { + if (showAnim == null) { + int width = binding.layoutMyVoiceEntrance.getWidth(); + showAnim = new TranslateAnimation(0, width / 3 * 1.8f, 1, 1); + showAnim.setStartOffset(2000); + showAnim.setDuration(600); + showAnim.setInterpolator(new AccelerateDecelerateInterpolator()); + showAnim.setFillAfter(true); + } + if (alphaAnimation == null) { + alphaAnimation = new AlphaAnimation(1, 0); + alphaAnimation.setStartOffset(2000); + alphaAnimation.setDuration(600); + alphaAnimation.setInterpolator(new AccelerateDecelerateInterpolator()); + alphaAnimation.setFillAfter(true); + } + binding.layoutMyVoiceEntrance.startAnimation(showAnim); + binding.tvMyVoiceEntrance.startAnimation(alphaAnimation); + }); + } + + /** + * 显示引导图的时机 + * 1. 首次进入页面(isNeedHiGuide) + * 2. 请求数据且数据不为空时 + */ + private void showGuide() { + /*引导图*/ + binding.svgaGroupVoiceLike.postDelayed(() -> { + if (!ActivityUtil.isValidContext(context)) { + return; + } + TuTuGuideHelper guideHelper = new TuTuGuideHelper(context); + guideHelper.createHiGuide(() -> guideHelper.createVoiceMatchGuide(binding.svgaGroupVoiceLike, binding.layoutMyVoiceEntrance)); + TuTuGuideHelper.setNoNeedHiGuide(TuTuGuideHelper.KEY_GUIDE_VOICE_MATCH); + }, 500); + } + + private void queryHistoryVoice() { + AudioModel.get().queryHistoryVoice(AuthModel.get().getCurrentUid()) + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .subscribe(new DontWarnObserver() { + @Override + public void accept(HistoryVoiceInfo historyVoiceInfo, String error) { + super.accept(historyVoiceInfo, error); + if (error == null) { + if (historyVoiceInfo != null) { + HistoryVoiceInfo.HistoryVoiceBean historyVoice = historyVoiceInfo.getHistoryVoice();// 是否在旧版录制过打招呼 + boolean hasVoice = historyVoiceInfo.isHasVoice();// 是否已录制声音,包括待审核、审核通过 + if (historyVoice != null) {// 存在旧版的个人介绍声音:是否使用原来的打招呼或重新录制 + showDialogWithSyncHistoryVoice(historyVoice); + SharedPreferenceUtils.put(KEY_VOICE_MUST_LIMIT + AuthModel.get().getCurrentUid(), true);// 存在旧版个人介绍声音,设置受限 + } else {// 没有在旧版的打招呼中录制过声音 + if (hasVoice) {// 录制过声音 + SharedPreferenceUtils.put(KEY_VOICE_MUST_LIMIT + AuthModel.get().getCurrentUid(), false);// 没有在旧版录制过个人介绍 且 录制过声音瓶子,设置不受限 + } else {// 没有录制过声音 + SharedPreferenceUtils.put(KEY_VOICE_MUST_LIMIT + AuthModel.get().getCurrentUid(), true);// 没有在旧版录制过个人介绍 且 没有录制过声音瓶子,设置受限 + } + } + } else { + SharedPreferenceUtils.put(KEY_VOICE_MUST_LIMIT + AuthModel.get().getCurrentUid(), true);// 请求成功但返回数据为空,设置受限 + } + } else { + SharedPreferenceUtils.put(KEY_VOICE_MUST_LIMIT + AuthModel.get().getCurrentUid(), true);// 请求失败,设置受限 + } + } + }); + } + + private void showDialogWithSyncHistoryVoice(HistoryVoiceInfo.HistoryVoiceBean voiceInfo) { + VmSoundManager.get().onPause(null);// 显示弹框的时候 暂停播放 + // 弹窗:是否使用原来的打招呼或重新录制 + View syncHistoryVoiceView = LayoutInflater.from(context).inflate(R.layout.dialog_custom_voice_match_sync_history_voice, null); + LinearLayout voiceBar = syncHistoryVoiceView.findViewById(R.id.layout_voice_bar); + playIcon = syncHistoryVoiceView.findViewById(R.id.iv_voice_bar_play); + if (voiceLine != null) { + voiceLine.stopAnim(); + } + voiceLine = syncHistoryVoiceView.findViewById(R.id.layout_voice_line); + TextView voiceDuration = syncHistoryVoiceView.findViewById(R.id.tv_voice_duration); + voiceDuration.setText(String.format(Locale.getDefault(), "%ds", voiceInfo.getVoiceLength())); + + voiceBar.setOnClickListener(view -> { + VmSoundManager.get().onPause(status -> { + if (status == VmSoundManager.ConstantStatus.playing || + status == VmSoundManager.ConstantStatus.preparing) { + binding.flGroupContent.onlySetPlayOrStopIconForBigBottle(true); + } + }); + if (AudioPlayerHelper.get().isPlaying()) { + stopVoice(); + } else { + playVoice(voiceInfo.getVoiceUrl()); + } + }); + getDialogManager().showOkCancelCustomDialog(syncHistoryVoiceView, ResUtil.getString(R.string.erban_audio_voicematchactivity_03), ResUtil.getString(R.string.erban_audio_voicematchactivity_04), + false, new DialogManager.OkCancelDialogListener() { + @Override + public void onOk() { + // 确定使用旧版打招呼的声音上传到声音瓶子 + stopVoice(); + syncHistoryVoice(voiceInfo.getId()); + } + + @Override + public void onCancel() { + // 跳转到录制页面 + //跳转界面时停止播放声音 + stopVoice(); + + UIHelper.showRecordVoiceAct(VoiceMatchActivity.this, REQUEST_CODE_RECORDING_VOICE_WITH_SYNC_HISTORY_VOICE, voiceInfo.getId()); + + } + }); + } + + private void playVoice(String voice) { + AudioPlayerHelper.get().playInThread(voice, new OnPlayListener() { + @Override + public void onError(String error) { + refreshVoiceBarLayout(false);// 播放出错 + } + + @Override + public void onPrepared() { + refreshVoiceBarLayout(true);// 准备完毕开始播放 + } + + @Override + public void onPlaying(long currDuration) { + + } + + @Override + public void onCompletion() { + refreshVoiceBarLayout(false);// 播放完成 + } + }); + } + + private void stopVoice() { + AudioPlayerHelper.get().endPlay(); + refreshVoiceBarLayout(false);// 点击停止播放 + } + + private void refreshVoiceBarLayout(boolean isPlaying) { + if (playIcon != null) { + playIcon.post(() -> + // 切换图标 + playIcon.setImageResource(isPlaying ? + R.drawable.ic_voice_bar_pause : R.drawable.ic_voice_bar_play)); + } + if (voiceLine != null) { + voiceLine.stopAnim(); + if (isPlaying) { + voiceLine.startAnim(); + } else { + voiceLine.stopAnim(); + } + } + } + + private void syncHistoryVoice(long voiceId) { + getDialogManager().showProgressDialog(context, ResUtil.getString(R.string.erban_audio_voicematchactivity_07), false); + AudioModel.get().syncHistoryVoice(AuthModel.get().getCurrentUid(), voiceId) + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .subscribe(new DontWarnObserver() { + @Override + public void accept(String s, String error) { + super.accept(s, error); + if (error == null) { + getDialogManager().dismissDialog(); + SharedPreferenceUtils.put(KEY_VOICE_MUST_LIMIT + AuthModel.get().getCurrentUid(), false);// 同步历史声音到瓶子成功,设置不受限 + } else { + getDialogManager().dismissDialog(); + SingleToastUtil.showToast(error); + } + } + }); + VmSoundManager.get().onResume(status -> { + if (status == VmSoundManager.ConstantStatus.playing || + status == VmSoundManager.ConstantStatus.preparing) { + binding.flGroupContent.onlySetPlayOrStopIconForBigBottle(false); + } + }); + } + + @Override + public void initWhiteTitleBar(String title) { + super.initWhiteTitleBar(title); + binding.titleBar.addAction(new TitleBar.ImageAction(R.drawable.ic_voice_match_filter_gender) { + @Override + public void performAction(View view) { + if (isLoading) { + return; + } + // 筛选性别 + if (filterGenderBottomDialog == null) { + filterGenderBottomDialog = new VoiceBottleFilterGenderBottomDialog(context, filterGender, gender -> { + String label = gender == 1 ? ResUtil.getString(R.string.erban_audio_voicematchactivity_08) : gender == 2 ? ResUtil.getString(R.string.erban_audio_voicematchactivity_09) : ResUtil.getString(R.string.erban_audio_voicematchactivity_010); + + filterGender = gender; + SharedPreferenceUtils.put("voice_match_filter_gender_" + AuthModel.get().getCurrentUid(), filterGender); + //重新加载数据时,停止掉声音播放 + VmSoundManager.get().getHelper().endPlay(); + loadingData(gender);// 筛选性别 重新加载数据 + }); + } + filterGenderBottomDialog.show(); + } + }); + } + + /** + * @param filterGender 1:男 2:女 + */ + private void loadingData(int filterGender) { + if (isLoading) { + return; + } + binding.groupVoiceLayout.setVisibility(View.INVISIBLE); + showVoiceStatusLoadingView(); + isLoading = true; + + SvgaCacheManager.get().initSvga(context) + .observeOn(AndroidSchedulers.mainThread()) + .flatMap((Function>>) + s -> AudioModel.get().getVoiceMatchList(filterGender, 10)) + .delay(300, TimeUnit.MILLISECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .subscribe(new DontWarnObserver>() { + @Override + public void accept(List voiceMatchInfos, String error) { + super.accept(voiceMatchInfos, error); + if (isFinishing() || isDestroyed()) { + return; + } + if (TuTuGuideHelper.isNeedHiGuide(TuTuGuideHelper.KEY_GUIDE_VOICE_MATCH) + && !ListUtils.isListEmpty(voiceMatchInfos)) { + showGuide();// 首次进入页面(isNeedHiGuide)且 请求成功数据不为空时,显示引导图 + } + if (voiceMatchInfos != null) { + if (voiceMatchInfos.size() == 0) { + binding.groupVoiceLayout.setVisibility(View.INVISIBLE); + showVoiceStatusView(new VoiceRefreshListener(), R.drawable.icon_voice_no_bottle, ResUtil.getString(R.string.erban_audio_voicematchactivity_012)); + } else { + hideVoiceStatusView(); + binding.groupVoiceLayout.setVisibility(View.VISIBLE); + binding.flGroupContent.initData(voiceMatchInfos); + } + } else { + binding.groupVoiceLayout.setVisibility(View.INVISIBLE); + showVoiceStatusView(new VoiceRefreshListener(), R.drawable.icon_voice_net_error, ResUtil.getString(R.string.erban_audio_voicematchactivity_013)); + } + if (isFirst) { + queryHistoryVoice(); + isFirst = false; + } + isLoading = false; + } + }); + } + + /** + * 状态页面:网络出错 / 无数据 + */ + private void showVoiceStatusView(OnRefreshListener listener, int statusImageId, String statusText) { + hideVoiceStatusView(); + View view = View.inflate(context, R.layout.fragment_voice_status, null); + ImageView ivStatusImage = view.findViewById(R.id.iv_status_image); + ivStatusImage.setImageResource(statusImageId); + TextView tvStatusText = view.findViewById(R.id.tv_status_text); + tvStatusText.setText(statusText); + View stvRefresh = view.findViewById(R.id.stv_refresh); + if (listener != null) { + stvRefresh.setVisibility(View.VISIBLE); + stvRefresh.setOnClickListener(v -> listener.refresh()); + } else { + stvRefresh.setVisibility(View.GONE); + } + binding.flStatusParent.addView(view, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT)); + } + + + private VoiceLine loadingLine; + + private void releaseLoadingLine() { + if (loadingLine != null) { + loadingLine.stopAnim(); + } + } + + /** + * 状态页:正在加载 + */ + private void showVoiceStatusLoadingView() { + hideVoiceStatusView(); + View view = View.inflate(context, R.layout.fragment_voice_status_loading, null); + releaseLoadingLine(); + loadingLine = view.findViewById(R.id.voice_line); + loadingLine.post(loadingLine::startAnim); + TextView tvStatusText = view.findViewById(R.id.tv_status_text); + tvStatusText.setText(ResUtil.getString(R.string.erban_audio_voicematchactivity_014)); + binding.flStatusParent.addView(view, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT)); + } + + /** + * 清除状态页 + */ + private void hideVoiceStatusView() { + binding.flStatusParent.removeAllViews(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + binding.flGroupContent.onDestroy(); + + VmSoundManager.get().onDestroy(); + AudioPlayerHelper.get().onDestroy(); + SvgaCacheManager.get().onDestroy(); + + if (showAnim != null) { + showAnim.cancel(); + showAnim = null; + } + if (alphaAnimation != null) { + alphaAnimation.cancel(); + alphaAnimation = null; + } + releaseLoadingLine(); + if (voiceLine != null) { + voiceLine.stopAnim(); + } + } + + private void toNext(boolean isLike) { + boolean isLimit = (boolean) SharedPreferenceUtils.get(KEY_VOICE_MUST_LIMIT + AuthModel.get().getCurrentUid(), true); + if (isLimit) { + binding.flGroupContent.dealBigBottleLimit(isLike); + } else { + playLikeOrUnLikeBtnAnim(isLike, true); + } + } + + + private void playLikeOrUnLikeBtnAnim(boolean isLike, boolean isNeedDealToNext) { + if (!isLike) { + //播放不喜欢按钮的属性动画 + if (helper.isDontLikeAnimRun()) { + return; + } + helper.playDontLikeAnim(binding.ivGroupDontLike); + } else { + if (binding.svgaGroupVoiceLike.isAnimating()) { + return; + } + binding.flGroupContent.addBigBottleLikeCount(); + helper.playDontLikeAnim(binding.ivGroupLike); + //播放喜欢按钮的svga动画 + binding.svgaGroupVoiceLike.startAnimation(); + binding.svgaGroupVoiceLike.setCallback(new SVGACallback() { + @Override + public void onPause() { + + } + + @Override + public void onFinished() { + + } + + @Override + public void onRepeat() { + + } + + @Override + public void onStep(int i, double v) { + + } + }); + } + if (isNeedDealToNext) { + binding.flGroupContent.dealToNext(isLike); + } + + } + + @Override + public void onClick(View view) { + switch (view.getId()) { + case R.id.layout_my_voice_entrance: + if (isLoading) { + return; + } + UIHelper.showMyVoiceAct(VoiceMatchActivity.this, REQUEST_CODE_RECORDING_VOICE_WITH_MY_VOICE, ResUtil.getString(R.string.erban_audio_voicematchactivity_015));// 跳转到我的声音页面 + break; + case R.id.iv_group_dont_like: + toNext(false); + break; + case R.id.svga_group_voice_like: + toNext(true); + break; + } + + } + + private void showDialogWithHasLimit(boolean isRight) { + String showMessage; + if (isRight) { + showMessage = ResUtil.getString(R.string.erban_audio_voicematchactivity_018); + } else { + showMessage = ResUtil.getString(R.string.erban_audio_voicematchactivity_019); + } + getDialogManager().showTipsDialog(showMessage, ResUtil.getString(R.string.erban_audio_voicematchactivity_020), () -> { + // 跳转到录制页面 + UIHelper.showRecordVoiceAct(VoiceMatchActivity.this, REQUEST_CODE_RECORDING_VOICE_WITH_HAS_LIMIT, -1); + }); + } + + private void likeOrUnlikeVoice(VoiceMatchInfo info, boolean isRight, boolean needLoading) { + AudioModel.get().likeOrUnlikeVoice(AuthModel.get().getCurrentUid(), info.getId(), isRight ? 1 : 0) + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .subscribe(new DontWarnObserver() { + @Override + public void accept(String s, String error) { + super.accept(s, error); + if (needLoading) { + loadingData(filterGender); + } + if (error == null) { + if (isRight) { + NimP2PMessageActivity.start(context, String.valueOf(info.getUid()), true); + } + } + } + }); + } + + public class VoiceRefreshListener implements OnRefreshListener { + + @Override + public void refresh() { + loadingData(filterGender);// 状态页面刷新一下 重新加载数据 + } + } + + @Override + protected void onResume() { + super.onResume(); + PlayerModel.get().pause(); + VmSoundManager.get().onResume(status -> { + if (status == VmSoundManager.ConstantStatus.playing || + status == VmSoundManager.ConstantStatus.preparing) { + binding.flGroupContent.onlySetPlayOrStopIconForBigBottle(false); + } + }); + } + + @Override + protected void onPause() { + super.onPause(); + PlayerModel.get().play(null); + VmSoundManager.get().onPause(status -> { + if (status == VmSoundManager.ConstantStatus.playing || + status == VmSoundManager.ConstantStatus.preparing) { + binding.flGroupContent.onlySetPlayOrStopIconForBigBottle(true); + } + }); + + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == REQUEST_CODE_RECORDING_VOICE_WITH_MY_VOICE) { + showMyVoiceEntranceAnim(); + } + if (resultCode == RESULT_OK) { + if (requestCode == REQUEST_CODE_RECORDING_VOICE_WITH_HAS_LIMIT && data != null) { + SharedPreferenceUtils.put(KEY_VOICE_MUST_LIMIT + AuthModel.get().getCurrentUid(), false);// 录制完声音,重置不受限制 + } else if (requestCode == REQUEST_CODE_RECORDING_VOICE_WITH_MY_VOICE && data != null) { + SharedPreferenceUtils.put(KEY_VOICE_MUST_LIMIT + AuthModel.get().getCurrentUid(), false);// 录制完声音,重置不受限制 + } + } + if (requestCode == REQUEST_CODE_RECORDING_VOICE_WITH_SYNC_HISTORY_VOICE) { + queryHistoryVoice();// 重新查询是否有历史声音 + } + } + +} diff --git a/app/src/main/java/com/chwl/app/audio/adapter/CardAdapter.java b/app/src/main/java/com/chwl/app/audio/adapter/CardAdapter.java new file mode 100644 index 0000000..016a78d --- /dev/null +++ b/app/src/main/java/com/chwl/app/audio/adapter/CardAdapter.java @@ -0,0 +1,120 @@ +package com.chwl.app.audio.adapter; + +import android.text.method.ScrollingMovementMethod; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.chwl.app.R; +import com.chwl.core.audio.bean.VoiceCardInfo; + +import java.util.ArrayList; +import java.util.List; + +/** + * 录制声音页面的声音卡片 + */ +public class CardAdapter extends RecyclerView.Adapter { + + private List dataList; + + private OnVoiceCardChangeButtonClickListener onVoiceCardChangeButtonClickListener; + + public CardAdapter(List cardInfoList) { + if (cardInfoList == null) { + cardInfoList = new ArrayList<>(); + } + this.dataList = cardInfoList; + } + + @NonNull + @Override + public CardVH onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) { + View itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.fragment_voice_card, viewGroup, false); + return new CardVH(itemView); + } + + @Override + public void onBindViewHolder(@NonNull CardVH cardVH, int i) { + if (dataList.get(i) == null) { + return; + } + if (i == 0) { + cardVH.layout.setAlpha(1); + cardVH.title.setAlpha(1); + cardVH.content.setAlpha(1); + } else if (i == 1) { + cardVH.layout.setAlpha(0.5f); + cardVH.title.setAlpha(0); + cardVH.content.setAlpha(0); + } else if (i == 2) { + cardVH.layout.setAlpha(0.3f); + cardVH.title.setAlpha(0); + cardVH.content.setAlpha(0); + } else { + cardVH.layout.setAlpha(0); + cardVH.title.setAlpha(0); + cardVH.content.setAlpha(0); + } + cardVH.title.setText(dataList.get(i).getTitle()); + cardVH.content.setText(dataList.get(i).getPlayBook()); + cardVH.changeButton.setVisibility(i == 0 ? View.VISIBLE : View.GONE); + cardVH.changeButton.setOnClickListener(view -> { + if (onVoiceCardChangeButtonClickListener != null) { + onVoiceCardChangeButtonClickListener.onVoiceCardChange(cardVH); + } + }); + cardVH.content.post(() -> { + // 超过五行显示阴影 + cardVH.shadow.setVisibility(cardVH.content.getLineCount() > 5 ? View.VISIBLE : View.GONE); + }); + } + + @Override + public int getItemCount() { + return dataList.size(); + } + + public void removeItem(int pos) { + dataList.remove(pos); + notifyDataSetChanged(); + } + + public VoiceCardInfo getFistItemInfo() { + return dataList.get(0); + } + + public class CardVH extends RecyclerView.ViewHolder { + + FrameLayout layout; + TextView title; + TextView content; + RelativeLayout changeButton; + View shadow; + + CardVH(@NonNull View itemView) { + super(itemView); + layout = itemView.findViewById(R.id.layout_voice_card); + title = itemView.findViewById(R.id.tv_voice_card_title); + content = itemView.findViewById(R.id.tv_voice_card_content); + changeButton = itemView.findViewById(R.id.layout_voice_card_change); + shadow = itemView.findViewById(R.id.iv_voice_card_bottom_shadow); + + content.setMovementMethod(ScrollingMovementMethod.getInstance()); + } + } + + public interface OnVoiceCardChangeButtonClickListener { + void onVoiceCardChange(RecyclerView.ViewHolder viewHolder); + } + + public void setOnVoiceCardChangeButtonClickListener(OnVoiceCardChangeButtonClickListener onVoiceCardChangeButtonClickListener) { + this.onVoiceCardChangeButtonClickListener = onVoiceCardChangeButtonClickListener; + } +} diff --git a/app/src/main/java/com/chwl/app/audio/adapter/MyVoiceListAdapter.java b/app/src/main/java/com/chwl/app/audio/adapter/MyVoiceListAdapter.java new file mode 100644 index 0000000..3fc437c --- /dev/null +++ b/app/src/main/java/com/chwl/app/audio/adapter/MyVoiceListAdapter.java @@ -0,0 +1,262 @@ +package com.chwl.app.audio.adapter; + +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.Nullable; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.app.audio.widget.VoiceLine; +import com.chwl.core.audio.bean.UserVoiceInfo; +import com.chwl.core.utils.StringFormatUtils; +import com.chwl.library.utils.ResUtil; + +import java.util.List; +import java.util.Locale; + +/** + * 我的声音.审核通过状态的列表 + */ +public class MyVoiceListAdapter extends BaseQuickAdapter { + + private OnVerifiedVoiceItemClickListener onVerifiedVoiceItemClickListener; + private boolean isPlayingVoice; + private int voiceClickPos = -1; + + private static final int TYPE_IN_REVIEW = 0; + private static final int TYPE_VERIFIED = 1; + private static final int TYPE_NO_SUBMITTED = 2; + + public MyVoiceListAdapter(@Nullable List data) { + super(data); + } + + @Override + public int getItemViewType(int position) { + UserVoiceInfo item = getItem(position); + if (item == null) { + return TYPE_NO_SUBMITTED; + } else { + return item.getStatus(); + } + } + + @Override + protected BaseViewHolder onCreateDefViewHolder(ViewGroup parent, int viewType) { + if (viewType == TYPE_IN_REVIEW) { + return onCreateViewHolderWithInReview(parent); + } else if (viewType == TYPE_VERIFIED) { + return onCreateViewHolderWithVerified(parent); + } else { + return onCreateViewHolderWithNoSubmitted(parent); + } + } + + private BaseViewHolder onCreateViewHolderWithInReview(ViewGroup parent) { + return new InReviewViewHolder(mLayoutInflater.inflate(R.layout.item_my_voice_in_review, parent, false)); + } + + private BaseViewHolder onCreateViewHolderWithVerified(ViewGroup parent) { + return new VerifiedViewHolder(mLayoutInflater.inflate(R.layout.item_my_voice_verified, parent, false)); + } + + private BaseViewHolder onCreateViewHolderWithNoSubmitted(ViewGroup parent) { + return new NoSubmittedViewHolder(mLayoutInflater.inflate(R.layout.item_my_voice_no_submitted, parent, false)); + } + + @Override + protected void convert(BaseViewHolder helper, UserVoiceInfo item) { + if (item == null) { + return; + } + if (helper instanceof InReviewViewHolder) { + onBindViewHolderWithInReview((InReviewViewHolder) helper, item); + } else if (helper instanceof VerifiedViewHolder) { + onBindViewHolderWithVerified((VerifiedViewHolder) helper, item); + } else if (helper instanceof NoSubmittedViewHolder) { + onBindViewHolderWithNoSubmitted((NoSubmittedViewHolder) helper, item); + } + } + + private void onBindViewHolderWithInReview(InReviewViewHolder helper, UserVoiceInfo item) { + helper.tvDuration.setText(String.format(Locale.getDefault(), "%ds", item.getVoiceLength()));// 声音时长 + // 播放动画 + if (helper.voiceLine != null) { + helper.voiceLine.stopAnim(); + } + helper.ivVoicePlay.post(() -> { + if (helper.getAdapterPosition() == voiceClickPos) { + if (isPlayingVoice) { + helper.ivVoicePlay.setImageResource(R.drawable.ic_voice_bar_pause); + helper.voiceLine.startAnim(); + } else { + helper.ivVoicePlay.setImageResource(R.drawable.ic_voice_bar_play); + helper.voiceLine.stopAnim(); + } + } else { + helper.ivVoicePlay.setImageResource(R.drawable.ic_voice_bar_play); + helper.voiceLine.stopAnim(); + } + }); + // 点击播放声音/停止声音 + helper.voiceBarLayout.setOnClickListener(view -> { + if (StringFormatUtils.isEmpty(item.getVoiceUrl())) { + return; + } + boolean isChange = helper.getAdapterPosition() != voiceClickPos; + voiceClickPos = helper.getAdapterPosition(); + if (onVerifiedVoiceItemClickListener != null) { + onVerifiedVoiceItemClickListener.onVoiceClick(isChange, item.getVoiceUrl()); + } + }); + // 点击重新录制:跳转到录制声音页面 + helper.addOnClickListener(helper.tvReRecord.getId()); + } + + private void onBindViewHolderWithVerified(VerifiedViewHolder helper, UserVoiceInfo item) { + helper.tvDuration.setText(String.format(Locale.getDefault(), "%ds", item.getVoiceLength()));// 声音时长 + // 播放动画 + if (helper.voiceLine != null) { + helper.voiceLine.stopAnim(); + } + helper.ivVoicePlay.post(() -> { + if (helper.getAdapterPosition() == voiceClickPos) { + if (isPlayingVoice) { + helper.ivVoicePlay.setImageResource(R.drawable.ic_voice_bar_pause); + helper.voiceLine.startAnim(); + } else { + helper.ivVoicePlay.setImageResource(R.drawable.ic_voice_bar_play); + helper.voiceLine.stopAnim(); + } + } else { + helper.ivVoicePlay.setImageResource(R.drawable.ic_voice_bar_play); + helper.voiceLine.stopAnim(); + } + }); + // 点击播放声音/停止声音 + helper.voiceBarLayout.setOnClickListener(view -> { + if (StringFormatUtils.isEmpty(item.getVoiceUrl())) { + return; + } + boolean isChange = helper.getAdapterPosition() != voiceClickPos; + voiceClickPos = helper.getAdapterPosition(); + if (onVerifiedVoiceItemClickListener != null) { + onVerifiedVoiceItemClickListener.onVoiceClick(isChange, item.getVoiceUrl()); + } + }); + // 点击重新录制:跳转到录制声音页面 + helper.addOnClickListener(helper.tvReRecord.getId()); + helper.tvHeardCount.setText(String.format(Locale.getDefault(), ResUtil.getString(R.string.audio_adapter_myvoicelistadapter_01), item.getPlayCount()));// 听过人数 + helper.tvLikeCount.setText(String.format(Locale.getDefault(), ResUtil.getString(R.string.audio_adapter_myvoicelistadapter_02), item.getLikeCount()));// 喜欢人数 + } + + private void onBindViewHolderWithNoSubmitted(NoSubmittedViewHolder helper, UserVoiceInfo item) { + helper.tvDuration.setText(String.format(Locale.getDefault(), "%ds", item.getVoiceLength()));// 声音时长 + // 播放动画 + if (helper.voiceLine != null) { + helper.voiceLine.stopAnim(); + } + helper.ivVoicePlay.post(() -> { + if (helper.getAdapterPosition() == voiceClickPos) { + if (isPlayingVoice) { + helper.ivVoicePlay.setImageResource(R.drawable.ic_voice_bar_pause); + helper.voiceLine.startAnim(); + } else { + helper.ivVoicePlay.setImageResource(R.drawable.ic_voice_bar_play); + helper.voiceLine.stopAnim(); + } + } else { + helper.ivVoicePlay.setImageResource(R.drawable.ic_voice_bar_play); + helper.voiceLine.stopAnim(); + } + }); + // 点击播放声音/停止声音 + helper.voiceBarLayout.setOnClickListener(view -> { + if (StringFormatUtils.isEmpty(item.getVoiceUrl())) { + return; + } + boolean isChange = helper.getAdapterPosition() != voiceClickPos; + voiceClickPos = helper.getAdapterPosition(); + if (onVerifiedVoiceItemClickListener != null) { + onVerifiedVoiceItemClickListener.onVoiceClick(isChange, item.getVoiceUrl()); + } + }); + // 点击重新录制:跳转到录制声音页面 + helper.addOnClickListener(helper.tvReRecord.getId()); + } + + public void changePlayState(boolean isPlaying) { + this.isPlayingVoice = isPlaying; + notifyDataSetChanged(); + } + + private class InReviewViewHolder extends BaseViewHolder { + + LinearLayout voiceBarLayout; + ImageView ivVoicePlay; + VoiceLine voiceLine; + TextView tvDuration; + TextView tvReRecord; + + InReviewViewHolder(View view) { + super(view); + voiceBarLayout = view.findViewById(R.id.layout_voice_bar); + ivVoicePlay = view.findViewById(R.id.iv_voice_bar_play); + voiceLine = view.findViewById(R.id.layout_voice_line); + tvDuration = view.findViewById(R.id.tv_voice_duration); + tvReRecord = view.findViewById(R.id.tv_re_recording); + } + } + + private class VerifiedViewHolder extends BaseViewHolder { + + LinearLayout voiceBarLayout; + ImageView ivVoicePlay; + VoiceLine voiceLine; + TextView tvDuration; + TextView tvReRecord; + TextView tvHeardCount, tvLikeCount; + + VerifiedViewHolder(View view) { + super(view); + voiceBarLayout = view.findViewById(R.id.layout_voice_bar); + ivVoicePlay = view.findViewById(R.id.iv_voice_bar_play); + voiceLine = view.findViewById(R.id.layout_voice_line); + tvDuration = view.findViewById(R.id.tv_voice_duration); + tvReRecord = view.findViewById(R.id.tv_re_recording); + tvHeardCount = view.findViewById(R.id.tv_voice_heard_count); + tvLikeCount = view.findViewById(R.id.tv_voice_like_count); + } + } + + private class NoSubmittedViewHolder extends BaseViewHolder { + + LinearLayout voiceBarLayout; + ImageView ivVoicePlay; + VoiceLine voiceLine; + TextView tvDuration; + TextView tvReRecord; + + NoSubmittedViewHolder(View view) { + super(view); + voiceBarLayout = view.findViewById(R.id.layout_voice_bar); + ivVoicePlay = view.findViewById(R.id.iv_voice_bar_play); + voiceLine = view.findViewById(R.id.layout_voice_line); + tvDuration = view.findViewById(R.id.tv_voice_duration); + tvReRecord = view.findViewById(R.id.tv_re_recording); + } + } + + public interface OnVerifiedVoiceItemClickListener { + void onVoiceClick(boolean isChange, String voice); + } + + public void setOnVerifiedVoiceItemClickListener(OnVerifiedVoiceItemClickListener onVerifiedVoiceItemClickListener) { + this.onVerifiedVoiceItemClickListener = onVerifiedVoiceItemClickListener; + } +} diff --git a/app/src/main/java/com/chwl/app/audio/helper/AudioPlayerHelper.java b/app/src/main/java/com/chwl/app/audio/helper/AudioPlayerHelper.java new file mode 100644 index 0000000..185348e --- /dev/null +++ b/app/src/main/java/com/chwl/app/audio/helper/AudioPlayerHelper.java @@ -0,0 +1,221 @@ +package com.chwl.app.audio.helper; + +import android.annotation.SuppressLint; +import android.media.AudioManager; +import android.media.MediaPlayer; +import android.os.Handler; +import android.os.Message; +import android.text.TextUtils; + +import com.chwl.app.R; +import com.chwl.library.utils.ResUtil; + +import java.io.IOException; + +/** + * create by lvzebiao @2019/6/14 + */ +public class AudioPlayerHelper { + + private final static long mIntervalTime = 16L; + + public interface WHAT_STATUS { + int ERROR = 1; + int COUNT_PLAY = 2; + int COMPLETION = 3; + int PREPARED = 4; + } + + private static final class Helper { + public static final AudioPlayerHelper INSTANCE = new AudioPlayerHelper(); + } + + public static AudioPlayerHelper get() { + return Helper.INSTANCE; + } + + private MediaPlayer player; + + private String audioFile; + + private boolean isLoop; + + public void onCreate() { + + } + + public void onPause() { + endPlay(); + } + + public void onDestroy() { + endPlay(); + } + + private boolean preparing = false; + + private boolean pause = false; + + public void playInThread(String filePath, OnPlayListener l) { + playInThread(filePath, false, l); + } + + public void rePlayInThread() { + if (listener != null && !TextUtils.isEmpty(audioFile)) { + playInThread(audioFile, isLoop, listener); + } + } + + public void playInThread(String filePath, boolean isLoop, OnPlayListener l) { + endPlay(); + this.listener = l; + if (listener != null) { + listener.onPreStart(); + } + this.audioFile = filePath; + this.isLoop = isLoop; + player = new MediaPlayer(); + player.setLooping(isLoop); + player.setAudioStreamType(AudioManager.STREAM_MUSIC); + + try { + player.setDataSource(filePath); + } catch (IOException e) { + e.printStackTrace(); + } + preparing = true; + try { + player.prepareAsync(); + } catch (Exception e) { + e.printStackTrace(); + preparing = false; + handler.sendEmptyMessage(WHAT_STATUS.ERROR); + } + player.setOnPreparedListener(mp -> { + if (player != null) { + player.start(); + } + preparing = false; + handler.sendEmptyMessage(WHAT_STATUS.PREPARED); + }); + player.setOnErrorListener((mp, what, extra) -> { + handler.sendEmptyMessage(WHAT_STATUS.ERROR); + return false; + }); + player.setOnCompletionListener(mp -> { + handler.removeMessages(WHAT_STATUS.COUNT_PLAY); + handler.sendEmptyMessage(WHAT_STATUS.COMPLETION); + }); + } + + public void endPlay() { + if (listener != null) { + listener.onCompletion(); + } + handler.removeMessages(WHAT_STATUS.COUNT_PLAY); + if (player != null) { + if (preparing) { + player.setOnPreparedListener(null); + player.setOnErrorListener(null); + player.setOnCompletionListener(null); + } + if (player.isPlaying() && !preparing) { + player.stop(); + } + player.release(); + player = null; + } + preparing = false; + pause = false; + this.listener = null; + this.audioFile = null; + } + + public void releaseWhenPreparing() { + handler.removeMessages(WHAT_STATUS.COUNT_PLAY); + if (player != null) { + if (player.isPlaying()) { + player.stop(); + } + player.setOnErrorListener(null); + player.setOnPreparedListener(null); + player.setOnCompletionListener(null); + player.release(); + player = null; + } + preparing = false; + } + + @SuppressLint("HandlerLeak") + private Handler handler = new Handler() { + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + switch (msg.what) { + case WHAT_STATUS.ERROR: + if (listener != null) { + listener.onError(ResUtil.getString(R.string.audio_helper_audioplayerhelper_01)); + } + break; + case WHAT_STATUS.PREPARED: + preparing = false; + if (listener != null) { + listener.onPrepared(); + } + handler.sendEmptyMessage(WHAT_STATUS.COUNT_PLAY); + break; + case WHAT_STATUS.COUNT_PLAY: + if (listener != null) { + if (player != null) { + listener.onPlaying(player.getCurrentPosition()); + } + } + sendEmptyMessageDelayed(WHAT_STATUS.COUNT_PLAY, mIntervalTime); + break; + case WHAT_STATUS.COMPLETION: + preparing = false; + if (listener != null) { + listener.onCompletion(); + } + break; + } + } + }; + + public void pausePlay() { + if (player == null) { + return; + } + if (isPlaying()) { + player.pause(); + pause = true; + } + } + + public void continuePlay() { + if (player == null) { + return; + } + player.start(); + pause = false; + } + + private OnPlayListener listener; + + public boolean isPlaying() { + return player != null && player.isPlaying(); + } + + public boolean isPause() { + return pause; + } + + public boolean isPreparing() { + return preparing; + } + + public long getDuration() { + return player == null ? 0 : player.getDuration(); + } + +} diff --git a/app/src/main/java/com/chwl/app/audio/helper/OnPlayListener.java b/app/src/main/java/com/chwl/app/audio/helper/OnPlayListener.java new file mode 100644 index 0000000..60a4c81 --- /dev/null +++ b/app/src/main/java/com/chwl/app/audio/helper/OnPlayListener.java @@ -0,0 +1,39 @@ +package com.chwl.app.audio.helper; + +/** + * create by lvzebiao @2019/6/17 + */ +public interface OnPlayListener { + + /** + * 播放之前的操作 + */ + default void onPreStart() { + + } + + /** + * 出错了 + * 1. prepare 出错 + * 2. setOnErrorListener 回调 + */ + void onError(String error); + + /** + * 准备完毕 + * 1. setOnPreparedListener 回调 + */ + void onPrepared(); + + /** + * 播放中 + * 1. onPlaying + */ + void onPlaying(long currDuration); + + /** + * 播放完毕回调 + * 1. setOnCompletionListener 回调 + */ + void onCompletion(); +} diff --git a/app/src/main/java/com/chwl/app/audio/helper/OnRefreshListener.java b/app/src/main/java/com/chwl/app/audio/helper/OnRefreshListener.java new file mode 100644 index 0000000..6db1b9c --- /dev/null +++ b/app/src/main/java/com/chwl/app/audio/helper/OnRefreshListener.java @@ -0,0 +1,10 @@ +package com.chwl.app.audio.helper; + +/** + * create by lvzebiao @2019/6/11 + */ +public interface OnRefreshListener { + + void refresh(); + +} diff --git a/app/src/main/java/com/chwl/app/audio/helper/SvgaCacheManager.java b/app/src/main/java/com/chwl/app/audio/helper/SvgaCacheManager.java new file mode 100644 index 0000000..1611fb2 --- /dev/null +++ b/app/src/main/java/com/chwl/app/audio/helper/SvgaCacheManager.java @@ -0,0 +1,171 @@ +package com.chwl.app.audio.helper; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.os.Build; +import android.os.Handler; +import android.os.Message; + +import com.opensource.svgaplayer.SVGADrawable; +import com.opensource.svgaplayer.SVGAParser; +import com.opensource.svgaplayer.SVGAVideoEntity; + +import javax.annotation.Nullable; + +import io.reactivex.Single; +import io.reactivex.SingleOnSubscribe; +import io.reactivex.schedulers.Schedulers; +import lombok.Getter; + +/** + * create by lvzebiao @2019/6/21 + */ +public class SvgaCacheManager { + + private boolean voiceMatchActivityHasDestroy; + + /** + * 大瓶子水波纹 + */ + @Getter + private SVGADrawable bigBottleSvga; + /** + * 大瓶子气泡 + */ + @Getter + private SVGADrawable bigBubbleSvga; + /** + * 小瓶子水波纹 + */ + @Getter + private SVGADrawable smallBottleSvga; + /** + * 小瓶子气泡 + */ + @Getter + private SVGADrawable smallBubbleSvga; + + private static SvgaCacheManager instance; + + private SvgaCacheManager() { + + } + + public static SvgaCacheManager get() { + if (instance == null) { + instance = new SvgaCacheManager(); + } + return instance; + } + + public Single initSvga(Context context) { + if (!isMoreAndroid7_0()) { + return Single.just(""); + } + if (bigBottleSvga != null && bigBubbleSvga != null && + smallBottleSvga != null && smallBubbleSvga != null) { + return Single.just(""); + } + SVGAParser parser = new SVGAParser(context); + return Single.just("") + .flatMap(s -> { + if (bigBottleSvga == null) { + return createSvga(parser, true, true); + } + return Single.just(""); + }) + .flatMap(s -> { + if (bigBubbleSvga == null) { + return createSvga(parser, true, false); + } + return Single.just(""); + }) + .flatMap(s -> { + if (smallBottleSvga == null) { + return createSvga(parser, false, true); + } + return Single.just(""); + }) + .flatMap(s -> { + if (smallBubbleSvga == null) { + return createSvga(parser, false, false); + } + return Single.just(""); + }); + } + + private Single createSvga(SVGAParser parser, boolean isBig, boolean isBottle) { + return Single.create((SingleOnSubscribe) emitter -> { + String path = isBottle ? "svga/svga_voice_bottle.svga" : "svga/svga_voice_bubble.svga"; + parser.decodeFromAssets(path, new SVGAParser.ParseCompletion() { + @Override + public void onComplete(@Nullable SVGAVideoEntity svgaVideoEntity) { + if (isBig) { + if (isBottle) { + bigBottleSvga = new SVGADrawable(svgaVideoEntity); + } else { + bigBubbleSvga = new SVGADrawable(svgaVideoEntity); + } + } else { + if (isBottle) { + smallBottleSvga = new SVGADrawable(svgaVideoEntity); + } else { + smallBubbleSvga = new SVGADrawable(svgaVideoEntity); + } + } + emitter.onSuccess(""); + } + + @Override + public void onError() { + emitter.onError(new Throwable("svga error")); + } + },null); + }).subscribeOn(Schedulers.io()); + } + + public void onCreate() { + if (!isMoreAndroid7_0()) { + return; + } + voiceMatchActivityHasDestroy = false; + handler.removeMessages(0); + } + + public void onDestroy() { + if (!isMoreAndroid7_0()) { + return; + } + voiceMatchActivityHasDestroy = true; + //发送消息释放资源,资源存活时间过后再回收,防止频繁调用声音匹配界面 + handler.sendEmptyMessageDelayed(0, 90 * 1000); + } + + private void release() { + bigBottleSvga = null; + bigBubbleSvga = null; + smallBottleSvga = null; + smallBubbleSvga = null; + instance = null; + //gc + System.gc(); + } + + @SuppressLint("HandlerLeak") + private Handler handler = new Handler() { + + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + release(); + } + }; + + /** + * 是否是android 7.0或者以上 + */ + public boolean isMoreAndroid7_0() { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N; + } + +} diff --git a/app/src/main/java/com/chwl/app/audio/helper/VmSoundManager.java b/app/src/main/java/com/chwl/app/audio/helper/VmSoundManager.java new file mode 100644 index 0000000..4387fd1 --- /dev/null +++ b/app/src/main/java/com/chwl/app/audio/helper/VmSoundManager.java @@ -0,0 +1,77 @@ +package com.chwl.app.audio.helper; + + +import lombok.Getter; + +/** + * 声音匹配界面播放管理,写一个单例类,管理 + * create by lvzebiao @2019/6/20 + */ +public class VmSoundManager { + + public interface ConstantStatus { + int init = 0; + /**准备播放的状态*/ + int preparing = 1; + /**播放中的状态*/ + int playing = 2; + } + + private int playStatus = 0; + + private static final class Helper { + public static final VmSoundManager INSTANCE = new VmSoundManager(); + } + + public static VmSoundManager get() { + return Helper.INSTANCE; + } + + @Getter + private AudioPlayerHelper helper; + + public void onCreate() { + helper = new AudioPlayerHelper(); + helper.onCreate(); + } + + public void onResume(OnResumeListener onResumeListener) { + if (playStatus == ConstantStatus.playing) { + VmSoundManager.get().getHelper().continuePlay(); + } else if (playStatus == ConstantStatus.preparing) { + VmSoundManager.get().getHelper().rePlayInThread(); + } + if (onResumeListener != null) { + onResumeListener.onHandleResume(playStatus); + } + playStatus = ConstantStatus.init; + } + + public void onPause(OnPauseListener onPauseListener) { + if (VmSoundManager.get().getHelper().isPlaying()) { + VmSoundManager.get().getHelper().pausePlay(); + playStatus = ConstantStatus.playing; + } else if (VmSoundManager.get().getHelper().isPreparing()) { + VmSoundManager.get().getHelper().releaseWhenPreparing(); + playStatus = ConstantStatus.preparing; + } + if (onPauseListener != null) { + onPauseListener.onHandlePause(playStatus); + } + } + + public void onDestroy() { + if (helper != null) { + helper.onDestroy(); + } + } + + public interface OnResumeListener { + void onHandleResume(int status); + } + + public interface OnPauseListener { + void onHandlePause(int status); + } + +} diff --git a/app/src/main/java/com/chwl/app/audio/helper/VoiceMacthHelper.java b/app/src/main/java/com/chwl/app/audio/helper/VoiceMacthHelper.java new file mode 100644 index 0000000..4b6754f --- /dev/null +++ b/app/src/main/java/com/chwl/app/audio/helper/VoiceMacthHelper.java @@ -0,0 +1,36 @@ +package com.chwl.app.audio.helper; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.view.View; + +import lombok.Getter; + +/** + * create by lvzebiao @2019/6/11 + */ +public class VoiceMacthHelper { + + @Getter + private boolean dontLikeAnimRun; + + public void playDontLikeAnim(View view) { + dontLikeAnimRun = true; + ObjectAnimator animatorX = ObjectAnimator.ofFloat(view, "scaleX", 1.0f, 0.9f, 1.2f, 1.0f); + ObjectAnimator animatorY = ObjectAnimator.ofFloat(view, "scaleY", 1.0f, 0.9f, 1.2f, 1.0f); + AnimatorSet animatorSet = new AnimatorSet(); + animatorSet.setDuration(600); + animatorSet.play(animatorX).with(animatorY); + animatorSet.start(); + animatorSet.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + dontLikeAnimRun = false; + } + }); + } + +} diff --git a/app/src/main/java/com/chwl/app/audio/presenter/MyVoicePresenter.java b/app/src/main/java/com/chwl/app/audio/presenter/MyVoicePresenter.java new file mode 100644 index 0000000..17a29a0 --- /dev/null +++ b/app/src/main/java/com/chwl/app/audio/presenter/MyVoicePresenter.java @@ -0,0 +1,35 @@ +package com.chwl.app.audio.presenter; + +import com.chwl.app.audio.view.IMyVoiceView; +import com.chwl.app.base.BaseMvpPresenter; +import com.chwl.core.audio.AudioModel; +import com.chwl.core.audio.bean.UserVoiceInfo; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.utils.net.DontWarnObserver; +import com.chwl.library.base.PresenterEvent; + +import java.util.List; + +/** + * 我的声音页面 + */ +public class MyVoicePresenter extends BaseMvpPresenter { + + public void getUserVoiceInfo() { + getMvpView().showLoadingView(); + AudioModel.get().getMyVoiceInfoList(AuthModel.get().getCurrentUid()) + .compose(bindUntilEvent(PresenterEvent.DESTROY)) + .subscribe(new DontWarnObserver>() { + @Override + public void accept(List userVoiceInfos, String error) { + super.accept(userVoiceInfos, error); + if (getMvpView() == null) { + return; + } + getMvpView().hideLoadingView(); + getMvpView().showVoiceInfo(userVoiceInfos); + } + }); + + } +} diff --git a/app/src/main/java/com/chwl/app/audio/presenter/RecordingVoicePresenter.java b/app/src/main/java/com/chwl/app/audio/presenter/RecordingVoicePresenter.java new file mode 100644 index 0000000..9a127f4 --- /dev/null +++ b/app/src/main/java/com/chwl/app/audio/presenter/RecordingVoicePresenter.java @@ -0,0 +1,462 @@ +package com.chwl.app.audio.presenter; + +import static com.chwl.app.audio.RecordingVoiceActivity.AUDIO_DURA; +import static com.chwl.app.audio.RecordingVoiceActivity.AUDIO_FILE; +import static com.chwl.app.audio.RecordingVoiceActivity.MIN_RECORD_VOICE_DURATION; + +import android.content.Context; +import android.content.Intent; +import android.os.Handler; +import android.os.Message; +import android.util.Log; + +import com.netease.nimlib.sdk.media.record.AudioRecorder; +import com.netease.nimlib.sdk.media.record.IAudioRecordCallback; +import com.netease.nimlib.sdk.media.record.RecordType; +import com.chwl.app.R; +import com.chwl.app.audio.helper.AudioPlayerHelper; +import com.chwl.app.audio.helper.OnPlayListener; +import com.chwl.app.audio.view.IRecordingVoiceView; +import com.chwl.app.base.BaseMvpPresenter; +import com.chwl.core.audio.AudioModel; +import com.chwl.core.audio.AudioPlayAndRecordManager; +import com.chwl.core.audio.bean.SaveVoiceSuccessResultInfo; +import com.chwl.core.audio.bean.VoiceCardInfo; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.file.FileModel; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.core.utils.net.DontWarnObserver; +import com.chwl.library.base.PresenterEvent; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; +import com.chwl.library.utils.log.MLog; + +import java.io.File; +import java.util.List; + +import io.reactivex.SingleObserver; +import io.reactivex.disposables.Disposable; + +/** + * 录制声音页面 + */ +public class RecordingVoicePresenter extends BaseMvpPresenter { + + private static final String TAG = "RecordingVoiceActivity"; + + public static final int STATE_RECORD_NORMAL = 0; + public static final int STATE_RECORD_RECORDING = 1; + public static final int STATE_RECORD_SUCCESS = 2; + + private int audioState = STATE_RECORD_NORMAL; + + private AudioPlayAndRecordManager audioManager; + private AudioRecorder audioRecorder; + private File audioFile; + private int audioDur; + private String audioUrl; + + private static final int WHAT_COUNT_PLAY = 1; + + /** + * 获取卡片信息 + */ + public void getCardInfo() { + AudioModel.get().getVoiceCardInfoList(AuthModel.get().getCurrentUid(), null, 10) + .compose(bindUntilEvent(PresenterEvent.DESTROY)) + .subscribe(new DontWarnObserver>() { + @Override + public void accept(List voiceCardInfos, String error) { + super.accept(voiceCardInfos, error); + if (getMvpView() == null) { + return; + } + if (error == null) { + if (ListUtils.isListEmpty(voiceCardInfos)) { + return; + } + getMvpView().addCardInfo(voiceCardInfos); + } + } + }); + } + + /** + * 初始化资源 + */ + public void initResource() { + audioManager = AudioPlayAndRecordManager.getInstance(); + } + + /** + * 离开页面处理 + */ + public void leaveThePage() { + if (audioRecorder != null && audioRecorder.isRecording()) { + stopRecord();// 录制过程被中断(如点了返回按钮或电话接入等):【自动跳转到试听状态】停止录音 + return; + } + if (AudioPlayerHelper.get().isPlaying()) { + AudioPlayerHelper.get().endPlay(); + if (getMvpView() != null) { + getMvpView().refreshListenerButton(false);// 返回页面时,此时正在播放声音,则停止播放并显示停止状态(播放按钮) + } + } + if (audioState == STATE_RECORD_SUCCESS) {// 已经录制未保存:未保存提示(确定则返回页面/取消则保留当前页面) + if (getMvpView() != null) { + getMvpView().showConfirmDialogWithLeave(); + } + } else { + if (getMvpView() != null) { + getMvpView().finishView(null);// 退出页面 + } + } + + } + + /** + * onPause()回调 + */ + public void pausePage() { + // 正在录制:则停止录制 + if (audioRecorder != null && audioRecorder.isRecording()) { + stopRecord();// onPause()时,如果正在录制,则停止录制 + } + // 正在播放:停止播放 + AudioPlayerHelper.get().onPause(); + if (getMvpView() != null) { + getMvpView().refreshListenerButton(false);// onPause() 停止播放并显示停止状态(播放按钮) + } + } + + /** + * 重录 + */ + public void reRecord() { + if (audioState == STATE_RECORD_SUCCESS) { + AudioPlayerHelper.get().endPlay(); + showNormalState();// 点击重录,回到初始状态 + } + } + + /** + * 试听按钮 + */ + public void clickRightIcon() { + if (audioState == STATE_RECORD_SUCCESS) { + if (AudioPlayerHelper.get().isPlaying()) { + AudioPlayerHelper.get().pausePlay(); + if (getMvpView() != null) { + getMvpView().refreshListenerButton(false);// 点击试听按钮此时正在播放声音,则暂停播放并显示停止状态(播放按钮) + } + } else if (AudioPlayerHelper.get().isPause()) { + AudioPlayerHelper.get().continuePlay(); + if (getMvpView() != null) { + getMvpView().refreshListenerButton(true);// 点击试听按钮此时正在暂停声音,则继续播放并显示播放状态(停止按钮) + } + } else if (AudioPlayerHelper.get().isPreparing()) { + AudioPlayerHelper.get().endPlay(); + if (getMvpView() != null) { + getMvpView().refreshListenerButton(false);// 点击试听按钮此时正在准备状态,则停止播放并显示停止状态(播放按钮) + } + } else { + if (null != audioFile && audioFile.exists()) { + MLog.debug(TAG, "play audioFilePath: " + audioFile.getPath()); + AudioPlayerHelper.get().playInThread(audioFile.getPath(), new OnPlayListener() { + @Override + public void onError(String error) { + if (getMvpView() != null) { + getMvpView().refreshListenerButton(false);// 出错:停止状态(播放按钮) + } + } + + @Override + public void onPrepared() { + if (getMvpView() != null) { + getMvpView().refreshListenerButton(true);// 准备完毕要开始播放:播放状态(暂停按钮) + } + } + + @Override + public void onPlaying(long currDuration) { + MLog.debug(TAG, "duration = " + currDuration); + if (getMvpView() != null) { + getMvpView().showCountDown((int) (currDuration / 1000)); + } + } + + @Override + public void onCompletion() { + if (getMvpView() != null) { + getMvpView().refreshListenerButton(false);// 播放完成:停止状态(播放按钮) + } + } + }); + if (getMvpView() != null) { + getMvpView().refreshListenerButton(true);// 点击试听按钮此时并没有正在播放声音,则播放声音并显示正在播放状态(暂停按钮) + } + } + } + } + } + + /** + * 中间按钮被点击 + */ + public void clickCenterIcon() { + switch (audioState) { + case STATE_RECORD_NORMAL: + startRecord();// 默认状态,点击了中间按钮:开始录音 + break; + case STATE_RECORD_RECORDING: + stopRecord();// 录制中状态,点击了中间按钮:停止录音 + break; + case STATE_RECORD_SUCCESS: + finishRecord();// 试听状态,点击了中间按钮:上传声音 + break; + } + } + + /** + * 停止录音 + */ + public void stopRecord() { + audioManager.stopRecord(false); + if (getMvpView() != null) { + getMvpView().stopChronometer(); + } + } + + /** + * 开始录音 + */ + private void startRecord() { + RoomInfo current = AvRoomDataManager.get().mCurrentRoomInfo; + if (current != null) { + if (getMvpView() != null) { + getMvpView().showConfirmDialogWithExitRoom(); + } + } else { + showRecordingState();// 开始录制,显示录制状态 + } + } + + /** + * 上传声音,完成录制 + */ + private void finishRecord() { + if (null != audioFile) { + Log.i("result_url", "upload before:" + audioFile.getAbsolutePath()); + if (getMvpView() != null) { + getMvpView().showLoadingView(); + } + FileModel.get() + .uploadFile(audioFile.getAbsolutePath()) + .compose(bindToLifecycle()) + .subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onSuccess(String url) { + audioUrl = url; + Log.i("result_url", "upload success:" + audioUrl); + saveVoice(); + } + + @Override + public void onError(Throwable e) { + SingleToastUtil.showToast(ResUtil.getString(R.string.audio_presenter_recordingvoicepresenter_01)); + if (getMvpView() != null) { + getMvpView().hideLoadingView();// 声音文件上传失败时 + } + } + }); + } + } + + /** + * 上传声音文件成功,提交保存声音 + */ + private void saveVoice() { + if (getMvpView() != null) { + Long piaId = getMvpView().getCardPiaId(); + Long changeVoiceId = getMvpView().getChangeVoiceId(); + AudioModel.get().saveVoice(AuthModel.get().getCurrentUid(), audioUrl, audioDur, changeVoiceId, piaId, 0) + .compose(bindUntilEvent(PresenterEvent.DESTROY)) + .subscribe(new DontWarnObserver() { + @Override + public void accept(SaveVoiceSuccessResultInfo saveVoiceSuccessResultInfo, String error) { + super.accept(saveVoiceSuccessResultInfo, error); + if (getMvpView() == null) { + return; + } + if (error == null) { + showNormalState();// 提交声音成功,显示初始状态 + getMvpView().hideLoadingView();// 提交声音成功时 + + SingleToastUtil.showToast(ResUtil.getString(R.string.audio_presenter_recordingvoicepresenter_03)); + Intent intent = new Intent(); + intent.putExtra(AUDIO_FILE, audioUrl); + intent.putExtra(AUDIO_DURA, audioDur); + getMvpView().finishView(intent);// 上传声音成功之后退出页面 + } else { + SingleToastUtil.showToast(error); + getMvpView().hideLoadingView();// 上传声音到用户信息中失败时 + } + } + }) + ; + } + } + + /** + * 显示默认状态,即初始状态 + */ + private void showNormalState() { + audioState = STATE_RECORD_NORMAL; + if (getMvpView() != null) { + getMvpView().refreshButtonView(audioState); + } + if (null != audioRecorder) { + audioRecorder.destroyAudioRecorder(); + audioRecorder = null; + } + } + + /** + * 显示录音中状态 + */ + private void showRecordingState() { + audioState = STATE_RECORD_RECORDING; + if (getMvpView() != null) { + getMvpView().refreshButtonView(audioState); + getMvpView().startChronometer(); + } + audioRecorder = audioManager.getAudioRecorder((Context) mMvpView, new IAudioRecordCallback() { + @Override + public void onRecordReady() { + Log.d(TAG, "onRecordReady"); + } + + @Override + public void onRecordStart(File audioFile, RecordType recordType) { + Log.d(TAG, "onRecordStart : " + audioFile.getPath() + "type: " + recordType.name()); + mHandler.sendEmptyMessage(WHAT_COUNT_PLAY); + if (getMvpView() != null) { + getMvpView().showVoiceWave(); + } + } + + @Override + public void onRecordSuccess(File file, long audioLength, RecordType recordType) { + double dura = (double) audioLength / 1000; + audioDur = (int) Math.round(dura); + audioFile = file; + Log.d(TAG, "onRecordSuccess : " + file.getPath() + + " dura:" + dura + + " length:" + audioDur + + " type:" + recordType.name()); + if (audioDur < MIN_RECORD_VOICE_DURATION) { + recordFailWithDurationShort();// 时长小于5s:Toast提示录音时间太短 + } else { + showRecordSuccessState();// 否则:【跳转到试听状态】 + } + mHandler.removeMessages(WHAT_COUNT_PLAY); + if (getMvpView() != null) { + getMvpView().hideVoiceWave(); + } + } + + @Override + public void onRecordFail() { + Log.d(TAG, "onRecordFail"); + recordFailWithDurationShort();// 录音结束,出错 + mHandler.removeMessages(WHAT_COUNT_PLAY); + if (getMvpView() != null) { + getMvpView().hideVoiceWave(); + } + } + + @Override + public void onRecordCancel() { + Log.d(TAG, "onRecordCancel"); + showNormalState();// 录制过程被取消,显示初始状态 + mHandler.removeMessages(WHAT_COUNT_PLAY); + if (getMvpView() != null) { + getMvpView().hideVoiceWave(); + } + } + + @Override + public void onRecordReachedMaxTime(int maxTime) { + Log.d(TAG, "onRecordReachedMaxTime"); +// double dura = (double) maxTime / 1000; +// int max = (int) Math.round(dura); + SingleToastUtil.showToast(ResUtil.getString(R.string.audio_presenter_recordingvoicepresenter_04)); + mHandler.removeMessages(WHAT_COUNT_PLAY); + if (getMvpView() != null) { + getMvpView().hideVoiceWave(); + } + } + }); + audioManager.startRecord(); + } + + /** + * 显示试听状态 + */ + private void showRecordSuccessState() { + audioState = STATE_RECORD_SUCCESS; + if (getMvpView() != null) { + getMvpView().refreshButtonView(audioState); + } + } + + /** + * 录音失败因时长太短 + */ + private void recordFailWithDurationShort() { + SingleToastUtil.showToast(ResUtil.getString(R.string.audio_presenter_recordingvoicepresenter_05)); + showNormalState();// 录制时长太短,显示初始状态 + } + + /** + * 释放资源 + */ + public void releaseResource() { + if (audioManager != null) { + audioManager.release(); + } + AudioPlayerHelper.get().onDestroy(); + if (getMvpView() != null) { + getMvpView().refreshListenerButton(false);// onDestroy() 停止播放并显示停止状态(播放按钮) + } + } + + private Handler mHandler = new Handler(new Handler.Callback() { + @Override + public boolean handleMessage(Message message) { + switch (message.what) { + case WHAT_COUNT_PLAY: + double ratio = (double) audioRecorder.getCurrentRecordMaxAmplitude() / 100; + double db = 0;// 分贝 + if (ratio > 1) { + db = 20 * Math.log10(ratio); + } + Log.d(TAG, ResUtil.getString(R.string.audio_presenter_recordingvoicepresenter_06) + db); + if (getMvpView() != null) { + getMvpView().refreshVoiceWave(db); + } + + mHandler.sendEmptyMessageDelayed(WHAT_COUNT_PLAY, 500L); + break; + } + return false; + } + }); +} diff --git a/app/src/main/java/com/chwl/app/audio/view/BottleContainer.java b/app/src/main/java/com/chwl/app/audio/view/BottleContainer.java new file mode 100644 index 0000000..1b0a9f2 --- /dev/null +++ b/app/src/main/java/com/chwl/app/audio/view/BottleContainer.java @@ -0,0 +1,290 @@ +package com.chwl.app.audio.view; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewTreeObserver; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.core.audio.bean.VoiceMatchInfo; +import com.chwl.library.utils.ListUtils; + +import java.util.ArrayList; +import java.util.List; + +import lombok.Setter; + +/** + * create by lvzebiao @2019/6/18 + */ +public class BottleContainer extends FrameLayout { + + private Context context; + + private List list = new ArrayList<>(); + + private int currPosition = 0; + + private int minOffset; + + private int maxOffset; + + public BottleContainer(@NonNull Context context) { + this(context, null); + } + + public BottleContainer(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + this.context = context; + minOffset = UIUtil.dip2px(context, 20); + maxOffset = UIUtil.dip2px(context, 270); + } + + public void initData(List list) { + if (!ListUtils.isListEmpty(list)) { + this.list.clear(); + this.list.addAll(list); + } + if (getChildCount() == 0) { + removeAllViews(); + initBottleViews(); + } + currPosition = 0; + initBottleData(); + } + + public void initBottleViews() { + BottleLayout smallBottle = new BottleLayout(context, false); + addView(smallBottle); + BottleLayout bigBottle = new BottleLayout(context, true); + addView(bigBottle); + bigBottle.setSvga(true); + smallBottle.setSvga(false); + } + + private void initBottleData() { + //设置大瓶子的数据 + setBigBottleDataAndSvga(); + //设置小瓶子的数据 + setSmallBottleDataAndSvga(); + //自动播放大瓶子的声音 + autoPlayBigBottleSound(); + //更新监听 + updateBottleStatus(); + //只有一个数据小瓶子隐藏 + updateVisibleStatus(); + } + + private void setBigBottleDataAndSvga() { + if (currPosition < list.size()) { + if (getChildCount() >= 2) { + //bigBottle + BottleLayout bigBottle = ((BottleLayout) getChildAt(1)); + bigBottle.setData(list.get(currPosition)); + bigBottle.stop(); + bigBottle.play(); + } + } + } + + private void setSmallBottleDataAndSvga() { + if (currPosition + 1 < list.size()) { + if (getChildCount() >= 1) { + //smallBottle + BottleLayout smallBottle = ((BottleLayout) getChildAt(0)); + smallBottle.setData(list.get(currPosition + 1)); + smallBottle.stop(); + smallBottle.play(); + } + } + } + + /** + * 自动播放大瓶子的声音 + */ + public void autoPlayBigBottleSound() { + if (getChildCount() >= 2) { + ((BottleLayout) getChildAt(1)).startPlay(); + } + } + + private void updateBottleStatus() { + + if (getChildCount() >= 2) { + //bigBottle + BottleLayout bigBottle = ((BottleLayout) getChildAt(1)); + bigBottle.setOnNextPageListener(new BottleOnNextPageListener()); + bigBottle.setCanDrag(true); + if (bigBottle.getTag() != null) { + bigBottle.getViewTreeObserver().removeOnGlobalLayoutListener( + (ViewTreeObserver.OnGlobalLayoutListener) bigBottle.getTag()); + bigBottle.setTag(null); + } + BottleLayoutListener listener = new BottleLayoutListener(); + bigBottle.getViewTreeObserver().addOnGlobalLayoutListener(listener); + bigBottle.setTag(listener); + } + if (getChildCount() >= 1) { + //smallBottle + BottleLayout smallBottle = ((BottleLayout) getChildAt(0)); + smallBottle.setOnNextPageListener(null); + smallBottle.setCanDrag(false); + if (smallBottle.getTag() != null) { + smallBottle.getViewTreeObserver().removeOnGlobalLayoutListener( + (ViewTreeObserver.OnGlobalLayoutListener) smallBottle.getTag()); + smallBottle.setTag(null); + } + } + + } + + public class BottleOnNextPageListener implements BottleLayout.OnNextPageListener { + + @Override + public void onLimit(boolean isRight) { + if (opListener != null) { + opListener.onLimit(isRight); + } + } + + @Override + public void onNext(boolean isRight) { + VoiceMatchInfo info = null; + if (currPosition < list.size()) { + info = list.get(currPosition); + } + if (getChildCount() == 2) { + //将上面第一个瓶子移除,并且添加到底下的瓶子,也就是大小瓶子位置互换 + BottleLayout bigBottle = (BottleLayout) getChildAt(1); + bigBottle.resetSoundPlayStatus(); + removeView(bigBottle); + + currPosition++; + if (bigBottle.getParent() == null) { + addView(bigBottle, 0); + setSmallBottleDataAndSvga(); + } else { + + } + updateVisibleStatus();// 切换到下一个瓶子时 + updateBottleStatus(); + if (currPosition < list.size()) { + autoPlayBigBottleSound(); + } + if (info != null) { + if (opListener != null) { + opListener.onLikeOrUnLike(info, isRight, currPosition >= list.size()); + } + } + } + } + } + + @Setter + private IBottleOpListener opListener; + + /** + * 更新显示的瓶子状态 + */ + private void updateVisibleStatus() { + if (currPosition == list.size() - 1 && getChildCount() >= 1) { + // 如果是最后一个瓶子,需要将底部的小瓶子隐藏掉 + getChildAt(0).setVisibility(View.INVISIBLE); + } else { + for (int i = 0; i < getChildCount(); i++) { + getChildAt(i).setVisibility(View.VISIBLE); + } + } + } + + + public class BottleLayoutListener implements ViewTreeObserver.OnGlobalLayoutListener { + + @Override + public void onGlobalLayout() { + if (getChildCount() != 2) { + return; + } + BottleLayout child = (BottleLayout) getChildAt(0); + FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) getChildAt(1).getLayoutParams(); + int leftMargin = params.leftMargin; + int topMargin = params.topMargin; + int dx = leftMargin - child.getInitLeft(); + int dy = topMargin - child.getInitTop(); + //平方后再开方 + int offset = (int) Math.sqrt(dx * dx + dy * dy); + if (offset < minOffset) { + offset = minOffset; + } + if (offset > maxOffset) { + offset = maxOffset; + } + float percent = (float) (offset - minOffset) / (maxOffset - minOffset); + + float scale = BottleLayout.MIN_SCALE_VALUE + (1f - BottleLayout.MIN_SCALE_VALUE) * percent; + child.setScaleX(scale); + child.setScaleY(scale); + } + } + + public void addBigBottleLikeCount() { + if (getChildCount() >= 2) { + BottleLayout bigBottle = (BottleLayout) getChildAt(1); + bigBottle.addLikeCount(); + } + } + + public void dealBigBottleLimit(boolean isLike) { + if (getChildCount() >= 2) { + BottleLayout bigBottle = (BottleLayout) getChildAt(1); + if (!bigBottle.isCanNext()) { + return; + } + bigBottle.dealWithLimit(isLike);// 点击按钮,受限制情况 + } + } + + public void dealToNext(boolean isLike) { + if (getChildCount() >= 2) { + BottleLayout bigBottle = (BottleLayout) getChildAt(1); + if (!bigBottle.isCanNext()) { + return; + } + bigBottle.toNext(isLike);// 点击按钮,不受限情况 + } + } + + public void resetBigBottlePlayStatus() { + if (getChildCount() >= 2) { + BottleLayout bigBottle = (BottleLayout) getChildAt(1); + bigBottle.resetSoundPlayStatus(); + } + } + + public void onlySetPlayOrStopIconForBigBottle(boolean isPlay) { + if (getChildCount() >= 2) { + BottleLayout bigBottle = (BottleLayout) getChildAt(1); + bigBottle.onlySetPlayOrStopIcon(isPlay); + } + } + + public void onDestroy() { + for (int i = 0; i < getChildCount(); i++) { + BottleLayout child = (BottleLayout) getChildAt(i); + if (child.getTag() != null) { + child.getViewTreeObserver().removeOnGlobalLayoutListener( + (ViewTreeObserver.OnGlobalLayoutListener) child.getTag()); + child.setTag(null); + } + child.setOnNextPageListener(null); + child.stop(); + } + opListener = null; + } + + +} diff --git a/app/src/main/java/com/chwl/app/audio/view/BottleLayout.java b/app/src/main/java/com/chwl/app/audio/view/BottleLayout.java new file mode 100644 index 0000000..03146df --- /dev/null +++ b/app/src/main/java/com/chwl/app/audio/view/BottleLayout.java @@ -0,0 +1,536 @@ +package com.chwl.app.audio.view; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.content.Context; +import android.text.TextUtils; +import android.view.MotionEvent; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; + +import com.coorchice.library.SuperTextView; +import com.opensource.svgaplayer.SVGAImageView; +import com.chwl.app.R; +import com.chwl.app.UIHelper; +import com.chwl.app.audio.VoiceMatchActivity; +import com.chwl.app.audio.helper.OnPlayListener; +import com.chwl.app.audio.helper.SvgaCacheManager; +import com.chwl.app.audio.helper.VmSoundManager; +import com.chwl.app.common.widget.CircleImageView; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.core.XConstants; +import com.chwl.core.audio.bean.VoiceMatchInfo; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.utils.SharedPreferenceUtils; +import com.chwl.core.utils.net.DontWarnObserver; +import com.chwl.core.utils.net.RxHelper; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; +import com.chwl.library.utils.TimeUtils; + +import java.math.BigDecimal; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Locale; +import java.util.concurrent.TimeUnit; + +import io.reactivex.Single; +import io.reactivex.android.schedulers.AndroidSchedulers; +import lombok.Getter; +import lombok.Setter; + +/** + * create by lvzebiao @2019/6/6 + */ +public class BottleLayout extends FrameLayout { + + public final static float MIN_SCALE_VALUE = 0.0f; + + private CircleImageView civAvatarBg; + private CircleImageView civAvatar; + private SVGAImageView svgaVoiceBubble; + private SVGAImageView svgaVoiceBottle; + private TextView tvNick; + private ImageView ivGender; + private SuperTextView stvConstellation; + private SuperTextView stvLocation; + private PlayLoadingImageView plivPlay; + private TextView tvLikeValue; + private ImageView ivReport; + + private int lastMoveX = 0; + private int lastMoveY = 0; + + int bigBottleWidth; + int bigBottleHeight; + int smallBottleWidth; + int smallBottleHeight; + /** + * 初始化时的左间距 + */ + int leftMargin; + + int topMargin; + + int parentWidth; + + @Getter + int initLeft; + + @Getter + int initTop; + + int minNextOffset; + + private boolean canDrag; + + private boolean animRun; + + private Context context; + + private VoiceMatchInfo voiceMatchInfo; + + public BottleLayout(@NonNull Context context) { + this(context, false); + } + + public BottleLayout(@NonNull Context context, boolean canDrag) { + super(context); + this.context = context; + this.canDrag = canDrag; + inflate(context, R.layout.layout_item_voice_bottle, this); + findView(); + + bigBottleWidth = UIUtil.dip2px(context, 295); + bigBottleHeight = UIUtil.dip2px(context, 441); + smallBottleWidth = bigBottleWidth / 3; + smallBottleHeight = bigBottleHeight / 3; + parentWidth = UIUtil.getScreenWidth(context); + topMargin = 0; + minNextOffset = UIUtil.dip2px(context, 80); + leftMargin = (parentWidth - bigBottleWidth) / 2; + initLeft = leftMargin; + initTop = topMargin; + resetParams(); + } + + private void findView() { + civAvatarBg = findViewById(R.id.civ_avatar_bg); + civAvatar = findViewById(R.id.civ_avatar); + svgaVoiceBubble = findViewById(R.id.svga_voice_bubble); + svgaVoiceBottle = findViewById(R.id.svga_voice_bottle); + tvNick = findViewById(R.id.tv_nick); + ivGender = findViewById(R.id.iv_gender); + stvConstellation = findViewById(R.id.stv_constellation); + stvLocation = findViewById(R.id.stv_location); + plivPlay = findViewById(R.id.pliv_play); + tvLikeValue = findViewById(R.id.tv_like_value); + ivReport = findViewById(R.id.iv_report); + } + + public void setSvga(boolean isBig) { + if (!SvgaCacheManager.get().isMoreAndroid7_0()) { + svgaVoiceBottle.setImageResource(R.drawable.bg_voice_match_android_6); + return; + } + if (isBig) { + if (SvgaCacheManager.get().getBigBottleSvga() != null) { + svgaVoiceBottle.setLoops(0); + svgaVoiceBottle.setImageDrawable(SvgaCacheManager.get().getBigBottleSvga()); + } + if (SvgaCacheManager.get().getBigBubbleSvga() != null) { + svgaVoiceBubble.setLoops(0); + svgaVoiceBubble.setImageDrawable(SvgaCacheManager.get().getBigBubbleSvga()); + } + } else { + if (SvgaCacheManager.get().getSmallBottleSvga() != null) { + svgaVoiceBottle.setLoops(0); + svgaVoiceBottle.setImageDrawable(SvgaCacheManager.get().getSmallBottleSvga()); + } + if (SvgaCacheManager.get().getSmallBubbleSvga() != null) { + svgaVoiceBubble.setLoops(0); + svgaVoiceBubble.setImageDrawable(SvgaCacheManager.get().getSmallBubbleSvga()); + } + } + } + + public void play() { + if (!SvgaCacheManager.get().isMoreAndroid7_0()) { + return; + } + if (!svgaVoiceBottle.isAnimating()) { + svgaVoiceBottle.startAnimation(); + } + if (!svgaVoiceBubble.isAnimating()) { + svgaVoiceBubble.startAnimation(); + } + } + + public void stop() { + svgaVoiceBottle.stopAnimation(); + svgaVoiceBubble.stopAnimation(); + } + + public void setCanDrag(boolean canDrag) { + this.canDrag = canDrag; + resetParams(); + } + + private void resetParams() { + LayoutParams params = new LayoutParams( + bigBottleWidth, bigBottleHeight); + params.leftMargin = initLeft; + params.topMargin = initTop; + setLayoutParams(params); + if (!canDrag) { + setScaleX(MIN_SCALE_VALUE); + setScaleY(MIN_SCALE_VALUE); + } else { + setScaleX(1.0f); + setScaleY(1.0f); + } + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent event) { + return super.onInterceptTouchEvent(event); + } + + @Override + public boolean performClick() { + return super.performClick(); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + //LogUtil.print(canDrag + "---Bottle---onTouchEvent---" + event.getAction()); + if (!canDrag || animRun) { + return super.onTouchEvent(event); + } + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + int downX = (int) event.getRawX(); + int downY = (int) event.getRawY(); + lastMoveX = downX; + lastMoveY = downY; + break; + + case MotionEvent.ACTION_MOVE: + + int disX = (int) (event.getRawX() - lastMoveX); + int disY = (int) (event.getRawY() - lastMoveY); + + //LogUtil.print("getLeft()=" + getLeft() + ", disX=" + disX); + leftMargin = getLeft() + disX; + topMargin = getTop() + disY; + //LogUtil.print("leftMargin=" + leftMargin + ", topMargin=" + topMargin); + + LayoutParams moveParams = new LayoutParams( + bigBottleWidth, bigBottleHeight + ); + moveParams.leftMargin = leftMargin; + moveParams.topMargin = topMargin; + setLayoutParams(moveParams); + + lastMoveX = (int) event.getRawX(); + lastMoveY = (int) event.getRawY(); + + break; + + case MotionEvent.ACTION_UP: + //手指离开的时候,回弹到初始位置 + if (Math.abs(getLeft() - initLeft) <= minNextOffset) { + recoveryToInit(); + } else { + boolean isRight = getLeft() > initLeft; + boolean isLimit = (boolean) SharedPreferenceUtils.get(VoiceMatchActivity.KEY_VOICE_MUST_LIMIT + AuthModel.get().getCurrentUid(), true); + if (isLimit) { + dealWithLimit(isRight);// 手势滑动,受限制情况 + } else { + toNext(isRight);// 不受限情况,允许左右滑动 + } + } + + break; + } + return true; + } + + public void dealWithLimit(boolean isRight) { + if (isRight) { + recoveryToInit(); + toLimit(true);// 限制右滑 + } else { + int limitCount = (int) SharedPreferenceUtils.get(VoiceMatchActivity.KEY_VOICE_LIMIT_COUNT + AuthModel.get().getCurrentUid(), 0); + if (limitCount >= 2) {// 0 1 索引为2时即为第三个声音 + recoveryToInit(); + toLimit(false);// 不喜欢第三个 限制左滑 + } else { + toNext(false);// 受限情况 但 左滑未超过三次,允许左滑 + limitCount = limitCount + 1; + SharedPreferenceUtils.put(VoiceMatchActivity.KEY_VOICE_LIMIT_COUNT + AuthModel.get().getCurrentUid(), limitCount); + } + } + } + + public boolean isCanNext() { + return !animRun; + } + + private void toLimit(boolean isRight) { + if (onNextPageListener != null) { + onNextPageListener.onLimit(isRight); + } + } + + public void toNext(boolean isRight) { + //如果切换下一页的时候,声音正在播放,则停止播放声音 + VmSoundManager.get().getHelper().endPlay(); + + animRun = true; + int endValue; + if (isRight) { + endValue = parentWidth; + } else { + endValue = -bigBottleWidth; + } + int duration = Math.abs(getLeft() - endValue) / 2; + if (duration < 100) { + duration = 100; + } else if (duration > 300) { + duration = 300; + } + ValueAnimator animator = ValueAnimator.ofInt(getLeft(), endValue); + animator.setDuration(duration); + animator.addUpdateListener(animation -> { + int curr = (int) animation.getAnimatedValue(); + LayoutParams params = (LayoutParams) getLayoutParams(); + params.leftMargin = curr; + setLayoutParams(params); + }); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + if (onNextPageListener != null) { + onNextPageListener.onNext(isRight); + } + Single.timer(200, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread()) + .subscribe(new DontWarnObserver() { + @Override + public void accept(Long aLong, String error) { + super.accept(aLong, error); + animRun = false; + } + }); + } + }); + animator.start(); + } + + @Setter + private OnNextPageListener onNextPageListener; + + public interface OnNextPageListener { + /** + * 受到限制 不给滑动 + * + * @param isRight 是否往右滑 + */ + void onLimit(boolean isRight); + + void onNext(boolean isRight); + } + + private void recoveryToInit() { + ValueAnimator xAnimator = ValueAnimator.ofInt(getLeft(), initLeft); + xAnimator.setDuration(150); + xAnimator.addUpdateListener(animation -> { + int currLeft = (int) animation.getAnimatedValue(); + LayoutParams params = (LayoutParams) getLayoutParams(); + params.leftMargin = currLeft; + setLayoutParams(params); + }); + xAnimator.start(); + + ValueAnimator yAnimator = ValueAnimator.ofInt(getTop(), initTop); + yAnimator.setDuration(150); + yAnimator.addUpdateListener(animation -> { + int currValue = (int) animation.getAnimatedValue(); + LayoutParams params = (LayoutParams) getLayoutParams(); + params.topMargin = currValue; + setLayoutParams(params); + }); + yAnimator.start(); + + } + + public void setData(VoiceMatchInfo info) { + voiceMatchInfo = info; + if (info == null) { + return; + } + ImageLoadUtils.loadAvatarBig(info.getAvatar(), civAvatar); + ImageLoadUtils.loadImageWithBlur(context, ImageLoadUtils.getAvatarSizeUrl(info.getAvatar()), civAvatarBg, 20, 2); + String showNick = info.getNick(); + if (showNick == null) { + showNick = ""; + } + if (showNick.length() >= 6) { + showNick = showNick.substring(0, 5) + "…"; + } + tvNick.setText(showNick); + ivGender.setImageResource(info.getGender() == 1 ? R.drawable.ic_gender_male : R.drawable.ic_gender_female); + stvConstellation.setText(TimeUtils.msToConstellation(info.getBirth())); + String location = info.getLocation(); + if (TextUtils.isEmpty(location)) { + stvLocation.setVisibility(GONE); + } else { + stvLocation.setVisibility(VISIBLE); + if (location.length() >= 5) { + location = location.substring(0, 4) + "…"; + } + stvLocation.setText(location); + } + + lastClickPlayTime = System.currentTimeMillis(); + + plivPlay.setOnClickListener(v -> { + //加个容错处理,防止频繁点击播放按钮 + long currTime = System.currentTimeMillis(); + if (currTime - lastClickPlayTime < 400) { + return; + } + if (isDelaying) { + return; + } + lastClickPlayTime = currTime; + if (VmSoundManager.get().getHelper().isPreparing()) { + VmSoundManager.get().getHelper().endPlay(); + resetSoundPlayStatus(); + return; + } + if (VmSoundManager.get().getHelper().isPlaying()) { + VmSoundManager.get().getHelper().pausePlay(); + plivPlay.setImageResource(R.drawable.icon_voice_to_start); + return; + } + if (VmSoundManager.get().getHelper().isPause()) { + VmSoundManager.get().getHelper().continuePlay(); + plivPlay.setImageResource(R.drawable.icon_voice_to_stop); + return; + } + startPlay(); + }); + + ivReport.setOnClickListener(view -> { + // 跳转到举报页面 + UIHelper.showReportPage(context, info.getUid(), XConstants.REPORT_TYPE_VOICE); + }); + + } + + public void startPlay() { + if (!canDrag) { + return; + } + if (voiceMatchInfo == null) { + return; + } + tvLikeValue.setTag(voiceMatchInfo.getLikeCount()); + tvLikeValue.setText(formatLikeCount(voiceMatchInfo.getLikeCount())); + plivPlay.setImageResource(R.drawable.icon_voice_to_stop); + VmSoundManager.get().getHelper().playInThread(voiceMatchInfo.getVoiceUrl(), true, new OnPlayListener() { + + @Override + public void onError(String error) { + resetSoundPlayStatus(); + SingleToastUtil.showToast(error); + } + + @Override + public void onPrepared() { + duration = VmSoundManager.get().getHelper().getDuration(); + plivPlay.setMaxProgress(duration); + } + + @Override + public void onPlaying(long currDuration) { + plivPlay.setProgress(currDuration, duration); + } + + @Override + public void onCompletion() { + plivPlay.setProgress(duration, duration); + isDelaying = true; + Single.timer(150, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread()) + .compose(RxHelper.bindContext(context)) + .subscribe(new DontWarnObserver() { + @Override + public void acceptThrowable(Long aLong, Throwable throwable) { + super.acceptThrowable(aLong, throwable); + resetSoundPlayStatus(); + isDelaying = false; + } + }); + } + }); + + } + + public void addLikeCount() { + tvLikeValue.post(() -> { + if (tvLikeValue.getTag() instanceof Integer) { + int tagLikeCount = (Integer) tvLikeValue.getTag(); + tvLikeValue.setText(String.valueOf(tagLikeCount + 1)); + } + }); + } + + public void resetSoundPlayStatus() { + plivPlay.setImageResource(R.drawable.icon_voice_to_start); + plivPlay.setProgress(0, 1000); + } + + public void onlySetPlayOrStopIcon(boolean isPlay) { + plivPlay.setImageResource(isPlay ? R.drawable.icon_voice_to_start : R.drawable.icon_voice_to_stop); + } + + private long duration; + + + private long lastClickPlayTime = 0; + /** + * 播放结束后,会有延迟让按钮回到最初状态,如果正在延迟中的话,则禁止操作 + */ + private boolean isDelaying = false; + + private String formatLikeCount(int likeCount) { + String showText; + if (likeCount < 0) { + showText = "0"; + } else if (likeCount < 10000) { + showText = String.valueOf(likeCount); + } else { + double likeCountDouble = (double) likeCount; + double num = likeCountDouble / 10000; + + DecimalFormat decimalFormat = new DecimalFormat("0.00");// 构造方法的字符格式这里如果小数不足2位,会以0补足. + decimalFormat.setDecimalFormatSymbols(DecimalFormatSymbols.getInstance(Locale.ENGLISH)); + BigDecimal bigDecimal = new BigDecimal(num); + double likeCountFormat = bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue(); + if (likeCountFormat > 9999) { + showText = ResUtil.getString(R.string.audio_view_bottlelayout_05); + } else { + showText = decimalFormat.format(likeCountFormat) + ResUtil.getString(R.string.audio_view_bottlelayout_06); + } + } + return showText; + } + +} diff --git a/app/src/main/java/com/chwl/app/audio/view/IBottleOpListener.java b/app/src/main/java/com/chwl/app/audio/view/IBottleOpListener.java new file mode 100644 index 0000000..e580e90 --- /dev/null +++ b/app/src/main/java/com/chwl/app/audio/view/IBottleOpListener.java @@ -0,0 +1,14 @@ +package com.chwl.app.audio.view; + +import com.chwl.core.audio.bean.VoiceMatchInfo; + +/** + * create by lvzebiao @2019/6/19 + */ +public interface IBottleOpListener { + + void onLimit(boolean isRight); + + void onLikeOrUnLike(VoiceMatchInfo info, boolean isRight, boolean needLoading); + +} diff --git a/app/src/main/java/com/chwl/app/audio/view/IMyVoiceView.java b/app/src/main/java/com/chwl/app/audio/view/IMyVoiceView.java new file mode 100644 index 0000000..72a5b9f --- /dev/null +++ b/app/src/main/java/com/chwl/app/audio/view/IMyVoiceView.java @@ -0,0 +1,23 @@ +package com.chwl.app.audio.view; + +import com.chwl.core.audio.bean.UserVoiceInfo; +import com.chwl.library.base.IMvpBaseView; + +import java.util.List; + +/** + * 我的声音页面 + */ +public interface IMyVoiceView extends IMvpBaseView { + /** + * 显示声音数据消息 + */ + void showVoiceInfo(List voiceList); + + /** + * 请稍后 + */ + void showLoadingView(); + + void hideLoadingView(); +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/audio/view/IRecordingVoiceView.java b/app/src/main/java/com/chwl/app/audio/view/IRecordingVoiceView.java new file mode 100644 index 0000000..62e658e --- /dev/null +++ b/app/src/main/java/com/chwl/app/audio/view/IRecordingVoiceView.java @@ -0,0 +1,79 @@ +package com.chwl.app.audio.view; + +import android.content.Intent; + +import com.chwl.core.audio.bean.VoiceCardInfo; +import com.chwl.library.base.IMvpBaseView; + +import java.util.List; + +/** + * 录制声音页面 + */ +public interface IRecordingVoiceView extends IMvpBaseView { + + /** + * 添加卡片信息 + */ + void addCardInfo(List cardInfoList); + + /** + * 获取当前pia剧本id + */ + Long getCardPiaId(); + + /** + * 刷新按钮的状态 + */ + void refreshButtonView(int state); + + /** + * 刷新试听按钮 + */ + void refreshListenerButton(boolean isPlaying); + + /** + * 开始倒计时 + */ + void startChronometer(); + + /** + * 停止倒计时 + */ + void stopChronometer(); + + /** + * 确认退出页面对话框 + */ + void showConfirmDialogWithLeave(); + + /** + * 退出页面 + */ + void finishView(Intent intent); + + /** + * 关闭房间再录音 + */ + void showConfirmDialogWithExitRoom(); + + /** + * 请稍后 + */ + void showLoadingView(); + + void hideLoadingView(); + + /** + * 获取被重新录制的声音的ID:打开页面的时候传入,可以为空 + */ + Long getChangeVoiceId(); + + void refreshVoiceWave(double db); + + void showVoiceWave(); + + void hideVoiceWave(); + + void showCountDown(int duration); +} diff --git a/app/src/main/java/com/chwl/app/audio/view/PlayLoadingImageView.java b/app/src/main/java/com/chwl/app/audio/view/PlayLoadingImageView.java new file mode 100644 index 0000000..8a851ed --- /dev/null +++ b/app/src/main/java/com/chwl/app/audio/view/PlayLoadingImageView.java @@ -0,0 +1,96 @@ +package com.chwl.app.audio.view; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.RectF; +import android.util.AttributeSet; + +import androidx.appcompat.widget.AppCompatImageView; + +import com.chwl.app.R; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; + +import lombok.Setter; + +/** + * create by lvzebiao @2019/6/12 + */ +public class PlayLoadingImageView extends AppCompatImageView { + + private long progress; + + RectF rectF; + + private Paint paint; + + private int color_white; + + private int color_32ECD9; + + private int color_F2F4F4; + + private int loading_width; + + @Setter + private long maxProgress = 1000; + + public PlayLoadingImageView(Context context, AttributeSet attrs) { + super(context, attrs); + loading_width = UIUtil.dip2px(context, 2); + rectF = new RectF(); + paint = new Paint(); + paint.setAntiAlias(true); + paint.setStyle(Paint.Style.STROKE); + paint.setStrokeWidth(loading_width); + color_white = context.getResources().getColor(R.color.white); + color_32ECD9 = context.getResources().getColor(R.color.color_32ECD9); + color_F2F4F4 = context.getResources().getColor(R.color.color_F2F4F4); + + + left = (float) loading_width / 2; + top = (float) loading_width / 2; + } + + private float left, top, rigth, end; + + @Override + protected void onDraw(Canvas canvas) { + + rectF.set(left, top, getWidth() - left, getHeight() - top); + + paint.setColor(color_F2F4F4); + float radiu = (float) (getWidth() - loading_width) / 2; + canvas.drawCircle((float) getWidth() / 2, (float) getHeight() / 2, radiu, paint); + + paint.setColor(color_32ECD9); + int degree; + if (maxProgress > 0) { + degree = (int) (progress * 360 / maxProgress); + } else { + degree = 0; + } + canvas.drawArc(rectF, -90, degree, false, paint); + + super.onDraw(canvas); + } + + public void setProgress(long progress, long maxProgress) { + if (progress > maxProgress) { + progress = maxProgress; + } else if (progress < 0) { + progress = 0; + } + if (maxProgress - progress <= 500) { + //LogUtil.print(ResUtil.getString(R.string.audio_view_playloadingimageview_01)); + progress = maxProgress; + } + if (progress == this.progress && maxProgress == this.maxProgress) { + //加载进度一样,不需要重绘 + return; + } + this.progress = progress; + this.maxProgress = maxProgress; + invalidate(); + } +} diff --git a/app/src/main/java/com/chwl/app/audio/viewmodel/SoundViewModel.kt b/app/src/main/java/com/chwl/app/audio/viewmodel/SoundViewModel.kt new file mode 100644 index 0000000..b77ea9d --- /dev/null +++ b/app/src/main/java/com/chwl/app/audio/viewmodel/SoundViewModel.kt @@ -0,0 +1,377 @@ +package com.chwl.app.audio.viewmodel + +import android.content.Intent +import android.util.Log +import androidx.lifecycle.MutableLiveData +import com.netease.nimlib.sdk.media.record.AudioRecorder +import com.netease.nimlib.sdk.media.record.IAudioRecordCallback +import com.netease.nimlib.sdk.media.record.RecordType +import com.chwl.app.R +import com.chwl.app.audio.SoundSignatureActivity +import com.chwl.app.audio.helper.AudioPlayerHelper +import com.chwl.app.audio.helper.OnPlayListener +import com.chwl.app.base.BaseViewModel +import com.chwl.core.Constants +import com.chwl.core.audio.AudioPlayAndRecordManager +import com.chwl.core.auth.AuthModel +import com.chwl.core.manager.AudioEngineManager +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.sound.model.SoundModel +import com.chwl.core.utils.extension.toast +import com.chwl.library.common.application.BaseApp +import com.chwl.library.utils.ResUtil +import com.chwl.library.utils.SingleToastUtil +import com.chwl.library.utils.log.MLog +import java.io.File + +/** + * @author wushaocheng + * 声音签名 + */ +class SoundViewModel : BaseViewModel() { + + companion object { + const val TAG = "RecordingVoiceActivity" + const val STATE_RECORD_NORMAL = 0//普通状态 + const val STATE_RECORD_RECORDING = 1//录音中 + const val STATE_RECORD_SUCCESS = 2//录音完成 + const val STATE_RECORD_SAVE_SUCCESS = 3//保存成功 + const val STATE_RECORD_AUDIT_SUCCESS = 4//审核成功 + } + + var audioState = STATE_RECORD_NORMAL + + private var audioManager: AudioPlayAndRecordManager? = null + private var audioRecorder: AudioRecorder? = null + var audioFile: File? = null + var audioDur = 0 + var audioUrl: String? = null + + private var isRemoteMute = false //是否静音 + private var isMute = true //是否开麦 + + private val _showConfirmLiveData = MutableLiveData() + val showConfirmLiveData: MutableLiveData = _showConfirmLiveData + + private val _refreshLiveData = MutableLiveData() + val refreshLiveData: MutableLiveData = _refreshLiveData + + private val _startChronometerLiveData = MutableLiveData() + val startChronometerLiveData: MutableLiveData = _startChronometerLiveData + + private val _stopChronometerLiveData = MutableLiveData() + val stopChronometerLiveData: MutableLiveData = _stopChronometerLiveData + + private val _refreshPlayStatusLiveData = MutableLiveData() + val refreshPlayStatusLiveData: MutableLiveData = _refreshPlayStatusLiveData + + private val _resetStatusLiveData = MutableLiveData() + val resetStatusLiveData: MutableLiveData = _resetStatusLiveData + + private val _showCountDownLiveData = MutableLiveData() + val showCountDownLiveData: MutableLiveData = _showCountDownLiveData + + private val _finishViewLiveData = MutableLiveData() + val finishViewLiveData: MutableLiveData = _finishViewLiveData + + private val _hideLoadLiveData = MutableLiveData() + val hideLoadLiveData: MutableLiveData = _hideLoadLiveData + + private val _saveRecordLiveData = MutableLiveData() + val saveRecordLiveData: MutableLiveData = _saveRecordLiveData + + private val _deleteRecordLiveData = MutableLiveData() + val deleteRecordLiveData: MutableLiveData = _deleteRecordLiveData + + private val _showSaveConfirmDialogLiveData = MutableLiveData() + val showSaveConfirmDialogLiveData: MutableLiveData = _showSaveConfirmDialogLiveData + + private val _showRecordConfirmDialogLiveData = MutableLiveData() + val showRecordConfirmDialogLiveData: MutableLiveData = _showRecordConfirmDialogLiveData + + init { + if (AvRoomDataManager.get().mCurrentRoomInfo != null) { + val roomQueueInfo = AvRoomDataManager.get() + .getRoomQueueMemberInfoByAccount(AuthModel.get().currentUid.toString()) + if (roomQueueInfo?.mRoomMicInfo != null) { + isMute = AudioEngineManager.get().isMute + } + isRemoteMute = AudioEngineManager.get().isRemoteMute + } + audioManager = AudioPlayAndRecordManager.getInstance() + } + + /** + * 中间按钮被点击 + */ + fun clickCenterIcon() { + when (audioState) { + STATE_RECORD_NORMAL -> startRecord() // 默认状态,点击了中间按钮:开始录音 + STATE_RECORD_RECORDING -> stopRecord() // 录制中状态,点击了中间按钮:停止录音 + STATE_RECORD_SUCCESS -> clickAudition() // 试听状态,点击了中间按钮:试听声音 + STATE_RECORD_SAVE_SUCCESS -> clickAudition() //保存成功,点击了中间按钮:试听声音 + STATE_RECORD_AUDIT_SUCCESS -> clickAudition() //审核成功,点击了中间按钮,试听声音 + } + } + + /** + * 开始录音 + */ + private fun startRecord() { + val current = AvRoomDataManager.get().mCurrentRoomInfo + if (current != null) { + _showConfirmLiveData.value = null + } else { + showRecordingState() // 开始录制,显示录制状态 + } + } + + /** + * 显示录音中状态 + */ + fun showRecordingState() { + audioState = STATE_RECORD_RECORDING + _refreshLiveData.value = audioState + audioRecorder = + audioManager?.getAudioRecorder(BaseApp.getContext(), object : IAudioRecordCallback { + override fun onRecordReady() { + Log.d(TAG, "onRecordReady") + } + + override fun onRecordStart(audioFile: File, recordType: RecordType) { + Log.d(TAG, "onRecordStart : " + audioFile.path + "type: " + recordType.name) + _startChronometerLiveData.value = null + } + + override fun onRecordSuccess( + file: File, + audioLength: Long, + recordType: RecordType + ) { + val dura = audioLength.toDouble() / 1000 + audioDur = dura.toInt() + audioFile = file + Log.d( + TAG, "onRecordSuccess : " + file.path + + " dura:" + dura + + " length:" + audioDur + + " type:" + recordType.name + ) + if (audioDur < SoundSignatureActivity.MIN_RECORD_VOICE_DURATION) { + recordFailWithDurationShort() // 时长小于1s:Toast提示录音时间太短 + } else { + showRecordSuccessState() // 否则:【跳转到试听状态】 + } + } + + override fun onRecordFail() { + Log.d(TAG, "onRecordFail") + recordFailWithDurationShort() // 录音结束,出错 + } + + override fun onRecordCancel() { + Log.d(TAG, "onRecordCancel") + showNormalState() // 录制过程被取消,显示初始状态 + } + + override fun onRecordReachedMaxTime(maxTime: Int) { + Log.d(TAG, "onRecordReachedMaxTime") + SingleToastUtil.showToast(ResUtil.getString(R.string.audio_presenter_recordingvoicepresenter_04)) + } + }) + audioManager?.startRecord() + } + + /** + * 录音失败因时长太短 + */ + private fun recordFailWithDurationShort() { + SingleToastUtil.showToast(ResUtil.getString(R.string.audio_presenter_recordingvoicepresenter_05)) + showNormalState() // 录制时长太短,显示初始状态 + } + + /** + * 显示默认状态,即初始状态 + */ + fun showNormalState() { + // 正在播放:停止播放 + AudioPlayerHelper.get().endPlay() + openRoomSound() + audioState = STATE_RECORD_NORMAL + audioUrl = null + audioDur = 0 + audioFile = null + _refreshLiveData.value = audioState + if (null != audioRecorder) { + audioRecorder?.destroyAudioRecorder() + audioRecorder = null + } + } + + /** + * 显示试听状态 + */ + private fun showRecordSuccessState() { + audioState = STATE_RECORD_SUCCESS + _refreshLiveData.value = audioState + } + + /** + * 停止录音 + */ + fun stopRecord() { + audioManager?.stopRecord(false) + openRoomSound() + _stopChronometerLiveData.value = null + } + + fun reRecord() { + if (audioState == STATE_RECORD_SUCCESS || audioState == STATE_RECORD_SAVE_SUCCESS || audioState == STATE_RECORD_AUDIT_SUCCESS) { + showNormalState() // 点击重录,回到初始状态 + } + } + + /** + * onPause()回调 + */ + fun pausePage() { + // 正在录制:则停止录制 + if (audioRecorder != null && audioRecorder?.isRecording == true) { + stopRecord() // onPause()时,如果正在录制,则停止录制 + } + // 正在播放:停止播放 + AudioPlayerHelper.get().onPause() + openRoomSound() + if (audioState != STATE_RECORD_NORMAL) { + _refreshPlayStatusLiveData.value = false // onPause() 停止播放并显示停止状态(播放按钮) + } + } + + /** + * 释放资源 + */ + fun releaseResource() { + audioManager?.release() + AudioPlayerHelper.get().onDestroy() + } + + /** + * 离开页面处理 + */ + fun leaveThePage() { + if (audioRecorder != null && audioRecorder?.isRecording == true) { + stopRecord() // 录制过程被中断(如点了返回按钮或电话接入等):【自动跳转到试听状态】停止录音 + return + } + if (AudioPlayerHelper.get().isPlaying) { + AudioPlayerHelper.get().endPlay() + openRoomSound() + _refreshPlayStatusLiveData.value = false // 返回页面时,此时正在播放声音,则停止播放并显示停止状态(播放按钮) + } + if (audioState == STATE_RECORD_SUCCESS) { // 已经录制未保存:未保存提示(确定则返回页面/取消则保留当前页面) + _showSaveConfirmDialogLiveData.value = null + } else { + _finishViewLiveData.value = null// 退出页面 + } + } + + /** + * 试听按钮 + */ + private fun clickAudition() { + if (audioState == STATE_RECORD_SUCCESS || audioState == STATE_RECORD_SAVE_SUCCESS || audioState == STATE_RECORD_AUDIT_SUCCESS) { + if (AudioPlayerHelper.get().isPlaying) { + AudioPlayerHelper.get().pausePlay() + openRoomSound() + _refreshPlayStatusLiveData.value = false// 点击试听按钮此时正在播放声音,则暂停播放并显示停止状态(播放按钮) + } else if (AudioPlayerHelper.get().isPause) { + AudioPlayerHelper.get().continuePlay() + stopRoomSound() + _refreshPlayStatusLiveData.value = true// 点击试听按钮此时正在暂停声音,则继续播放并显示播放状态(停止按钮) + } else if (AudioPlayerHelper.get().isPreparing) { + AudioPlayerHelper.get().endPlay() + openRoomSound() + _refreshPlayStatusLiveData.value = false// 点击试听按钮此时正在准备状态,则停止播放并显示停止状态(播放按钮) + } else { + if (null != audioFile && audioFile?.exists() == true) { + MLog.debug(TAG, "play audioFilePath: " + audioFile?.path) + playSound(audioFile?.path) + } else if (null != audioUrl && audioUrl?.contains("http") == true) { + MLog.debug(TAG, "play audioUrl: $audioUrl") + playSound(audioUrl) + } + } + } + } + + /** + * 播放录音 + */ + private fun playSound(path: String?) { + AudioPlayerHelper.get().playInThread(path, object : OnPlayListener { + override fun onError(error: String) { + _refreshPlayStatusLiveData.value = false // 出错:停止状态(播放按钮) + } + + override fun onPrepared() { + stopRoomSound() + _refreshPlayStatusLiveData.value = true// 准备完毕要开始播放:播放状态(暂停按钮) + } + + override fun onPlaying(currDuration: Long) { + MLog.debug( + TAG, + "duration = $currDuration" + ) + _showCountDownLiveData.value = currDuration.toInt() + } + + override fun onCompletion() { + openRoomSound() + _refreshPlayStatusLiveData.value = false// 播放完成:停止状态(播放按钮) + _resetStatusLiveData.value = null + } + }) + _refreshPlayStatusLiveData.value = true// 点击试听按钮此时并没有正在播放声音,则播放声音并显示正在播放状态(暂停按钮) + } + + fun stopRoomSound() { + if (AvRoomDataManager.get().mCurrentRoomInfo != null) { + AudioEngineManager.get().isRemoteMute = true //設置靜音 + AudioEngineManager.get().isMute = true //不能説話 + AudioEngineManager.get().setRole(Constants.CLIENT_ROLE_AUDIENCE) + } + } + + fun openRoomSound() { + if (AvRoomDataManager.get().mCurrentRoomInfo != null) { + AudioEngineManager.get().isRemoteMute = isRemoteMute //非靜音 + AudioEngineManager.get().isMute = isMute //能説話 + AudioEngineManager.get() + .setRole(if (isMute) Constants.CLIENT_ROLE_AUDIENCE else Constants.CLIENT_ROLE_BROADCASTER) + } + } + + fun saveRecord(audioUrl: String, second: Int = audioDur) { + this.audioUrl = audioUrl + safeLaunch( + onError = { + it.message.toast() + _hideLoadLiveData.value = null + }, + block = { + _saveRecordLiveData.value = SoundModel.saveRecord(audioUrl, second) + } + ) + } + + fun deleteRecord() { + safeLaunch( + true, + block = { + _deleteRecordLiveData.value = SoundModel.deleteRecord() + } + ) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/audio/widget/DynamicWave.java b/app/src/main/java/com/chwl/app/audio/widget/DynamicWave.java new file mode 100644 index 0000000..42ccb37 --- /dev/null +++ b/app/src/main/java/com/chwl/app/audio/widget/DynamicWave.java @@ -0,0 +1,121 @@ +package com.chwl.app.audio.widget; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.DrawFilter; +import android.graphics.Paint; +import android.graphics.PaintFlagsDrawFilter; +import android.util.AttributeSet; +import android.view.View; + +import com.netease.nim.uikit.common.util.sys.ScreenUtil; + +/** + * Created by liruiyuan on 2015/12/21. + */ +public class DynamicWave extends View { + // y = Asin(wx+b)+h + private static final float STRETCH_FACTOR_A = 20; + private static final int OFFSET_Y = -50; + // 第一条水波移动速度 + private static final int TRANSLATE_X_SPEED_ONE = 7; + // 第二条水波移动速度 + private static final int TRANSLATE_X_SPEED_TWO = 5; + private float mCycleFactorW; + + private int mTotalWidth, mTotalHeight; + private float[] mYPositions; + private float[] mResetOneYPositions; + private float[] mResetTwoYPositions; + private int mXOffsetSpeedOne; + private int mXOffsetSpeedTwo; + private int mXOneOffset; + private int mXTwoOffset; + + private Paint mWavePaint; + private DrawFilter mDrawFilter; + + public DynamicWave(Context context, AttributeSet attrs) { + super(context, attrs); + // 将dp转化为px,用于控制不同分辨率上移动速度基本一致 + mXOffsetSpeedOne = ScreenUtil.dip2px(TRANSLATE_X_SPEED_ONE); + mXOffsetSpeedTwo = ScreenUtil.dip2px(TRANSLATE_X_SPEED_TWO); + + // 初始绘制波纹的画笔 + mWavePaint = new Paint(); + // 去除画笔锯齿 + mWavePaint.setAntiAlias(true); + // 设置风格为实线 + mWavePaint.setStyle(Paint.Style.FILL); + // 设置画笔颜色 + mWavePaint.setColor(Color.parseColor("#26FFFFFF")); + mDrawFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + // 从canvas层面去除绘制时锯齿 + canvas.setDrawFilter(mDrawFilter); + resetPositonY(); + for (int i = 0; i < mTotalWidth; i++) { + + // 减400只是为了控制波纹绘制的y在屏幕的位置,大家可以改成一个变量,然后动态改变这个变量,从而形成波纹上升下降效果 + // 绘制第一条水波纹 + canvas.drawLine(i, mTotalHeight - mResetOneYPositions[i] - 200, i, mTotalHeight, mWavePaint); + + // 绘制第二条水波纹 + canvas.drawLine(i, mTotalHeight - mResetTwoYPositions[i] - 200, i, mTotalHeight, mWavePaint); + } + + // 改变两条波纹的移动点 + mXOneOffset += mXOffsetSpeedOne; + mXTwoOffset += mXOffsetSpeedTwo; + + // 如果已经移动到结尾处,则重头记录 + if (mXOneOffset >= mTotalWidth) { + mXOneOffset = 0; + } + if (mXTwoOffset > mTotalWidth) { + mXTwoOffset = 0; + } + + // 引发view重绘,一般可以考虑延迟20-30ms重绘,空出时间片 + postInvalidate(); + } + + private void resetPositonY() { + // mXOneOffset代表当前第一条水波纹要移动的距离 + int yOneInterval = mYPositions.length - mXOneOffset; + // 使用System.arraycopy方式重新填充第一条波纹的数据 + System.arraycopy(mYPositions, mXOneOffset, mResetOneYPositions, 0, yOneInterval); + System.arraycopy(mYPositions, 0, mResetOneYPositions, yOneInterval, mXOneOffset); + + int yTwoInterval = mYPositions.length - mXTwoOffset; + System.arraycopy(mYPositions, mXTwoOffset, mResetTwoYPositions, 0, yTwoInterval); + System.arraycopy(mYPositions, 0, mResetTwoYPositions, yTwoInterval, mXTwoOffset); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + // 记录下view的宽高 + mTotalWidth = w; + mTotalHeight = h; + // 用于保存原始波纹的y值 + mYPositions = new float[mTotalWidth]; + // 用于保存波纹一的y值 + mResetOneYPositions = new float[mTotalWidth]; + // 用于保存波纹二的y值 + mResetTwoYPositions = new float[mTotalWidth]; + + // 将周期定为view总宽度 + mCycleFactorW = (float) (2 * Math.PI / mTotalWidth); + + // 根据view总宽度得出所有对应的y值 + for (int i = 0; i < mTotalWidth; i++) { + mYPositions[i] = (float) (STRETCH_FACTOR_A * Math.sin(mCycleFactorW * i) + OFFSET_Y); + } + } +} diff --git a/app/src/main/java/com/chwl/app/audio/widget/OnSwipeListener.java b/app/src/main/java/com/chwl/app/audio/widget/OnSwipeListener.java new file mode 100644 index 0000000..f44db1f --- /dev/null +++ b/app/src/main/java/com/chwl/app/audio/widget/OnSwipeListener.java @@ -0,0 +1,28 @@ +package com.chwl.app.audio.widget; + +import androidx.recyclerview.widget.RecyclerView; + +/** + * 录制声音页面.声音卡片滑动监听 + */ +public interface OnSwipeListener { + /** + * 卡片还在滑动时回调 + * + * @param viewHolder 该滑动卡片的viewHolder + * @param ratio 滑动进度的比例 + * @param direction 卡片滑动的方向,CardConfig.SWIPING_LEFT 为向左滑,CardConfig.SWIPING_RIGHT 为向右滑, + * CardConfig.SWIPING_NONE 为不偏左也不偏右 + */ + void onSwiping(RecyclerView.ViewHolder viewHolder, float ratio, int direction); + + /** + * 卡片完全滑出时回调 + * + * @param viewHolder 该滑出卡片的viewHolder + * @param pos 该滑出卡片的索引 + * @param direction 卡片滑出的方向,CardConfig.SWIPED_LEFT 为左边滑出;CardConfig.SWIPED_RIGHT 为右边滑出 + */ + void onSwiped(RecyclerView.ViewHolder viewHolder, int pos, int direction); + +} diff --git a/app/src/main/java/com/chwl/app/audio/widget/RingProgressView.java b/app/src/main/java/com/chwl/app/audio/widget/RingProgressView.java new file mode 100644 index 0000000..956d03b --- /dev/null +++ b/app/src/main/java/com/chwl/app/audio/widget/RingProgressView.java @@ -0,0 +1,115 @@ +package com.chwl.app.audio.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.RectF; +import android.util.AttributeSet; +import android.view.View; + +import androidx.annotation.Nullable; + +import com.netease.nim.uikit.common.util.sys.ScreenUtil; +import com.chwl.app.R; + +/** + * 录制声音页面的环形进度条 + */ +public class RingProgressView extends View { + // 圆环的颜色 + private int ringColor = 0x00FFFFFF; + // 圆环进度的颜色 + private int ringProgressColor = 0xFFFFFFFF; + // 圆环的宽度 + private int ringWidth = ScreenUtil.dip2px(4); + // 当前进度 + private int currentProgress = 0; + // 最大进度 + private int maxProgress = 100; + // 得到控件的宽度 + private int width; + // 画笔对象 + private Paint paint; + // 圆弧 + private RectF rectF; + + // 默认的构造方法,一般取这3个就够用了 + public RingProgressView(Context context) { + this(context, null); + } + + public RingProgressView(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public RingProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + // 得到自定义资源数组 + TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RingProgressView); + ringColor = typedArray.getColor(R.styleable.RingProgressView_ringColor, ringColor); + ringProgressColor = typedArray.getColor(R.styleable.RingProgressView_ringProgressColor, ringProgressColor); + ringWidth = (int) typedArray.getDimension(R.styleable.RingProgressView_ringWidth, ringWidth); + currentProgress = typedArray.getInt(R.styleable.RingProgressView_currentProgress, currentProgress); + maxProgress = typedArray.getColor(R.styleable.RingProgressView_maxProgress, maxProgress); + typedArray.recycle(); + + initData(); + } + + private void initData() { + paint = new Paint(); + paint.setAntiAlias(true); + paint.setStyle(Paint.Style.STROKE); + paint.setStrokeWidth(ringWidth); + paint.setStrokeCap(Paint.Cap.ROUND); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + width = getMeasuredWidth(); + rectF = new RectF(ringWidth / 2, ringWidth / 2, width - ringWidth / 2, width - ringWidth / 2); + } + + // 绘制 + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + // 1. 计算圆心坐标及半径 + float centerX = width / 2; + float centerY = width / 2; + float radius = width / 2 - ringWidth / 2; + + + // 2. 画圆环 + paint.setColor(ringColor); + canvas.drawCircle(centerX, centerY, radius, paint); + + + // 3. 画圆弧 + paint.setColor(ringProgressColor); + canvas.drawArc(rectF, -90, currentProgress * 360 / maxProgress, false, paint); + } + + public int getCurrentProgress() { + return currentProgress; + } + + public void setCurrentProgress(int currentProgress) { + if (currentProgress > maxProgress) { + currentProgress = maxProgress; + } + this.currentProgress = currentProgress; + postInvalidate(); + } + + public int getMaxProgress() { + return maxProgress; + } + + public void setMaxProgress(int maxProgress) { + this.maxProgress = maxProgress; + } +} diff --git a/app/src/main/java/com/chwl/app/audio/widget/RoundProgressView.java b/app/src/main/java/com/chwl/app/audio/widget/RoundProgressView.java new file mode 100644 index 0000000..cc66779 --- /dev/null +++ b/app/src/main/java/com/chwl/app/audio/widget/RoundProgressView.java @@ -0,0 +1,171 @@ +package com.chwl.app.audio.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.RectF; +import android.graphics.SweepGradient; +import android.util.AttributeSet; +import android.view.View; + +import com.chwl.app.R; + +public class RoundProgressView extends View { + // 画实心圆的画笔 + private Paint mCirclePaint; + // 画圆环的画笔 + private Paint mRingPaint; + // 画圆环的画笔背景色 + private Paint mRingPaintBg; + // 画字体的画笔 + private Paint mTextPaint; + // 圆形颜色 + private int mCircleColor; + // 圆环颜色 + private int mRingColor; + // 圆环背景颜色 + private int mRingBgColor; + // 半径 + private float mRadius; + // 圆环半径 + private float mRingRadius; + // 圆环宽度 + private float mStrokeWidth; + // 圆心x坐标 + private int mXCenter; + // 圆心y坐标 + private int mYCenter; + // 字的长度 + private float mTxtWidth; + // 字的高度 + private float mTxtHeight; + // 总进度 + private int mTotalProgress = 60000; + // 当前进度 + private int mProgress; + + private String string; + + public RoundProgressView(Context context, AttributeSet attrs) { + super(context, attrs); + // 获取自定义的属性 + initAttrs(context, attrs); + initVariable(); + } + + //属性 + private void initAttrs(Context context, AttributeSet attrs) { + TypedArray typeArray = context.getTheme().obtainStyledAttributes(attrs, + R.styleable.RoundProgressView, 0, 0); + mRadius = typeArray.getDimension(R.styleable.RoundProgressView_round_radius, 80); + mStrokeWidth = typeArray.getDimension(R.styleable.RoundProgressView_round_strokeWidth, 10); + mCircleColor = typeArray.getColor(R.styleable.RoundProgressView_round_circleColor, 0xFFFFFFFF); + mRingColor = typeArray.getColor(R.styleable.RoundProgressView_round_ringColor, 0xFFFFFFFF); + mRingBgColor = typeArray.getColor(R.styleable.RoundProgressView_round_ringBgColor, 0xFFFFFFFF); + + mRingRadius = mRadius + mStrokeWidth / 2; + } + RectF oval; + //初始化画笔 + private void initVariable() { + oval = new RectF(); + //内圆 + mCirclePaint = new Paint(); + mCirclePaint.setAntiAlias(true); + mCirclePaint.setColor(mCircleColor); + mCirclePaint.setStyle(Paint.Style.FILL); + mCirclePaint.setStrokeCap(Paint.Cap.ROUND); + + //外圆弧背景 + mRingPaintBg = new Paint(); + mRingPaintBg.setAntiAlias(true); + mRingPaintBg.setColor(mRingBgColor); + mRingPaintBg.setStyle(Paint.Style.STROKE); + mRingPaintBg.setStrokeWidth(mStrokeWidth); + + + //外圆弧 + mRingPaint = new Paint(); + mRingPaint.setAntiAlias(true); + //mRingPaint.setColor(mRingColor); + mRingPaint.setStyle(Paint.Style.STROKE); + mRingPaint.setStrokeWidth(mStrokeWidth); + mRingPaint.setStrokeCap(Paint.Cap.ROUND);//设置线冒样式,有圆 有方 + + + //中间字 + mTextPaint = new Paint(); + mTextPaint.setAntiAlias(true); + mTextPaint.setStyle(Paint.Style.FILL); + mTextPaint.setColor(mRingColor); + mTextPaint.setTextSize(mRadius / 2); + + Paint.FontMetrics fm = mTextPaint.getFontMetrics(); + mTxtHeight = (int) Math.ceil(fm.descent - fm.ascent); + } + SweepGradient sweepGradient; + //画图 + @Override + protected void onDraw(Canvas canvas) { + mXCenter = getWidth() / 2; + mYCenter = getHeight() / 2; + + //内圆 + canvas.drawCircle(mXCenter, mYCenter, mRadius, mCirclePaint); + + //外圆弧背景 + RectF oval1 = new RectF(); + oval1.left = (mXCenter - mRingRadius); + oval1.top = (mYCenter - mRingRadius); + oval1.right = mRingRadius * 2 + (mXCenter - mRingRadius); + oval1.bottom = mRingRadius * 2 + (mYCenter - mRingRadius); + canvas.drawArc(oval1, 0, 360, false, mRingPaintBg); //圆弧所在的椭圆对象、圆弧的起始角度、圆弧的角度、是否显示半径连线 + + //外圆弧 + if (mProgress > 0 ) { + + oval.left = (mXCenter - mRingRadius); + oval.top = (mYCenter - mRingRadius); + oval.right = mRingRadius * 2 + (mXCenter - mRingRadius); + oval.bottom = mRingRadius * 2 + (mYCenter - mRingRadius); + if (sweepGradient==null) { + int[] arcColors= new int[]{Color.parseColor("#CC67FF"), + Color.parseColor("#9DB4FF"), + Color.parseColor("#13E2F5"), + Color.parseColor("#CC67FF")}; + float[] arcPostion=new float[]{0.0f,0.25f,0.75f,1f}; + //sweepGradient = new SweepGradient(mXCenter, mYCenter, mRingColor,Color.parseColor("#b05e39")); + sweepGradient = new SweepGradient(mXCenter, mYCenter, arcColors,arcPostion); + + Matrix matrix = new Matrix(); + matrix.setRotate(-90,mXCenter,mYCenter); + sweepGradient.setLocalMatrix(matrix); + mRingPaint.setShader(sweepGradient); + } + canvas.drawArc(oval, -90, ((float)mProgress / mTotalProgress) * 360, false, mRingPaint); // + + //字体 +// String txt = mProgress + "%"; +// mTxtWidth = mTextPaint.measureText(txt, 0, txt.length()); +// canvas.drawText(txt, mXCenter - mTxtWidth / 2, mYCenter + mTxtHeight / 4, mTextPaint); + } + } + public void setText(String string){ + + } + + //设置进度 + public void setProgress(int progress) { + mProgress = progress; + postInvalidate();//重绘 + } + + //设置总进度 + public void setTotalProgress(int totalProgress) { + mTotalProgress = totalProgress; + } + +} diff --git a/app/src/main/java/com/chwl/app/audio/widget/VoiceBottleFilterGenderBottomDialog.java b/app/src/main/java/com/chwl/app/audio/widget/VoiceBottleFilterGenderBottomDialog.java new file mode 100644 index 0000000..0ac0706 --- /dev/null +++ b/app/src/main/java/com/chwl/app/audio/widget/VoiceBottleFilterGenderBottomDialog.java @@ -0,0 +1,105 @@ +package com.chwl.app.audio.widget; + +import android.content.Context; +import android.os.Bundle; +import android.util.DisplayMetrics; +import android.view.Display; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.widget.RadioButton; +import android.widget.RadioGroup; +import android.widget.TextView; + +import androidx.annotation.NonNull; + +import com.google.android.material.bottomsheet.BottomSheetDialog; +import com.chwl.app.R; + +/** + * 声音瓶子.筛选性别Dialog + */ +public class VoiceBottleFilterGenderBottomDialog extends BottomSheetDialog { + private RadioGroup rgVoiceFilterGender; + private TextView btnConfirm; + + private int currentFilterGender; + private OnVoiceBottleFilterGenderListener onFilterGenderListener; + + public VoiceBottleFilterGenderBottomDialog(@NonNull Context context, int currentFilterGender, OnVoiceBottleFilterGenderListener onFilterGenderListener) { + super(context); + this.currentFilterGender = currentFilterGender; + this.onFilterGenderListener = onFilterGenderListener; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ViewGroup view = (ViewGroup) View.inflate(getContext(), R.layout.layout_voice_bottle_filter_gender_bottom_dialog, null); + RadioButton rbVoiceFilterGenderFemale = view.findViewById(R.id.rb_voice_filter_gender_female); + RadioButton rbVoiceFilterGenderMale = view.findViewById(R.id.rb_voice_filter_gender_male); + RadioButton rbVoiceFilterGenderAll = view.findViewById(R.id.rb_voice_filter_gender_all); + rgVoiceFilterGender = view.findViewById(R.id.rg_voice_filter_gender); + btnConfirm = view.findViewById(R.id.btn_confirm); + + if (currentFilterGender == 1) { + rbVoiceFilterGenderFemale.setChecked(false); + rbVoiceFilterGenderMale.setChecked(true); + rbVoiceFilterGenderAll.setChecked(false); + } else if (currentFilterGender == 2) { + rbVoiceFilterGenderFemale.setChecked(true); + rbVoiceFilterGenderMale.setChecked(false); + rbVoiceFilterGenderAll.setChecked(false); + } else { + rbVoiceFilterGenderFemale.setChecked(false); + rbVoiceFilterGenderMale.setChecked(false); + rbVoiceFilterGenderAll.setChecked(true); + } + + setContentView(view); + + Window window = getWindow(); + if (window == null) { + return; + } + WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); + if (windowManager == null) { + return; + } + Display display = windowManager.getDefaultDisplay(); + WindowManager.LayoutParams params = window.getAttributes(); + params.width = WindowManager.LayoutParams.MATCH_PARENT; + params.height = WindowManager.LayoutParams.MATCH_PARENT; + DisplayMetrics realDisplayMetrics = new DisplayMetrics(); + display.getRealMetrics(realDisplayMetrics); + window.setAttributes(params); + window.setWindowAnimations(R.style.ErbanCommonWindowAnimationStyle); + window.findViewById(R.id.design_bottom_sheet).setBackgroundResource(android.R.color.transparent); + setCancelable(false); + + setListener(); + } + + private void setListener() { + btnConfirm.setOnClickListener(view -> { + if (onFilterGenderListener != null) { + if (rgVoiceFilterGender.getCheckedRadioButtonId() == R.id.rb_voice_filter_gender_female) { + onFilterGenderListener.onFilterGender(2); + } else if (rgVoiceFilterGender.getCheckedRadioButtonId() == R.id.rb_voice_filter_gender_male) { + onFilterGenderListener.onFilterGender(1); + } else if (rgVoiceFilterGender.getCheckedRadioButtonId() == R.id.rb_voice_filter_gender_all) { + onFilterGenderListener.onFilterGender(0); + } + } + dismiss(); + }); + } + + public interface OnVoiceBottleFilterGenderListener { + /** + * @param gender 0.不限 1.男 2.女 + */ + void onFilterGender(int gender); + } +} diff --git a/app/src/main/java/com/chwl/app/audio/widget/VoiceCardConfig.java b/app/src/main/java/com/chwl/app/audio/widget/VoiceCardConfig.java new file mode 100644 index 0000000..2f2f14a --- /dev/null +++ b/app/src/main/java/com/chwl/app/audio/widget/VoiceCardConfig.java @@ -0,0 +1,43 @@ +package com.chwl.app.audio.widget; + +/** + * 录制声音页面.声音卡片滑动配置 + */ +public class VoiceCardConfig { + /** + * 显示可见的卡片数量 + */ + public static final int DEFAULT_SHOW_ITEM = 3; + /** + * 默认缩放的比例 + */ + public static final float DEFAULT_SCALE = 0.1f; + /** + * 卡片Y轴偏移量时按照14等分计算 + */ + public static final int DEFAULT_TRANSLATE_Y = 14; + /** + * 卡片滑动时默认倾斜的角度 + */ + public static final float DEFAULT_ROTATE_DEGREE = 15f; + /** + * 卡片滑动时不偏左也不偏右 + */ + public static final int SWIPING_NONE = 1; + /** + * 卡片向左滑动时 + */ + public static final int SWIPING_LEFT = 1 << 2; + /** + * 卡片向右滑动时 + */ + public static final int SWIPING_RIGHT = 1 << 3; + /** + * 卡片从左边滑出 + */ + public static final int SWIPED_LEFT = 1; + /** + * 卡片从右边滑出 + */ + public static final int SWIPED_RIGHT = 1 << 2;; +} diff --git a/app/src/main/java/com/chwl/app/audio/widget/VoiceCardItemTouchHelperCallback.java b/app/src/main/java/com/chwl/app/audio/widget/VoiceCardItemTouchHelperCallback.java new file mode 100644 index 0000000..285cf4f --- /dev/null +++ b/app/src/main/java/com/chwl/app/audio/widget/VoiceCardItemTouchHelperCallback.java @@ -0,0 +1,156 @@ +package com.chwl.app.audio.widget; + +import android.graphics.Canvas; +import android.util.Log; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.ItemTouchHelper; +import androidx.recyclerview.widget.RecyclerView; + +import com.chwl.app.R; +import com.chwl.library.utils.ResUtil; + +/** + * 录制声音页面.声音卡片滑动列表ItemTouchHelperCallback + */ +public class VoiceCardItemTouchHelperCallback extends ItemTouchHelper.Callback { + private OnSwipeListener mListener; + + public void setOnSwipedListener(OnSwipeListener mListener) { + this.mListener = mListener; + } + + /** + * 让RecyclerView拦截上下左右的滑动 + * + * @return 调用makeMovementFlags() + */ + @Override + public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) { + int dragFlags = 0; + int swipeFlags = 0; + RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); + if (layoutManager instanceof VoiceCardLayoutManager) { + swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT; + } + return makeMovementFlags(dragFlags, swipeFlags); + } + + /** + * 针对drag状态:在canDropOver()返回true时,会调用该方法 + * 可以实现拖动换位置的逻辑(需要自己处理变换位置的逻辑) + */ + @Override + public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) { + return false; + } + + /** + * 针对swipe和drag状态:当一个item view在swipe、drag状态结束的时候调用 + * drag状态:当手指释放的时候会调用 + * swipe状态:当item从RecyclerView中删除的时候调用,一般我们会在onSwiped()函数里面删除掉指定的item view + */ + @Override + public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) { + super.clearView(recyclerView, viewHolder); + Log.e("ItemTouchHelperCallback", "clearView--->"); + viewHolder.itemView.setRotation(0f); + viewHolder.itemView.setAlpha(1); + viewHolder.itemView.setScaleY(1); + viewHolder.itemView.setScaleX(1); + } + + /** + * 针对swipe和drag状态:整个过程中一直会调用这个函数,随手指移动的view就是在super里面做到的(和ItemDecoration里面的onDraw()函数对应) + */ + @Override + public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, + float dX, float dY, int actionState, boolean isCurrentlyActive) { + super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); + Log.e("ItemTouchHelperCallback", "onChildDraw--->" + + " dX = " + dX + + " dY = " + dY + + " actionState = " + actionState + + " isCurrentlyActive = " + isCurrentlyActive); + View itemView = viewHolder.itemView; + if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) { + float ratio = dX / getThreshold(recyclerView, viewHolder); + // ratio 最大为 1 或 -1 + if (ratio > 1) { + ratio = 1; + } else if (ratio < -1) { + ratio = -1; + } + itemView.setRotation(ratio * VoiceCardConfig.DEFAULT_ROTATE_DEGREE); + int childCount = recyclerView.getChildCount(); + // 当数据源个数大于最大显示数时 + if (childCount > VoiceCardConfig.DEFAULT_SHOW_ITEM) { + for (int position = 1; position < childCount - 1; position++) { + int index = childCount - position - 1; + View view = recyclerView.getChildAt(position); + view.setScaleX(1 - index * VoiceCardConfig.DEFAULT_SCALE + Math.abs(ratio) * VoiceCardConfig.DEFAULT_SCALE); + view.setScaleY(1 - index * VoiceCardConfig.DEFAULT_SCALE + Math.abs(ratio) * VoiceCardConfig.DEFAULT_SCALE); + view.setTranslationY((index - Math.abs(ratio)) * itemView.getMeasuredHeight() / VoiceCardConfig.DEFAULT_TRANSLATE_Y); + } + } else { + // 当数据源个数小于或等于最大显示数时 + for (int position = 0; position < childCount - 1; position++) { + int index = childCount - position - 1; + View view = recyclerView.getChildAt(position); + view.setScaleX(1 - index * VoiceCardConfig.DEFAULT_SCALE + Math.abs(ratio) * VoiceCardConfig.DEFAULT_SCALE); + view.setScaleY(1 - index * VoiceCardConfig.DEFAULT_SCALE + Math.abs(ratio) * VoiceCardConfig.DEFAULT_SCALE); + view.setTranslationY((index - Math.abs(ratio)) * itemView.getMeasuredHeight() / VoiceCardConfig.DEFAULT_TRANSLATE_Y); + } + } + if (mListener != null) { + if (ratio != 0) { + mListener.onSwiping(viewHolder, ratio, ratio < 0 ? VoiceCardConfig.SWIPING_LEFT : VoiceCardConfig.SWIPING_RIGHT); + } else { + mListener.onSwiping(viewHolder, ratio, VoiceCardConfig.SWIPING_NONE); + } + } + } + } + + /** + * 针对swipe和drag状态:当swipe或者drag对应的ViewHolder改变的时候调用,可以通过重写这个函数获取到swipe、drag开始和结束时机, + * viewHolder 不为空的时候是开始,空的时候是结束 + */ + @Override + public void onSelectedChanged(@Nullable RecyclerView.ViewHolder viewHolder, int actionState) { + Log.e("ItemTouchHelperCallback", "onSelectedChanged--->" + (viewHolder == null ? ResUtil.getString(R.string.audio_widget_voicecarditemtouchhelpercallback_01) + actionState : ResUtil.getString(R.string.audio_widget_voicecarditemtouchhelpercallback_02) + actionState)); + } + + /** + * 针对swipe状态:是否允许swipe(滑动)操作 + */ + @Override + public boolean isItemViewSwipeEnabled() { + Log.e("ItemTouchHelperCallback", "isItemViewSwipeEnabled--->"); + return true; + } + + /** + * 针对swipe状态:swipe 到达滑动消失的距离会回调函数 + * 一般在这个函数里面处理删除item的逻辑, + * 确切的来讲是swipe item滑出屏幕动画结束的时候调用 + */ + @Override + public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) { + Log.e("ItemTouchHelperCallback", "onSwiped--->"); + // 移除 onTouchListener,否则触摸滑动会乱了 + viewHolder.itemView.setOnTouchListener(null); + int layoutPosition = viewHolder.getLayoutPosition(); + // 移除完item时回调 mListener + if (mListener != null) { + mListener.onSwiped(viewHolder, layoutPosition, direction == ItemTouchHelper.LEFT ? VoiceCardConfig.SWIPED_LEFT : VoiceCardConfig.SWIPED_RIGHT); + } + } + + private float getThreshold(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { + return recyclerView.getWidth() * getSwipeThreshold(viewHolder); + } + +} diff --git a/app/src/main/java/com/chwl/app/audio/widget/VoiceCardLayoutManager.java b/app/src/main/java/com/chwl/app/audio/widget/VoiceCardLayoutManager.java new file mode 100644 index 0000000..6088dc7 --- /dev/null +++ b/app/src/main/java/com/chwl/app/audio/widget/VoiceCardLayoutManager.java @@ -0,0 +1,110 @@ +package com.chwl.app.audio.widget; + +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.core.view.MotionEventCompat; +import androidx.recyclerview.widget.ItemTouchHelper; +import androidx.recyclerview.widget.RecyclerView; + +/** + * 录制声音页面.声音卡片滑动列表LayoutManager + */ +public class VoiceCardLayoutManager extends RecyclerView.LayoutManager { + + private RecyclerView mRecyclerView; + private ItemTouchHelper mItemTouchHelper; + + public VoiceCardLayoutManager(@NonNull RecyclerView recyclerView, @NonNull ItemTouchHelper itemTouchHelper) { + this.mRecyclerView = checkIsNull(recyclerView); + this.mItemTouchHelper = checkIsNull(itemTouchHelper); + } + + private T checkIsNull(T t) { + if (t == null) { + throw new NullPointerException(); + } + return t; + } + + /** + * 给RecyclerView的ItemView生成LayoutParams + */ + @Override + public RecyclerView.LayoutParams generateDefaultLayoutParams() { + return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + } + + /** + * 布局ItemView + */ + @Override + public void onLayoutChildren(final RecyclerView.Recycler recycler, RecyclerView.State state) { + detachAndScrapAttachedViews(recycler); + int itemCount = getItemCount(); + // 当数据源个数大于最大显示数时 + if (itemCount > VoiceCardConfig.DEFAULT_SHOW_ITEM) { + for (int position = VoiceCardConfig.DEFAULT_SHOW_ITEM; position >= 0; position--) { + final View view = recycler.getViewForPosition(position); + addView(view); + measureChildWithMargins(view, 0, 0); + int widthSpace = getWidth() - getDecoratedMeasuredWidth(view); + int heightSpace = getHeight() - getDecoratedMeasuredHeight(view); + // recyclerView 布局 + layoutDecoratedWithMargins(view, widthSpace / 2, heightSpace / 2, + widthSpace / 2 + getDecoratedMeasuredWidth(view), + heightSpace / 2 + getDecoratedMeasuredHeight(view)); + + if (position == VoiceCardConfig.DEFAULT_SHOW_ITEM) { + view.setScaleX(1 - (position - 1) * VoiceCardConfig.DEFAULT_SCALE); + view.setScaleY(1 - (position - 1) * VoiceCardConfig.DEFAULT_SCALE); + view.setTranslationY((position - 1) * view.getMeasuredHeight() / VoiceCardConfig.DEFAULT_TRANSLATE_Y); + view.setOnTouchListener(null); + } else if (position > 0) { + view.setScaleX(1 - position * VoiceCardConfig.DEFAULT_SCALE); + view.setScaleY(1 - position * VoiceCardConfig.DEFAULT_SCALE); + view.setTranslationY(position * view.getMeasuredHeight() / VoiceCardConfig.DEFAULT_TRANSLATE_Y); + view.setOnTouchListener(null); + } else { + view.setOnTouchListener(mOnTouchListener); + } + } + } else { + // 当数据源个数小于或等于最大显示数时 + for (int position = itemCount - 1; position >= 0; position--) { + final View view = recycler.getViewForPosition(position); + addView(view); + measureChildWithMargins(view, 0, 0); + int widthSpace = getWidth() - getDecoratedMeasuredWidth(view); + int heightSpace = getHeight() - getDecoratedMeasuredHeight(view); + // recyclerView 布局 + layoutDecoratedWithMargins(view, widthSpace / 2, heightSpace / 2, + widthSpace / 2 + getDecoratedMeasuredWidth(view), + heightSpace / 2 + getDecoratedMeasuredHeight(view)); + + if (position > 0) { + view.setScaleX(1 - position * VoiceCardConfig.DEFAULT_SCALE); + view.setScaleY(1 - position * VoiceCardConfig.DEFAULT_SCALE); + view.setTranslationY(position * view.getMeasuredHeight() / VoiceCardConfig.DEFAULT_TRANSLATE_Y); + view.setOnTouchListener(null); + } else { + view.setOnTouchListener(mOnTouchListener); + } + } + } + } + + private View.OnTouchListener mOnTouchListener = new View.OnTouchListener() { + + @Override + public boolean onTouch(View v, MotionEvent event) { + RecyclerView.ViewHolder childViewHolder = mRecyclerView.getChildViewHolder(v); + if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) { + mItemTouchHelper.startSwipe(childViewHolder); + } + return false; + } + }; +} diff --git a/app/src/main/java/com/chwl/app/audio/widget/VoiceCardRecyclerView.java b/app/src/main/java/com/chwl/app/audio/widget/VoiceCardRecyclerView.java new file mode 100644 index 0000000..be9f343 --- /dev/null +++ b/app/src/main/java/com/chwl/app/audio/widget/VoiceCardRecyclerView.java @@ -0,0 +1,38 @@ +package com.chwl.app.audio.widget; + +import android.content.Context; +import android.graphics.Canvas; +import android.util.AttributeSet; + +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.RecyclerView; + +/** + * 录制声音页面.声音卡片滑动列表 + */ +public class VoiceCardRecyclerView extends RecyclerView { + + private Canvas canvas; + + public VoiceCardRecyclerView(Context context) { + super(context); + } + + public VoiceCardRecyclerView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + public VoiceCardRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + public void onDraw(Canvas c) { + canvas = c; + super.onDraw(c); + } + + public Canvas getCanvas() { + return canvas; + } +} diff --git a/app/src/main/java/com/chwl/app/audio/widget/VoiceLine.java b/app/src/main/java/com/chwl/app/audio/widget/VoiceLine.java new file mode 100644 index 0000000..37868ae --- /dev/null +++ b/app/src/main/java/com/chwl/app/audio/widget/VoiceLine.java @@ -0,0 +1,225 @@ +package com.chwl.app.audio.widget; + +import android.animation.ValueAnimator; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.RectF; +import android.util.AttributeSet; +import android.view.View; + +import com.netease.nim.uikit.common.util.sys.ScreenUtil; +import com.chwl.app.R; + +import java.util.ArrayList; +import java.util.List; + +/** + * 声音播放的波纹 + */ +public class VoiceLine extends View { + + public static final int VOICE_LINE_STYLE_REGULAR_LINE = 1;// 缺省图的规律的效果 + public static final int VOICE_LINE_STYLE_VOICE_CORRUGATED = 2;// 播放声音的动画效果:9个线条 + + + /*画笔*/ + private Paint mPaint; + + /*lineView*/ + private RectF[] lineList; + + /*lineView.height*/ + private List lineHeightList = new ArrayList<>(); + + /*lineView.Top坐标 Bottom坐标*/ + private List lineTopList = new ArrayList<>(); + private List lineBottomList = new ArrayList<>(); + + /*属性*/ + private int lineStyle = VOICE_LINE_STYLE_REGULAR_LINE;// 展示效果,默认:缺省图的规律的效果 + private float lineWidth = ScreenUtil.dip2px(3);// 线条宽度,单位PX + private float lineRadius = lineWidth / 2;// 线条圆角,为线条宽度的一半 + private float lineSpace = lineWidth;// 线条之间的间隙 + private int lineCount = 5;// 线条数量:默认5 + private float lineHeightMin = ScreenUtil.dip2px(15);// 线条最小高度 + private float lineHeightMax = ScreenUtil.dip2px(28);// 线条最大高度 + private float lineHeightMiddle = (lineHeightMax - lineHeightMin) / 2 + lineHeightMin;// 线条中界的数值:控制拉伸收缩 + + /*动画*/ + private boolean isPlayingAnim = false; + private ValueAnimator valueAnimator; + private float fraction; + + + public VoiceLine(Context context) { + this(context, null); + } + + public VoiceLine(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public VoiceLine(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initAttrs(context, attrs); + init(); + } + + private void initAttrs(Context context, AttributeSet attrs) { + TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.VoiceLine); + lineStyle = typedArray.getInt(R.styleable.VoiceLine_voice_line_style, lineStyle); + lineWidth = typedArray.getDimension(R.styleable.VoiceLine_voice_line_width, lineWidth); + lineRadius = lineWidth / 2; + lineSpace = lineWidth; + + lineCount = typedArray.getInt(R.styleable.VoiceLine_voice_line_count, lineCount); + if (lineStyle == VOICE_LINE_STYLE_VOICE_CORRUGATED) {// 如果是播放声音的动画效果:默认就是9个线条 + lineCount = 9; + } + lineList = new RectF[lineCount]; + + lineHeightMin = typedArray.getDimension(R.styleable.VoiceLine_voice_line_height_min, lineHeightMin); + lineHeightMax = typedArray.getDimension(R.styleable.VoiceLine_voice_line_height_max, lineHeightMax); + + /*设置中界的数值:控制拉伸收缩*/ + if (lineStyle == VOICE_LINE_STYLE_VOICE_CORRUGATED) {// 如果是播放声音的动画效果:默认中界数值为10 + lineHeightMiddle = ScreenUtil.dip2px(10); + } else { + lineHeightMiddle = (lineHeightMax - lineHeightMin) / 2 + lineHeightMin; + + } + typedArray.recycle(); + } + + private void init() { + mPaint = new Paint(); + mPaint.setColor(Color.WHITE); + mPaint.setStyle(Paint.Style.FILL); + + valueAnimator = ValueAnimator.ofInt(0, 1); + valueAnimator.setDuration(500); + valueAnimator.setRepeatCount(-1); + valueAnimator.setRepeatMode(ValueAnimator.REVERSE); + valueAnimator.addUpdateListener(animation -> { + fraction = animation.getAnimatedFraction(); + postInvalidate(); + }); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + + // 高度 + lineHeightList.clear(); + if (lineStyle == VOICE_LINE_STYLE_VOICE_CORRUGATED) {// 如果是播放声音的动画效果:给线条指定高度 + lineHeightList.add(ScreenUtil.dip2px(10)); + lineHeightList.add(ScreenUtil.dip2px(16)); + lineHeightList.add(ScreenUtil.dip2px(10)); + lineHeightList.add(ScreenUtil.dip2px(6)); + lineHeightList.add(ScreenUtil.dip2px(10)); + lineHeightList.add(ScreenUtil.dip2px(12)); + lineHeightList.add(ScreenUtil.dip2px(19)); + lineHeightList.add(ScreenUtil.dip2px(11)); + lineHeightList.add(ScreenUtil.dip2px(7)); + lineWidth = ScreenUtil.dip2px(3); + lineRadius = lineWidth / 2; + lineSpace = lineWidth; + } else { + for (int i = 0; i < lineCount; i++) { + if (i == 0) { + lineHeightList.add((int) lineHeightMax); + } else if (i == lineCount - 1) { + lineHeightList.add((int) lineHeightMax); + } else { + lineHeightList.add((int) lineHeightMin); + } + } + lineWidth = ScreenUtil.dip2px(6); + lineRadius = lineWidth / 2; + lineSpace = lineWidth; + } + + // 左边的坐标 + float[] lineLeftList = new float[lineCount]; + for (int i = 0; i < lineCount; i++) { + if (i == 0) { + lineLeftList[i] = 0f; + } else { + lineLeftList[i] = lineLeftList[i - 1] + lineWidth + lineSpace; + } + } + + // 右边的坐标 + float[] lineRightList = new float[lineCount]; + for (int i = 0; i < lineCount; i++) { + lineRightList[i] = lineLeftList[i] + lineSpace; + } + + // Top坐标 + lineTopList.clear(); + float lineMaxHeight = getMeasuredHeight();// 单位PX + for (int i = 0; i < lineCount; i++) { + lineTopList.add((lineMaxHeight - lineHeightList.get(i)) / 2); + } + // Bottom坐标 + lineBottomList.clear(); + for (int i = 0; i < lineCount; i++) { + lineBottomList.add(lineTopList.get(i) + lineHeightList.get(i)); + } + + // LineView + for (int i = 0; i < lineCount; i++) { + lineList[i] = new RectF(lineLeftList[i], lineTopList.get(i), lineRightList[i], lineBottomList.get(i)); + } + + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (!isPlayingAnim) { + for (int i = 0; i < lineList.length; i++) { + lineList[i].top = lineTopList.get(i); + lineList[i].bottom = lineBottomList.get(i); + canvas.drawRoundRect(lineList[i], lineRadius, lineRadius, mPaint); + } + } else { + for (int i = 0; i < lineList.length; i++) { + int centerIndex = lineList.length % 2 == 0 ? lineList.length / 2 : lineList.length / 2 + 1; + if (i == centerIndex - 1) {// 中间拉伸并且增加长度 + lineList[i].top = lineTopList.get(i) - fraction / 2 * lineHeightList.get(i); + lineList[i].bottom = lineBottomList.get(i) + fraction / 2 * lineHeightList.get(i); + canvas.drawRoundRect(lineList[i], lineRadius, lineRadius, mPaint); + } else { + if (lineHeightList.get(i) <= lineHeightMiddle) {// 拉伸 + lineList[i].top = lineTopList.get(i) - fraction / 2 * lineHeightList.get(i) * 0.5f; + lineList[i].bottom = lineBottomList.get(i) + fraction / 2 * lineHeightList.get(i) * 0.5f; + canvas.drawRoundRect(lineList[i], lineRadius, lineRadius, mPaint); + } else {// 收缩 + lineList[i].top = lineTopList.get(i) + fraction / 2 * lineHeightList.get(i) * 0.5f; + lineList[i].bottom = lineBottomList.get(i) - fraction / 2 * lineHeightList.get(i) * 0.5f; + canvas.drawRoundRect(lineList[i], lineRadius, lineRadius, mPaint); + } + } + } + } + } + + public void startAnim() { + this.isPlayingAnim = true; + valueAnimator.start(); + } + + public void stopAnim() { + this.isPlayingAnim = false; + if (valueAnimator != null) { + valueAnimator.cancel(); + } + postInvalidate(); + } + +} diff --git a/app/src/main/java/com/chwl/app/audio/widget/VoiceWave.java b/app/src/main/java/com/chwl/app/audio/widget/VoiceWave.java new file mode 100644 index 0000000..210e5b0 --- /dev/null +++ b/app/src/main/java/com/chwl/app/audio/widget/VoiceWave.java @@ -0,0 +1,193 @@ +package com.chwl.app.audio.widget; + +import android.animation.ValueAnimator; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Path; +import android.util.AttributeSet; +import android.view.View; + +import com.netease.nim.uikit.common.util.sys.ScreenUtil; +import com.chwl.app.R; + +import java.util.ArrayList; +import java.util.List; + +/** + * 录制声音的波纹 + */ +public class VoiceWave extends View { + + private Paint paintVoiceLine; + private List paths = null; + + /*属性*/ + private int voiceLineColor = Color.WHITE;// 波动的线的颜色 + private int lineSpeed = 90;// 波动线的横向移动速度,数值越大线移动越慢,默认90 + private float maxVolume = 100;// 所输入音量的最大值 + private int sensibility = 4;// 灵敏度 + private int fineness = 1;// 精细度,绘制曲线的时候,每几个像素绘制一次,默认是1,值越小,曲线越顺滑 + + + // 音量 + private float volume = 10; + private float targetVolume = 1; + + private long lastTime = 0;// 记录最后绘制的时间 + private float translateX = 0; + private boolean isSet = false; + private boolean isClear = true;// 是否清楚为初始状态,清空振幅 + + private ValueAnimator valueAnimator; + + private int viewHeight; + + public VoiceWave(Context context) { + super(context); + } + + public VoiceWave(Context context, AttributeSet attrs) { + super(context, attrs); + initAttrs(context, attrs); + initData(); + } + + public VoiceWave(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initAttrs(context, attrs); + initData(); + } + + private void initAttrs(Context context, AttributeSet attrs) { + TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.VoiceWave); + voiceLineColor = typedArray.getColor(R.styleable.VoiceWave_voice_wave_line_color, voiceLineColor); + lineSpeed = typedArray.getInt(R.styleable.VoiceWave_voice_wave_line_speed, lineSpeed); + maxVolume = typedArray.getFloat(R.styleable.VoiceWave_voice_wave_max_volume, maxVolume); + sensibility = typedArray.getInt(R.styleable.VoiceWave_voice_wave_sensibility, sensibility); + fineness = typedArray.getInt(R.styleable.VoiceWave_voice_wave_fineness, fineness); + typedArray.recycle(); + } + + private void initData() { + paths = new ArrayList<>(2); + for (int i = 0; i < 2; i++) { + paths.add(new Path()); + } + + paintVoiceLine = new Paint(); + paintVoiceLine.setColor(voiceLineColor); + paintVoiceLine.setAntiAlias(true); + paintVoiceLine.setStyle(Paint.Style.STROKE); + paintVoiceLine.setStrokeWidth(ScreenUtil.dip2px(2)); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + viewHeight = getHeight(); + } + + @Override + protected void onDraw(Canvas canvas) { + lineChange(); + canvas.save(); + int moveY = viewHeight / 2; + for (int i = 0; i < paths.size(); i++) { + paths.get(i).reset(); + paths.get(i).moveTo(getWidth(), viewHeight / 2); + } + for (float i = getWidth() - 1; i >= 0; i -= fineness) { + // 振幅 + float amplitude; + if (isClear) { + amplitude = 1; + } else { + amplitude = volume * i / getWidth() - volume * i * i / getWidth() / getWidth(); + } +// Log.e("VoiceWave", ResUtil.getString(R.string.audio_widget_voicewave_01) + isClear + ResUtil.getString(R.string.audio_widget_voicewave_02) + amplitude); + for (int n = 1; n <= paths.size(); n++) { + float sin = amplitude * (float) Math.sin((i - Math.pow(1.22, n)) * Math.PI / 180 - translateX); + float lineToY; + if (n == 1) { + lineToY = 10 * sin / paths.size() + moveY; + } else { + lineToY = 25 * sin / paths.size() + moveY; + } +// float lineToY = 2 * n * sin / paths.size() - 15 * sin / paths.size() + moveY; + paths.get(n - 1).lineTo(i, lineToY); + } + } + for (int n = 0; n < paths.size(); n++) { + if (n == 0) { + paintVoiceLine.setAlpha(255); + } else { + paintVoiceLine.setAlpha(200); + } + if (paintVoiceLine.getAlpha() > 0) { + canvas.drawPath(paths.get(n), paintVoiceLine); + } + } + canvas.restore(); + } + + private void lineChange() { + if (lastTime == 0) { + lastTime = System.currentTimeMillis(); + translateX += 1.5; + } else { + if (System.currentTimeMillis() - lastTime > lineSpeed) { + lastTime = System.currentTimeMillis(); + translateX += 1.5; + } else { + return; + } + } + if (volume < targetVolume && isSet) { + volume += viewHeight / 30; + } else { + isSet = false; + if (volume <= 10) { + volume = 10; + } else { + if (volume < viewHeight / 30) { + volume -= viewHeight / 60; + } else { + volume -= viewHeight / 30; + } + } + } + } + + public void setVolume(int volume) { + if (volume > maxVolume * sensibility / 25) { + isSet = true; + targetVolume = viewHeight * volume / 2 / maxVolume; + } + } + + public void startAnim() { + isClear = false; + if (valueAnimator == null) { + valueAnimator = ValueAnimator.ofInt(0, 1); + valueAnimator.setDuration(500); + valueAnimator.setRepeatCount(-1); + valueAnimator.setRepeatMode(ValueAnimator.REVERSE); + valueAnimator.addUpdateListener(valueAnimator -> invalidate()); + } + if (!valueAnimator.isRunning()) { + valueAnimator.start(); + } + } + + public void stopAnim() { + isClear = true; + postInvalidate(); + if (valueAnimator != null) { + valueAnimator.cancel(); + valueAnimator = null; + } + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/BottomViewListenerWrapper.java b/app/src/main/java/com/chwl/app/avroom/BottomViewListenerWrapper.java new file mode 100644 index 0000000..9dab598 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/BottomViewListenerWrapper.java @@ -0,0 +1,53 @@ +package com.chwl.app.avroom; + +/** + * Created by chenran on 2017/11/21. + */ + +public abstract class BottomViewListenerWrapper { + public BottomViewListenerWrapper() { + + } + + public void onOpenMicBtnClick(int type) { + + } + + public void onSendMsgBtnClick() { + + } + + public void onSendFaceBtnClick() { + + } + + public void onSendGiftBtnClick() { + + } + + public void onRemoteMuteBtnClick() { + + } + + public void onMoreBtnClick() { + + } + + /** + * 点击排麦按钮 + */ + public void onMicQueueClick() { + + } + + /** + * 房间内私聊 + */ + public void onRoomMessageClick() { + + } + + public void onRoomGameplayClick(boolean isOnlyPK){ + + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/ButtonItemFactory.java b/app/src/main/java/com/chwl/app/avroom/ButtonItemFactory.java new file mode 100644 index 0000000..40f645d --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/ButtonItemFactory.java @@ -0,0 +1,529 @@ +package com.chwl.app.avroom; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.text.TextUtils; + +import com.chwl.app.R; +import com.chwl.app.UIHelper; +import com.chwl.app.avroom.widget.ViewItem; +import com.chwl.app.common.util.DialogCommonUtil; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.app.room_chat.fragment.RoomMsgTabFragment; +import com.chwl.app.ui.im.avtivity.NimFriendModel; +import com.chwl.app.ui.im.avtivity.NimP2PMessageActivity; +import com.chwl.app.ui.widget.ButtonItem; +import com.chwl.app.ui.widget.GiftDialog; +import com.chwl.app.vip.util.VipHelper; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.bean.RoomQueueInfo; +import com.chwl.core.bean.response.ServiceResult; +import com.chwl.core.initial.InitialModel; +import com.chwl.core.initial.bean.InitInfo; +import com.chwl.core.kick.KickModel; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.manager.IMNetEaseManager; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.core.room.model.AvRoomModel; +import com.chwl.core.statistic.StatLogKey; +import com.chwl.core.super_admin.bean.KickOutExtBean; +import com.chwl.core.super_admin.model.SuperAdminModel; +import com.chwl.core.super_admin.util.SAdminOptUtil; +import com.chwl.core.super_admin.util.SaAttachmentFactory; +import com.chwl.core.super_admin.util.SuperAdminUtil; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.library.common.util.OtherExtKt; +import com.chwl.library.net.rxnet.callback.CallBack; +import com.chwl.library.utils.JavaUtil; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; +import com.chwl.library.utils.config.BasicConfig; +import com.example.lib_utils.ktx.ResourcesKtxKt; +import com.hjq.toast.ToastUtils; +import com.netease.nim.uikit.business.uinfo.UserInfoHelper; +import com.netease.nim.uikit.common.util.log.LogUtil; +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMember; +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage; +import com.orhanobut.logger.Logger; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import io.reactivex.Single; +import io.reactivex.SingleSource; +import io.reactivex.functions.Function; + + +/** + * @author chenran + * @date 2017/10/11 + */ +public class ButtonItemFactory { + + /** + * 创建相关的buttons 添加到资料卡片 + * + * @param context context + * @param uid uid or 云信account + * @param isNeedGiftItem ture能送礼物 + * @param isNeedRoomItem ture表示房间相关的操作,比如踢出房间,外部调用一般置为false + * @param isInRoom ture表现在房间内,giftdialog在不在房间有不同的ui + * @param listener dialog的监听回调 + * @return List + */ + public static List createCommonButtonItems( + Context context, + UserInfo userInfo, + long uid, + boolean isNeedGiftItem, + boolean isNeedRoomItem, + boolean isInRoom, + GiftDialog.OnGiftDialogBtnClickListener listener) { + + if (uid <= 0) return null; + String account = String.valueOf(uid); + // 判断在不在麦上 + RoomQueueInfo roomQueueInfo = AvRoomDataManager.get().getRoomQueueMemberInfoByAccount(account); + // 麦上的人员信息,麦上的坑位信息 + ChatRoomMember chatRoomMember = null; + String currentUid = String.valueOf(AuthModel.get().getCurrentUid()); + //null表示不在麦位,比如,点击公屏的用户时 + + if (roomQueueInfo != null && roomQueueInfo.mChatRoomMember != null) { + chatRoomMember = new ChatRoomMember(); + chatRoomMember.setAccount(roomQueueInfo.mChatRoomMember.getAccount()); + chatRoomMember.setNick(roomQueueInfo.mChatRoomMember.getNick()); + chatRoomMember.setAvatar(roomQueueInfo.mChatRoomMember.getAvatar()); + } + if (chatRoomMember == null) { + chatRoomMember = AvRoomDataManager.get().getChatRoomMember(account); + } + //account和chatRoomMember 不会同时为空,如果同时为空,则是前面传参出错 + boolean isMySelf = Objects.equals(currentUid, account); + if (isMySelf) { + return null; + } + String nick = getNick(chatRoomMember, account); + List buttonItems = new ArrayList<>(); + //ture则表示需要传入此类型button + boolean gift = false; + if (isNeedGiftItem) { + gift = true; + } + //提出房间 + boolean kickOutRoom = false; + //设置管理员 + boolean mark_manager = false; + //取消管理员 + boolean no_mark_manager = false; + //黑名单 + boolean mart_black = false; + + boolean isTargetRoomAdmin = AvRoomDataManager.get().isRoomAdmin(account); + boolean isTargetRoomOwner = AvRoomDataManager.get().isRoomOwner(account); + boolean isTargetSuperAdmin = AvRoomDataManager.get().isSuperAdmin(account); + //资料卡片需要房间操作的按钮,不去判断是否在房间内 + if (AvRoomDataManager.get().isRoomOwner() || AvRoomDataManager.get().isSuperAdmin()) { + //房主操作 + //点击不是自己 + if (isNeedRoomItem && !isTargetSuperAdmin) { + //提出房间 + kickOutRoom = true; + //管理员 + if (!isTargetRoomAdmin) { + mark_manager = true; + } else { + no_mark_manager = true; + } + //黑名单 + mart_black = true; + } + + } else if (AvRoomDataManager.get().isRoomAdmin()) { + //管理员操作 + //不是自己 + if (!isTargetRoomAdmin && !isTargetRoomOwner && !isTargetSuperAdmin) { + //非房主或管理员 + if (isNeedRoomItem) { + //踢出房间 + kickOutRoom = true; + //加入黑名单 + mart_black = true; + } + } + } + +// if (gift) { +// if (!SuperAdminUtil.isSuperAdmin()) { +// buttonItems.add(createSendGiftItem(context, uid, isInRoom, listener)); +// } +// } + // 私聊 +// buttonItems.add(createPrivateChatItem(context, account, isInRoom)); + + //关注 +// buttonItems.add(createAttentItem()); + //aite @ +// buttonItems.add(createAtItem()); + + final RoomInfo currentRoom = AvRoomDataManager.get().mCurrentRoomInfo; + if (currentRoom == null) return buttonItems; + + //超管能踢人拉黑用户,房主除外 + if (!isTargetRoomOwner && SuperAdminUtil.isSuperAdmin()) { + kickOutRoom = true; + mart_black = true; + } + + if (kickOutRoom) { + buttonItems.add(createKickOutRoomItem(context, userInfo, String.valueOf(currentRoom.getRoomId()), + account, nick)); + } + if (mark_manager) { + buttonItems.add(createMarkManagerListItem(context,String.valueOf(currentRoom.getRoomId()), account, nick,true)); + } + if (no_mark_manager) { + buttonItems.add(createMarkManagerListItem(context,String.valueOf(currentRoom.getRoomId()), account, nick,false)); + } + if (mart_black) { + buttonItems.add(createMarkBlackListItem( + context, + userInfo, + String.valueOf(currentRoom.getRoomId()), + account, + nick) + ); + } + return buttonItems; + } + + + + + /** + * 根据account获取昵称 + */ + private static String getNick(ChatRoomMember member, String account) { + String nick = null; + if (member != null) { + nick = member.getNick(); + } else { + nick = UserInfoHelper.getUserDisplayName(account); + } + if (TextUtils.isEmpty(nick)) { + nick = ""; + } + return nick; + } + + + /** + * 踩TA,当该人再房间中的时候,进入他所在的房间 + * + * @return + */ + private static ViewItem createFindMeItem() { + ViewItem viewItem = new ViewItem(ResUtil.getString(R.string.erban_avroom_buttonitemfactory_01), R.drawable.icon_dialog_find_ta, null); + viewItem.isFindTa = true; + return viewItem; + } + + + + /** + * 私聊 + */ + public static ViewItem createPrivateChatItem(final Context context, String account, boolean isInRoom) { + return new ViewItem(ResUtil.getString(R.string.erban_avroom_buttonitemfactory_02), R.mipmap.ic_private_chat, () -> { + if (isInRoom) { + RoomMsgTabFragment.Companion.newInstance(account).show(context); + } else { + NimP2PMessageActivity.start(context, account); + } + + }); + } + + /** + * 关注or取消 + */ + public static ViewItem createAttentItem() { + ViewItem viewItem = new ViewItem(ResUtil.getString(R.string.erban_avroom_buttonitemfactory_04), R.drawable.icon_dialog_attent, null); + viewItem.isAttent = true; + return viewItem; + } + + /** + * @Ta + */ + public static ViewItem createAtItem() { + ViewItem viewItem = new ViewItem("@Ta", R.drawable.icon_dialog_ait, null); + viewItem.isAt = true; + return viewItem; + } + + /** + * 踢出房间: 先强制下麦,再踢出房间 todo do + */ + public static ViewItem createKickOutRoomItem(Context context, UserInfo userInfo, final String roomId, + final String account, String nick) { + return new ViewItem(ResUtil.getString(R.string.erban_avroom_buttonitemfactory_05), R.drawable.icon_dialog_kickout_room, new ViewItem.OnClickListener() { + @Override + public void onClick() { + + if (VipHelper.notKick(userInfo)) { + ToastUtils.show(ResUtil.getString(R.string.vipPower,userInfo.getUserVipInfoVO().getVipLevel())); + return; + } + + String tips = (AvRoomDataManager.get().isGamePlaying(Long.parseLong(account)) ? ResUtil.getString(R.string.erban_avroom_buttonitemfactory_07) : "") + ResUtil.getString(R.string.erban_avroom_buttonitemfactory_08); + if (VipHelper.notKick(userInfo)) { + if (AvRoomDataManager.get().isRoomOwner()) { + tips = ResUtil.getString(R.string.erban_avroom_buttonitemfactory_09) + VipHelper.getVipName(userInfo) + ResUtil.getString(R.string.erban_avroom_buttonitemfactory_010); + } else { + SingleToastUtil.showToast(ResUtil.getString(R.string.erban_avroom_buttonitemfactory_011) + VipHelper.getVipName(userInfo) + ResUtil.getString(R.string.erban_avroom_buttonitemfactory_012)); + return; + } + } + + new DialogManager(context).showOkCancelDialog(tips, + true, new DialogManager.AbsOkDialogListener() { + @SuppressLint("CheckResult") + @Override + public void onOk() { + final Map reason = new HashMap<>(); + reason.put("reason", "kick"); + if (AvRoomDataManager.get().isOnMic(JavaUtil.str2long(account))) { + int micPosition = AvRoomDataManager.get().getMicPosition(JavaUtil.str2long(account)); + reason.put("micPosition", micPosition); + reason.put("account", account); + IMNetEaseManager.get().downMicroPhoneBySdk(micPosition, null); + } + + reason.put(StatLogKey.USER_ID_KICK, String.valueOf(AuthModel.get().getCurrentUid())); + int role = SuperAdminUtil.isSuperAdmin() ? 1 : 2; + reason.put(KickOutExtBean.KEY_ROLE, role); + + //如果是超管踢人 + //超管踢普通人的话, 先将自己升级为管理员,再踢人 + if (SAdminOptUtil.kickOutNormalUser(account, nick, reason)) { + LogUtil.print("super admin kick out normal user"); + SuperAdminModel superAdminModel = new SuperAdminModel(); + superAdminModel.roomOperate(SuperAdminModel.KICK_OUT_ROOM, JavaUtil.str2long(account)).subscribe(); + return; + } + //踢房间管理员 + //通过超管发消息管理员,管理员退出房间的方式踢人 + if (SAdminOptUtil.kickOutRoomAdmin(account, nick)) { + LogUtil.print("super admin kick out room admin"); + return; + } + IMNetEaseManager.get().kickMemberFromRoomBySdk(JavaUtil.str2long(roomId), + JavaUtil.str2long(account), reason) + .subscribe((s, throwable) -> { + if (throwable != null) { + if (throwable.getMessage().contains("404")) { + SingleToastUtil.showToast(BasicConfig.INSTANCE.getAppContext(), ResUtil.getString(R.string.erban_avroom_buttonitemfactory_013)); + } else { + SingleToastUtil.showToast(BasicConfig.INSTANCE.getAppContext(), throwable.getMessage()); + } + } else { + IMNetEaseManager.get().kickMemberFromRoomBySdk(Long.valueOf(roomId), + Long.valueOf(account), nick) + .subscribe(chatRoomMessage -> + KickModel.get().sendMessage(chatRoomMessage)); + + Logger.e("kick out mic and room: " + s); + IMNetEaseManager.get().noticeKickOutChatMember(null, account); + } + }); + } + }); + } + }); + } + + //设置管理员 + public static ViewItem createMarkManagerListItem(final Context context,final String roomId, final String account, final String nick, final boolean mark) { + String title = BasicConfig.INSTANCE.getAppContext().getString(mark ? R.string.set_manager : R.string.remove_manager); + int icon = mark ? R.drawable.icon_dialog_set_manager_ture : R.drawable.icon_dialog_set_manager_false; + return new ViewItem(title, icon, () -> { + + //xxx 设置管理员 + if (AvRoomDataManager.get().isSuperAdmin()) { + AvRoomModel.get().markManager(Long.parseLong(account), mark).subscribe(); + } else { + IMNetEaseManager.get().markManagerListBySdk(roomId, account, mark, new CallBack() { + @Override + public void onSuccess(ChatRoomMember data) { + if (mark) { + OtherExtKt.doToast(ResourcesKtxKt.getString(R.string._ver_23_setManagerAddSuccess, nick)); + } else { + OtherExtKt.doToast(ResourcesKtxKt.getString(R.string._ver_23_setManagerRemoveSuccess, nick)); + } + AvRoomModel.get().manageOpt(Long.parseLong(account),mark).subscribe(); + } + + @Override + public void onFail(int code, String error) { + if (code == ServiceResult.CODE_ROOM_MANAGER_LIMIT) { + DialogCommonUtil.showManagerLimit(context); + } else { + OtherExtKt.doToast(error); + } + } + }); + } + + }); + } + + //加入黑名单 todo do + public static ViewItem createMarkBlackListItem(final Context context, + UserInfo userInfo, + final String roomId, + final String account, + String nick) { + return new ViewItem(ResUtil.getString(R.string.erban_avroom_buttonitemfactory_015), R.drawable.icon_dialog_mark_black_list, () -> { + if (VipHelper.notKick(userInfo)) { + ToastUtils.show(ResUtil.getString(R.string.vipPower,userInfo.getUserVipInfoVO().getVipLevel())); + return; + } + int roomBlackListSize = 200; + InitInfo initInfo = InitialModel.get().getCacheInitInfo(); + if (initInfo != null && initInfo.getRoomBlackListSize() != 0) { + roomBlackListSize = initInfo.getRoomBlackListSize(); + } + if (AvRoomDataManager.get().mRoomLimitMemberList.size() >= roomBlackListSize) { + new DialogManager(context).showOkDialog(ResUtil.getString(R.string.erban_avroom_buttonitemfactory_017) + roomBlackListSize + ResUtil.getString(R.string.erban_avroom_buttonitemfactory_018)); + return; + } + + String tips = ResUtil.getString(R.string.erban_avroom_buttonitemfactory_019) + nick + ResUtil.getString(R.string.erban_avroom_buttonitemfactory_020) + + (AvRoomDataManager.get().mCurrentRoomInfo != null && AvRoomDataManager.get().isGamePlaying(Long.parseLong(account)) ? ResUtil.getString(R.string.erban_avroom_buttonitemfactory_021) : ""); + if (VipHelper.notKick(userInfo)) { + if (AvRoomDataManager.get().isRoomOwner()) { + tips = ResUtil.getString(R.string.erban_avroom_buttonitemfactory_022) + VipHelper.getVipName(userInfo) + ResUtil.getString(R.string.erban_avroom_buttonitemfactory_023); + } else { + SingleToastUtil.showToast(ResUtil.getString(R.string.erban_avroom_buttonitemfactory_024) + VipHelper.getVipName(userInfo) + ResUtil.getString(R.string.erban_avroom_buttonitemfactory_025)); + return; + } + } + + new DialogManager(context).showOkCancelDialog(tips, true, + () -> { + Single single; + if (SuperAdminUtil.isSuperAdmin() || AvRoomDataManager.get().isSuperAdmin()) { + //超管拉黑 + single = AvRoomModel.get().markBlack(JavaUtil.str2long(account)); + SuperAdminModel superAdminModel = new SuperAdminModel(); + superAdminModel.roomOperate(SuperAdminModel.ADD_BLACK_LIST, JavaUtil.str2long(account)).subscribe(); + } else { + single = IMNetEaseManager.get().markBlackListBySdk(roomId, account, true); + } + //拉黑后,下麦和管理操作保持一致 + single + //发公屏 + .flatMap((Function>) s -> { + if (SuperAdminUtil.isSuperAdmin()) { + ChatRoomMessage chatRoomMessage = SaAttachmentFactory + .createBlackOrKickOutChatRoomMsg(account, nick, 1); + return IMNetEaseManager.get().sendChatRoomMessage(chatRoomMessage, false); + } + return IMNetEaseManager.get().markBlackListBySdk(roomId, account, true, nick); + }) + .doOnSuccess(chatRoomMessage -> + KickModel.get().onSendRoomMessageSuccess(chatRoomMessage)) + .flatMap(s -> { + int micPosition = AvRoomDataManager.get().getMicPosition(account); + return IMNetEaseManager.get().downMicroPhoneBySdk(micPosition); + }) + .subscribe(); + }); + + + }); + } + + //发送礼物 + + /** + * @param isInRoom true 在房间内弹起 + * @param isHideMagicTab true 隐藏魔法 + * @return ViewItem + */ + public static ViewItem createSendGiftItem(final Context context, long otherUid, boolean isInRoom, boolean isHideMagicTab, + final GiftDialog.OnGiftDialogBtnClickListener giftDialogBtnClickListener) { + return new ViewItem(ResUtil.getString(R.string.erban_avroom_buttonitemfactory_026), R.drawable.icon_send_gift_ture, () -> { + + GiftDialog dialog = new GiftDialog(context, otherUid, isInRoom, false, isHideMagicTab); + if (giftDialogBtnClickListener != null) { + dialog.setGiftDialogBtnClickListener(giftDialogBtnClickListener); + } + dialog.show(); + }); + } + + + /** + * @param isInRoom true 在房间内弹起 + * @return ViewItem + */ + public static ViewItem createSendGiftItem(final Context context, long otherUid, boolean isInRoom, + final GiftDialog.OnGiftDialogBtnClickListener giftDialogBtnClickListener) { + return createSendGiftItem(context, otherUid, isInRoom, true, giftDialogBtnClickListener); + } + + /** + * 拉黑 todo do + */ + public static ButtonItem createAddToBlackListItem(DialogManager dialogManager, String account) { + return new ButtonItem(ResUtil.getString(R.string.me_block), () -> { + dialogManager.showOkCancelDialog(ResUtil.getString(R.string.erban_avroom_buttonitemfactory_031), true, + new DialogManager.AbsOkDialogListener() { + @Override + public void onOk() { + NimFriendModel.get().addToBlackList(account) + .subscribe((aBoolean, throwable) -> { + SingleToastUtil.showToastShort((throwable == null) ? ResUtil.getString(R.string.erban_avroom_buttonitemfactory_034) : ResUtil.getString(R.string.erban_avroom_buttonitemfactory_035)); + }); + } + }); + }); + } + + /** + * 举报 + */ + public static ButtonItem createReportItem(Context context, long uid, String reportType) { + return new ButtonItem(ResUtil.getString(R.string.erban_avroom_buttonitemfactory_036), () -> UIHelper.showReportPage(context, uid, reportType)); + } + +// public static List createMiniWorldGroupButtonItems( +// Context context, +// long uid, +// boolean isInRoom, +// GiftDialog.OnGiftDialogBtnClickListener listener) { +// if (uid <= 0) return null; +// String currentUid = String.valueOf(AuthModel.get().getCurrentUid()); +// String account = String.valueOf(uid); +// //account和chatRoomMember 不会同时为空,如果同时为空,则是前面传参出错 +// boolean isMySelf = Objects.equals(currentUid, account); +// if (isMySelf) { +// return null; +// } +// List buttonItems = new ArrayList<>(); +// //不在房间内,也不需要魔法 +// buttonItems.add(createSendGiftItem(context, uid, true, true, listener)); +// // 私聊 +// buttonItems.add(createPrivateChatItem(context, account, isInRoom)); +// //装扮和关注目前是都有的操作 +// // buttonItems.add(createSendDecorationItem(context, uid)); +// buttonItems.add(createAttentItem()); +// buttonItems.add(createFindMeItem()); +// return buttonItems; +// } +} diff --git a/app/src/main/java/com/chwl/app/avroom/ChatMemberDiffUtilCallback.java b/app/src/main/java/com/chwl/app/avroom/ChatMemberDiffUtilCallback.java new file mode 100644 index 0000000..77b534a --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/ChatMemberDiffUtilCallback.java @@ -0,0 +1,44 @@ +package com.chwl.app.avroom; + +import androidx.recyclerview.widget.DiffUtil; + +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMember; + +import java.util.List; +import java.util.Objects; + +/** + * @author Administrator + */ +public class ChatMemberDiffUtilCallback extends DiffUtil.Callback { + private List mOldMemberList, mNewMemberList; + + public ChatMemberDiffUtilCallback(List oldMemberList, List newMemberList) { + mOldMemberList = oldMemberList; + mNewMemberList = newMemberList; + } + + @Override + public int getOldListSize() { + return mOldMemberList == null ? 0 : mOldMemberList.size(); + } + + @Override + public int getNewListSize() { + return mNewMemberList == null ? 0 : mNewMemberList.size(); + } + + @Override + public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { + return Objects.equals(mOldMemberList.get(oldItemPosition).getAccount(), + mNewMemberList.get(newItemPosition).getAccount()); + } + + @Override + public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { + ChatRoomMember oldItem = mOldMemberList.get(oldItemPosition); + ChatRoomMember newItem = mNewMemberList.get(newItemPosition); + return Objects.equals(oldItem.getAccount(), newItem.getAccount()) + && Objects.equals(oldItem.getNick(), newItem.getNick()); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/SoftKeyBoardListener.java b/app/src/main/java/com/chwl/app/avroom/SoftKeyBoardListener.java new file mode 100644 index 0000000..69a83ba --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/SoftKeyBoardListener.java @@ -0,0 +1,81 @@ +package com.chwl.app.avroom; + +import android.app.Activity; +import android.graphics.Rect; +import android.view.View; +import android.view.ViewTreeObserver; + +import java.lang.ref.WeakReference; + +/** + * 该类用于监听软键盘是否显示并获取其高度 + *

+ * Success is the sum of small efforts, repeated day in and day out. + * 成功就是日复一日那一点点小小努力的积累。 + * AndroidGroup:158423375 + * Author:Johnny + * AuthorQQ:956595454 + * AuthorWX:Qiang_it + * AuthorPhone:nothing + * Created by 2016/9/22. + */ +public class SoftKeyBoardListener { + + private View rootView;/*activity的根视图*/ + private int rootViewVisibleHeight;/*纪录根视图的显示高度*/ + private WeakReference mReference; +// private OnSoftKeyBoardChangeListener onSoftKeyBoardChangeListener; + + public SoftKeyBoardListener(Activity activity) { + /*获取activity的根视图*/ + rootView = activity.getWindow().getDecorView(); + /*监听视图树中全局布局发生改变或者视图树中的某个视图的可视状态发生改变*/ + rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + OnSoftKeyBoardChangeListener onSoftKeyBoardChangeListener = mReference.get(); + if (onSoftKeyBoardChangeListener == null) return; + /*获取当前根视图在屏幕上显示的大小*/ + Rect r = new Rect(); + rootView.getWindowVisibleDisplayFrame(r); + int visibleHeight = r.height(); + if (rootViewVisibleHeight == 0) { + rootViewVisibleHeight = visibleHeight; + return; + } + /*根视图显示高度没有变化,可以看作软键盘显示/隐藏状态没有改变*/ + if (rootViewVisibleHeight == visibleHeight) { + return; + } + /*根视图显示高度变小超过200,可以看作软键盘显示了*/ + if (rootViewVisibleHeight - visibleHeight > 200) { + onSoftKeyBoardChangeListener.keyBoardShow(rootViewVisibleHeight - visibleHeight); + rootViewVisibleHeight = visibleHeight; + return; + } + /*根视图显示高度变大超过200,可以看作软键盘隐藏了*/ + if (visibleHeight - rootViewVisibleHeight > 200) { + onSoftKeyBoardChangeListener.keyBoardHide(visibleHeight - rootViewVisibleHeight); + rootViewVisibleHeight = visibleHeight; + } + } + }); + } + + private void setOnSoftKeyBoardChangeListener(OnSoftKeyBoardChangeListener onSoftKeyBoardChangeListener) { + mReference = new WeakReference<>(onSoftKeyBoardChangeListener); +// this.onSoftKeyBoardChangeListener = onSoftKeyBoardChangeListener; + } + + public interface OnSoftKeyBoardChangeListener { + void keyBoardShow(int height); + + void keyBoardHide(int height); + } + + public static void setListener(Activity activity, OnSoftKeyBoardChangeListener onSoftKeyBoardChangeListener) { + if (activity == null) return; + SoftKeyBoardListener softKeyBoardListener = new SoftKeyBoardListener(activity); + softKeyBoardListener.setOnSoftKeyBoardChangeListener(onSoftKeyBoardChangeListener); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/UserCardButtonManager.java b/app/src/main/java/com/chwl/app/avroom/UserCardButtonManager.java new file mode 100644 index 0000000..1d86123 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/UserCardButtonManager.java @@ -0,0 +1,12 @@ +package com.chwl.app.avroom; + +/** + * 用户卡片的管理 + * Created by lvzebiao on 2018/11/12. + */ + +public class UserCardButtonManager { + + + +} diff --git a/app/src/main/java/com/chwl/app/avroom/activity/AVRoomActivity.java b/app/src/main/java/com/chwl/app/avroom/activity/AVRoomActivity.java new file mode 100644 index 0000000..e1ceb5a --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/activity/AVRoomActivity.java @@ -0,0 +1,1600 @@ +package com.chwl.app.avroom.activity; + +import static android.view.View.VISIBLE; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_FAIRY; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_LUCKY_SEA; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_LUCKY_SEA_GIFT_SERVER_ALL; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_ROOM_PK; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_DRAW_GIFT_L5; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_ROOM_PK_NOTIFY; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.Dialog; +import android.app.FragmentManager; +import android.content.Context; +import android.content.Intent; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.os.Parcelable; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.TextUtils; +import android.util.Log; +import android.view.View; +import android.view.ViewStub; +import android.view.WindowManager; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; +import androidx.fragment.app.DialogFragment; +import androidx.lifecycle.LifecycleOwner; +import androidx.lifecycle.LiveData; +import androidx.viewpager2.widget.ViewPager2; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.chwl.app.R; +import com.chwl.app.avroom.dialog.NewUserGiftDialog; +import com.chwl.app.avroom.dialog.SingleRoomTipDialog; +import com.chwl.app.avroom.fragment.FakeSingleRoomBackFragment; +import com.chwl.app.avroom.fragment.FakeSingleRoomFragment; +import com.chwl.app.avroom.fragment.HomePartyFragment; +import com.chwl.app.avroom.fragment.InputPwdDialogFragment; +import com.chwl.app.avroom.presenter.AvRoomPresenter; +import com.chwl.app.avroom.presenter.HomePartyPresenter; +import com.chwl.app.avroom.view.IAvRoomView; +import com.chwl.app.avroom.widget.VerticalViewPagerAdapter; +import com.chwl.app.base.BaseMvpActivity; +import com.chwl.app.common.widget.CircleImageView; +import com.chwl.app.common.widget.CustomImageSpan; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.app.home.dialog.HelloMessageDialog; +import com.chwl.app.notify.GlobalNotifyManager; +import com.chwl.app.notify.RoomNotifyManager; +import com.chwl.app.ui.patriarch.help.LimitEnterRoomHelper; +import com.chwl.app.ui.user.activity.UserInfoActivity; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.app.ui.webview.CommonWebViewActivity; +import com.chwl.app.ui.webview.baishun.BaiShunGameWebFragment; +import com.chwl.app.ui.webview.baishun.IBaiShunGameListener; +import com.chwl.app.ui.webview.baishun.JoyPlayGameWebFragment; +import com.chwl.app.ui.webview.baishun.LeaderccGameWebFragment; +import com.chwl.app.ui.widget.NobleOpenNoticeView; +import com.chwl.app.ui.widget.dialog.AllServiceGiftLevelDialog; +import com.chwl.app.ui.widget.dialog.MonsterDialog; +import com.chwl.app.utils.RoomBoomManager; +import com.chwl.app.utils.RoomHelperManager; +import com.chwl.app.utils.UserUtils; +import com.chwl.core.Constants; +import com.chwl.core.DemoCache; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.auth.event.LogoutEvent; +import com.chwl.core.bean.BaseProtocol; +import com.chwl.core.channel_page.bean.HelloMessageInfo; +import com.chwl.core.gift.GiftModel; +import com.chwl.core.gift.bean.GiftInfo; +import com.chwl.core.im.custom.bean.CustomAttachment; +import com.chwl.core.im.custom.bean.FairyMsgAttachment; +import com.chwl.core.im.custom.bean.NotifyH5Attachment; +import com.chwl.core.im.custom.bean.NotifyH5Info; +import com.chwl.core.im.custom.bean.RoomLuckySeaAttachment; +import com.chwl.core.im.custom.bean.RoomLuckySeaMsgBean; +import com.chwl.core.im.custom.bean.RoomPKAttachment; +import com.chwl.core.im.custom.bean.RoomPkBean; +import com.chwl.core.im.custom.bean.TarotAttachment; +import com.chwl.core.im.custom.bean.TarotMsgBean; +import com.chwl.core.initial.InitialModel; +import com.chwl.core.manager.AudioEngineManager; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.manager.IMNetEaseManager; +import com.chwl.core.manager.RoomEvent; +import com.chwl.core.module_hall.hall.HallModel; +import com.chwl.core.module_hall.hall.bean.SuperAdminInfo; +import com.chwl.core.monsterhunting.bean.MonsterDataBean; +import com.chwl.core.monsterhunting.bean.MonsterHuntingResult; +import com.chwl.core.monsterhunting.bean.MonsterInfo; +import com.chwl.core.monsterhunting.manager.MonsterDataManager; +import com.chwl.core.noble.NobleResourceType; +import com.chwl.core.noble.NobleUtil; +import com.chwl.core.noble.bean.AllServiceGiftProtocol; +import com.chwl.core.noble.bean.NobleInfo; +import com.chwl.core.patriarch.event.CloseMinRoomEvent; +import com.chwl.core.patriarch.event.ImPushMsgPmLimitTimeEvent; +import com.chwl.core.patriarch.event.PmDismissAllLimitDialogEvent; +import com.chwl.core.patriarch.exception.PmRoomLimitException; +import com.chwl.core.redpackage.bean.RedPackageNotifyInfo; +import com.chwl.core.room.anotherroompk.ShowGiftDialogEvent; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.core.room.bean.RoomModeType; +import com.chwl.core.room.dragonball.DragonBallModel; +import com.chwl.core.room.event.FinishAvRoomEvent; +import com.chwl.core.room.event.RoomExitEvent; +import com.chwl.core.room.event.RoomTaskTipsEvent; +import com.chwl.core.room.game.bean.BaiShunGameConfig; +import com.chwl.core.room.pk.event.PKStateEvent; +import com.chwl.core.super_admin.util.SAdminOptUtil; +import com.chwl.core.super_admin.util.SuperAdminUtil; +import com.chwl.core.support.room.AudioRoomContext; +import com.chwl.core.support.room.RoomContext; +import com.chwl.core.support.room.RoomView; +import com.chwl.core.support.room.RoomWidget; +import com.chwl.core.treasurefairy.bean.FairyMsgInfoBean; +import com.chwl.core.user.UserModel; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.core.utils.LogUtils; +import com.chwl.core.utils.StringFormatUtils; +import com.chwl.library.base.factory.CreatePresenter; +import com.chwl.library.common.util.OtherExtKt; +import com.chwl.library.common.util.Utils; +import com.chwl.library.language.LanguageHelper; +import com.chwl.library.rxbus.RxBus; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; +import com.chwl.library.utils.UIUtils; +import com.chwl.library.widget.SVGAView; +import com.netease.nim.uikit.StatusBarUtil; +import com.netease.nimlib.sdk.NIMSDK; +import com.netease.nimlib.sdk.Observer; +import com.netease.nimlib.sdk.chatroom.ChatRoomMessageBuilder; +import com.netease.nimlib.sdk.chatroom.model.ChatRoomKickOutEvent; +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage; +import com.netease.nimlib.sdk.msg.model.BroadcastMessage; +import com.opensource.svgaplayer.SVGADrawable; +import com.opensource.svgaplayer.SVGAImageView; +import com.opensource.svgaplayer.SVGAParser; +import com.opensource.svgaplayer.SVGAVideoEntity; +import com.orhanobut.logger.Logger; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.lang.ref.WeakReference; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.LinkedList; + +import io.reactivex.Single; +import io.reactivex.SingleObserver; +import io.reactivex.disposables.Disposable; +import kotlin.Unit; +import kotlin.jvm.functions.Function1; + + +/** + * 房间入口 + * + * @author Administrator + */ +@CreatePresenter(AvRoomPresenter.class) +public class AVRoomActivity extends BaseMvpActivity + implements View.OnClickListener, IAvRoomView, RoomView { + + public static final int FROM_TYPE_NORMAL = 0; + public static final int FROM_TYPE_RECOMMEND = 1; + public static final int FROM_TYPE_USER = 2;//跟随用户进房 + public static final int FROM_TYPE_ALL_RED = 5;//通过全服红包进房 + public static final int FROM_TYPE_GAME_RECOMMEND = 8;//赛事详情进房 + public static final int FROM_TYPE_ROOM_PK = 9;//跨房PK进房 + public static final int FROM_TYPE_HELLO = 10;//新用户打招呼弹窗进房 + private static final String TAG = "AVRoomActivity"; + private static final int SHOW_RED_DIALOG_MAX = 10; + public static boolean isPKModel = false; + private static SVGAView.SVGACache svgaCache; + + public static SVGAView.SVGACache getSvgaCache() { + if (svgaCache == null) { + svgaCache = SVGAView.newCache(20); + } + return svgaCache; + } + + /** + * 管理限制进房 + */ + LimitEnterRoomHelper limitEnterRoomHelper; + private int fromType = FROM_TYPE_NORMAL;// 入口类型 0 其他 1 推荐 2 个人主页或者广场 + private String fromNick = "";// 从萌圈进入时 需要传入作品发布者的昵称 + private String fromUid = ""; + private int giftId; + private RelativeLayout finishLayout; + private ViewStub mVsRoomOffline; + private ImageView avatarBg; + private TextView nick; + private CircleImageView avatar; + private ViewStub mVsNobleOpen; + private NobleOpenNoticeView mNobleOpenNoticeView; + + private ViewStub vsTaskTips; + private LinearLayout llTaskTips; + private long roomUid; + @Nullable + private HomePartyFragment mCurrentFragment; + private InputPwdDialogFragment mPwdDialogFragment; + @Nullable + private RoomInfo mRoomInfo; + private ImageView ivHeadWear; + private MonsterDialog monsterDialog; + private ViewPager2 viewpager; + private VerticalViewPagerAdapter mAdapter; + /*********************************显示全服礼物***************************************/ + + private GiftBroadcastObserver giftObserver; + private Dialog giftDialog; + private LinkedList giftList; + @Nullable + private SingleRoomTipDialog singleRoomTipDialog; + // 通过红包进来时,有该参数 + private RedPackageNotifyInfo redPackageNotifyInfo; + + // 是否禁用VP滑动(true:不允许滑动;false:某些条件下可以滑动) + private boolean viewPagerInputDisable; + + private RoomNotifyManager roomNotify; + + private BaiShunGameWebFragment baiShunGameFragment; + private LeaderccGameWebFragment leaderccGameFragment; + private JoyPlayGameWebFragment joyPlayGameWebFragment; + + public static void start(Context context, long roomUid) { + startForFromType(context, roomUid, FROM_TYPE_NORMAL, null, null); + } + + public static void start(Context context, long roomUid, int fromType, String fromNick, @Nullable RedPackageNotifyInfo notifyInfo) { + startForFromType(context, roomUid, fromType, fromNick, null, notifyInfo, 0); + } + + public static void startForFromType(Context context, long roomUid, int fromType) { + startForFromType(context, roomUid, fromType, null, null); + } + + public static void startForFromGiftId(Context context, long roomUid, int giftId) { + startForFromType(context, roomUid, FROM_TYPE_NORMAL, null, null, null, giftId); + } + + + public static void startForFromType(Context context, long roomUid, int fromType, @Nullable String fromNick, @Nullable String fromUid) { + startForFromType(context, roomUid, fromType, fromNick, fromUid, null, 0); + } + + /** + * 如果在进房的时候就已经调用了room/get的话,可以使用这个方法进入房间,可以少调用一次room/get! + * + * @param context + * @param roomInfo + */ + public static void start(Context context, @NonNull RoomInfo roomInfo) { + if (AvRoomDataManager.get().isLimitEnterRoom(String.valueOf(roomInfo.getRoomUid()))) { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_activity_avroomactivity_01)); + return; + } + Intent intent = new Intent(context, AVRoomActivity.class); + intent.putExtra(Constants.ROOM_INFO, (Parcelable) roomInfo); + intent.putExtra(Constants.ROOM_UID, roomInfo.getUid()); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + } + + public static void startForFromType(Context context, + long roomUid, + int fromType, + @Nullable String fromNick, + @Nullable String fromUid, + @Nullable RedPackageNotifyInfo notifyInfo, + int giftId) { + if (AvRoomDataManager.get().isLimitEnterRoom(String.valueOf(roomUid))) { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_activity_avroomactivity_03)); + return; + } + Intent intent = new Intent(context, AVRoomActivity.class); + intent.putExtra(Constants.ROOM_UID, roomUid); + intent.putExtra("fromType", fromType); + if (!TextUtils.isEmpty(fromNick)) { + intent.putExtra("fromNick", fromNick); + } + if (!TextUtils.isEmpty(fromUid)) { + intent.putExtra("fromUid", fromUid); + } + if (notifyInfo != null) { + intent.putExtra("notifyInfo", notifyInfo); + } + if (giftId != 0) { + intent.putExtra("giftId", giftId); + } + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + } + + + public static void setBackBg(Context context, RoomInfo roomInfo, SVGAImageView svgaRoomBg, String[] bgPicture) { + if (roomInfo != null && svgaRoomBg != null) { + if (!StringFormatUtils.isBlank(roomInfo.getBackPic())) { + int resourceType = NobleUtil.getResourceType(roomInfo.getBackPic()); + if (resourceType == NobleResourceType.URLS) { + if (!roomInfo.getBackPic().equals(bgPicture[0])) { + bgPicture[0] = roomInfo.getBackPic(); + ImageLoadUtils.loadRoomBgBackground(context, bgPicture[0], svgaRoomBg); + } + } else if (resourceType == NobleResourceType.SVGAS) { + if (!roomInfo.getBackPic().equals(bgPicture[0])) { + bgPicture[0] = roomInfo.getBackPic(); + playSvgaUrlBg(svgaRoomBg, bgPicture[0]); + } + } + } else { + if (roomInfo.getType() == RoomInfo.ROOMTYPE_CP) { + bgPicture[0] = ""; + if (roomInfo.isOpenGame) { + svgaRoomBg.setImageResource(R.drawable.room_cp_game_bg); + } else { + svgaRoomBg.setImageResource(R.drawable.bg_room_cp); + } + } else if (roomInfo.getType() == RoomInfo.ROOM_TYPE_SINGLE) { + bgPicture[0] = ""; +// svgaRoomBg.setImageResource(R.drawable.bg_room_single_pic); + playSvgaBg(svgaRoomBg, "svga/room_bg_single.svga"); + } else { + bgPicture[0] = ""; + if (roomInfo.getRoomModeType() == RoomModeType.OPEN_PK_MODE) { + svgaRoomBg.setImageResource(R.drawable.bg_room_pk); + } else { + svgaRoomBg.setImageResource(R.drawable.bg_room_normal_default_pic); + } + } + } + } + } + + private static void playSvgaBg(SVGAImageView svgaRoomBg, String asstets) { + SVGAParser mSVGAParser = new SVGAParser(svgaRoomBg.getContext()); + mSVGAParser.decodeFromAssets(asstets, new SVGAParser.ParseCompletion() { + @Override + public void onComplete(SVGAVideoEntity svgaVideoEntity) { + SVGADrawable drawable = new SVGADrawable(svgaVideoEntity); + svgaRoomBg.setImageDrawable(drawable); + svgaRoomBg.startAnimation(); + } + + @Override + public void onError() { + } + }, null); + } + + private static void playSvgaUrlBg(SVGAImageView svgaRoomBg, String url) { + SVGAParser mSVGAParser = new SVGAParser(svgaRoomBg.getContext()); + try { + mSVGAParser.decodeFromURL(new URL(url), new SVGAParser.ParseCompletion() { + @Override + public void onComplete(SVGAVideoEntity svgaVideoEntity) { + SVGADrawable drawable = new SVGADrawable(svgaVideoEntity); + svgaRoomBg.setImageDrawable(drawable); + svgaRoomBg.startAnimation(); + } + + @Override + public void onError() { + } + }, null); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + } + + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + // 如果是同一个房间,则只更新房间的信息 + long oldRoomUid = roomUid; + initIntentExtra(intent); + if (roomUid != 0 && oldRoomUid == roomUid) { + updateRoomInfo(); + showRoomFragment(false); + dismissLoadingDialog(); + return; + } + // 相同类型的房间,但是是不同人的房间 + if (AvRoomDataManager.get().isFirstEnterRoomOrChangeOtherRoom(roomUid)) { + showLoadingDialog(); + dismissRedPackageDialog(); + if (mRoomInfo == null) { + updateRoomInfo(); + } else { + requestRoomInfoSuccessView(mRoomInfo); + } + } + } + + public void setCurrentItem(int item) { + dismissLoadingDialog(); + if (viewpager != null) { + tryEnabledViewPagerInput(); + viewpager.setCurrentItem(item, false); + } + } + + private void initIntentExtra(Intent intent) { + if (intent == null) return; + fromType = intent.getIntExtra("fromType", 0); + fromNick = intent.getStringExtra("fromNick"); + fromUid = intent.getStringExtra("fromUid"); + giftId = intent.getIntExtra("giftId", 0); + mRoomInfo = intent.getParcelableExtra(Constants.ROOM_INFO); + Object notifyInfo = intent.getSerializableExtra("notifyInfo"); + if (notifyInfo instanceof RedPackageNotifyInfo) { + redPackageNotifyInfo = (RedPackageNotifyInfo) notifyInfo; + } else { + redPackageNotifyInfo = null; + } + if (mRoomInfo != null) { + roomUid = mRoomInfo.getRoomUid(); + } else { + roomUid = intent.getLongExtra(Constants.ROOM_UID, 0); + } + OtherExtKt.doLog("initIntentExtra 进房 fromType = "+fromType); + OtherExtKt.doLog("进房方式 initIntentExtra() AvRoomDataManager.get().getRoomUid() = "+AvRoomDataManager.get().getRoomUid() + " roomUid "+roomUid); + RoomHelperManager.INSTANCE.setRoomUid(roomUid); + } + + @SuppressLint("CheckResult") + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_chat_room); + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + initIntentExtra(getIntent()); + mVsRoomOffline = findViewById(R.id.vs_room_offline); + mVsNobleOpen = findViewById(R.id.vs_noble_open_notice); + vsTaskTips = findViewById(R.id.vs_task_tips); + viewpager = findViewById(R.id.fragment_container); + InitialModel.get().getFairyOpenInfo(); + + IMNetEaseManager.get().getChatRoomEventObservable() + .compose(bindToLifecycle()) + .subscribe(this::onRoomEventReceive); + + EventBus.getDefault().register(this); + + if (mAdapter == null) { + mAdapter = new VerticalViewPagerAdapter(this); + viewpager.setOffscreenPageLimit(2); + viewpager.setOrientation(ViewPager2.ORIENTATION_VERTICAL); + viewpager.getChildAt(0).setOverScrollMode(View.OVER_SCROLL_NEVER); + disableViewPagerInput(); + viewpager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() { + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + if (positionOffset > 0 && position == 1) { + if (mAdapter == null || mAdapter.getItem(2) == null) return; + ((FakeSingleRoomFragment) mAdapter.getItem(2)).requestPreRoomInfo(); + if (singleRoomTipDialog != null) { + singleRoomTipDialog.dismissAllowingStateLoss(); + singleRoomTipDialog = null; + } + } else if (positionOffset > 0 && position == 0) { + if (mAdapter == null || mAdapter.getItem(0) == null) return; + ((FakeSingleRoomBackFragment) mAdapter.getItem(0)).requestPreRoomInfo(); + } + } + + @Override + public void onPageSelected(int position) { + + } + + @Override + public void onPageScrollStateChanged(int state) { + if (state == 0 && viewpager.getCurrentItem() == 2) { + showLoadingDialog(); + ((FakeSingleRoomFragment) mAdapter.getItem(2)).tryJumpRoom(); + disableViewPagerInput(); + } else if (state == 0 && viewpager.getCurrentItem() == 0) { + showLoadingDialog(); + ((FakeSingleRoomBackFragment) mAdapter.getItem(0)).tryJumpRoom(); + disableViewPagerInput(); + } + } + }); + viewpager.setAdapter(mAdapter); + viewpager.setCurrentItem(1, false); + } + + viewpager.post(() -> { + mCurrentFragment = (HomePartyFragment) mAdapter.getItem(1); + //第一次进来 + if (AvRoomDataManager.get().isFirstEnterRoomOrChangeOtherRoom(roomUid)) { + showLoadingDialog(); + if (mRoomInfo == null) { + updateRoomInfo(); + } else { + requestRoomInfoSuccessView(mRoomInfo); + } + OtherExtKt.doLog("进房方式 第一次进来 进房 AvRoomDataManager.get().getRoomUid() = "+AvRoomDataManager.get().getRoomUid() + " roomUid "+roomUid); + } else { + showRoomFragment(true); + if (UserUtils.getUserInfo().isFirstCharge()) { + getMvpPresenter().checkFirstCharge(); + } + RoomBoomManager.INSTANCE.setMRoomUid(AvRoomDataManager.get().getRoomUid()); + IMNetEaseManager.get().getChatRoomEventObservable().onNext(new RoomEvent().setEvent(RoomEvent.MSG_SELF_ENTER_ROOM)); + OtherExtKt.doLog("进房方式 最小化 进房 AvRoomDataManager.get().getRoomUid() = "+AvRoomDataManager.get().getRoomUid() + " roomUid "+roomUid); + } + }); + + roomNotify = new RoomNotifyManager(this); + roomNotify.setOnShowUserCard(new Function1() { + @Override + public Unit invoke(String s) { + if (mCurrentFragment != null) { + mCurrentFragment.showUserCardDialog(s); + } + return null; + } + }); + roomNotify.start(); + AvRoomDataManager.get().hasAvRoomAct = true; + } + + @Override + protected void onResume() { + super.onResume(); + AvRoomDataManager.get().roomNoDestory = true; + registerGiftBroadcastMessage(true); + if (giftList != null) { + giftList.clear(); + } + } + + private void onRoomEventReceive(RoomEvent roomEvent) { + if (roomEvent == null || roomEvent.getEvent() == RoomEvent.NONE) return; + int event = roomEvent.getEvent(); + switch (event) { + case RoomEvent.ENTER_ROOM: + onEnterRoom(); + break; + case RoomEvent.KICK_OUT_ROOM: + if (AvRoomDataManager.get().haveStartDragon && AvRoomDataManager.get().isOwner(roomEvent.getAccount())) { + giveUpDragonBar().subscribe(s -> onKickMember(roomEvent.getReason())); + } else { + onKickMember(roomEvent.getReason()); + } + break; + case RoomEvent.ROOM_MANAGER_ADD: + case RoomEvent.ROOM_MANAGER_REMOVE: + if (AvRoomDataManager.get().isOwner(roomEvent.getAccount())) { + if (roomEvent.getEvent() == RoomEvent.ROOM_MANAGER_ADD) { + toast(R.string.set_room_manager); + } else if (roomEvent.getEvent() == RoomEvent.ROOM_MANAGER_REMOVE) { + toast(R.string.remove_room_manager); + } + } + break; + case RoomEvent.RTC_ENGINE_NETWORK_BAD: + toast(ResUtil.getString(R.string.avroom_activity_avroomactivity_06)); + break; + case RoomEvent.RTC_ENGINE_NETWORK_CLOSE: + toast(ResUtil.getString(R.string.avroom_activity_avroomactivity_07)); + break; + case RoomEvent.ON_OPEN_NOBLE_NOTICE: + if (roomEvent.mRoomNobleMsgAttachment != null) { + NobleInfo nobleInfo = roomEvent.mRoomNobleMsgAttachment.nobleInfo; + if (nobleInfo == null) return; + if (mNobleOpenNoticeView == null) + mNobleOpenNoticeView = (NobleOpenNoticeView) mVsNobleOpen.inflate(); + mNobleOpenNoticeView.setVisibility(VISIBLE); + mNobleOpenNoticeView.setData(nobleInfo, roomEvent.mRoomNobleMsgAttachment.nick, + roomEvent.mRoomNobleMsgAttachment.type); + } + break; + case RoomEvent.MONSTER_STATUS_CHANGED: + MonsterDataBean dataBean = roomEvent.getMonsterStatusAttachment().getDataBean(); + Log.e(TAG, "onRoomEventReceive: monster status changed: " + dataBean); + RoomInfo myRoomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + // 当前为房间页面并且当前房间为怪兽出现房间时才出现通知 + if (UIUtils.isTopActivity(AVRoomActivity.this) && myRoomInfo != null && + myRoomInfo.getUid() == dataBean.getAppearRoomUid()) { + switch (dataBean.getMonsterStatus()) { + case MonsterInfo.MONSTER_STATUS_WILL_APPEAR: + if (dataBean.getBeforeAppearSeconds() <= 3 * 60 && + dataBean.getBeforeAppearSeconds() >= 45) { + if (monsterDialog != null && monsterDialog.isShowing()) { + monsterDialog.dismiss(); + } + monsterDialog = new MonsterDialog(AVRoomActivity.this, dataBean); + monsterDialog.show(); + } else if (dataBean.getBeforeAppearSeconds() < 15) { + if (monsterDialog != null && monsterDialog.isShowing()) { + monsterDialog.dismiss(); + } + monsterDialog = new MonsterDialog(AVRoomActivity.this, dataBean); + monsterDialog.show(); + } + break; + + case MonsterInfo.MONSTER_STATUS_DID_APPEAR: + if (dataBean.getAppearRoomUid() == AvRoomDataManager.get().mCurrentRoomInfo.getUid() && + UIUtils.isTopActivity(AVRoomActivity.this)) { + getMvpPresenter().getMonster(); + } + break; + + case MonsterInfo.MONSTER_STATUS_DID_LEAVE: + if (monsterDialog != null && monsterDialog.isShowing()) { + monsterDialog.dismiss(); + } + monsterDialog = new MonsterDialog(AVRoomActivity.this, dataBean); + monsterDialog.show(); + break; + } + } + break; + case RoomEvent.MONSTER_HUNTING_RESULT: + MonsterHuntingResult monsterHuntingResult = roomEvent.getMonsterHuntingResultAttachment().getResult(); + Log.e(TAG, "onRoomEventReceive: monster result has come: " + monsterHuntingResult); + RoomInfo currentRoomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + // 当前为房间页面并且当前房间为怪兽出现房间时才出现通知 + if (UIUtils.isTopActivity(AVRoomActivity.this) && currentRoomInfo != null && + currentRoomInfo.getUid() == monsterHuntingResult.getMonster().getAppearRoomUid()) { + MonsterDataBean monsterInfo = monsterHuntingResult.getMonster(); + if (monsterDialog != null && monsterDialog.isShowing()) { + monsterDialog.dismiss(); + } + monsterDialog = new MonsterDialog(AVRoomActivity.this, monsterInfo); + monsterDialog.show(); + } + break; + case RoomEvent.MY_SELF_KICK_OUT_ROOM_BY_S_ADMIN: + toBack(true); + break; + default: + } + } + + private void onKickMember(ChatRoomKickOutEvent reason) { + if (reason == null) return; + ChatRoomKickOutEvent.ChatRoomKickOutReason reasonReason = reason.getReason(); + getDialogManager().dismissDialog(); + if (reasonReason == ChatRoomKickOutEvent.ChatRoomKickOutReason.BE_BLACKLISTED) { + if (SAdminOptUtil.isOptBySAdmin(reason)) { + toast(R.string.add_to_room_black_list_by_s_admin); + } else { + toast(getString(R.string.add_black_list)); + } + finish(); + } else if (reasonReason == ChatRoomKickOutEvent.ChatRoomKickOutReason.CHAT_ROOM_INVALID) { + showLiveFinishView(AvRoomDataManager.get().getRoomUid()); + } else if (reasonReason == ChatRoomKickOutEvent.ChatRoomKickOutReason.KICK_OUT_BY_MANAGER) { + AvRoomDataManager.get().addCurrentRoomLimitEnter(); + if (SAdminOptUtil.isOptBySAdmin(reason)) { + toast(R.string.kick_out_room_by_s_admin); + } else { + toast(getString(R.string.kick_member_by_manager)); + } + finish(); + } else { + finish(); + } + } + + private void onEnterRoom() { + mRoomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + Logger.i(ResUtil.getString(R.string.avroom_activity_avroomactivity_08) + mRoomInfo.getRoomId()); + dismissDialog(); + if (AvRoomDataManager.get().isSingleRoom() && DemoCache.readSingleRoomTip()) { + DemoCache.saveSingleRoomTip(false); + if (singleRoomTipDialog == null) { + singleRoomTipDialog = new SingleRoomTipDialog(); + singleRoomTipDialog.show(this); + } + } + } + + /** + * @param isRoomMin 如果是最小化,则传ture + */ + private void showRoomFragment(boolean isRoomMin) { + mCurrentFragment = (HomePartyFragment) mAdapter.getItem(1); + tryEnabledViewPagerInput(); + viewpager.setCurrentItem(1, false); + if (isRoomMin) { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (mCurrentFragment != null) { + mCurrentFragment.setRoomBg(roomInfo); + } + getMvpPresenter().judgeIsLimitEnter(); + } + if (giftId != 0) { + RxBus.get().post(new ShowGiftDialogEvent().setGiftId(giftId)); + giftId = 0; + } + + /** + * TODO 临时方案:后续逐步完善整个房间的RoomContext替换计划 + * PS:目前房间进入的逻辑有些凌乱,没有明确的生命周期,看代码逻辑,无论是第一次还是再次进入都会走这里,所以在这里绑定View + */ + RoomContext roomContext = getRoomContext(); + if (roomContext != null) { + roomContext.onViewAttach(this); + } + } + + private void showLiveFinishView(long uid) { + if (finishLayout == null) { + finishLayout = (RelativeLayout) mVsRoomOffline.inflate(); + ivHeadWear = finishLayout.findViewById(R.id.iv_head_wear); + avatar = finishLayout.findViewById(R.id.avatar); + avatarBg = finishLayout.findViewById(R.id.avatar_bg); + nick = finishLayout.findViewById(R.id.nick); + } + //防止点击到底下的操作按钮 + finishLayout.setOnClickListener(null); + finishLayout.setVisibility(VISIBLE); + finishLayout.findViewById(R.id.home_page_btn).setOnClickListener(this); + finishLayout.findViewById(R.id.back_btn).setOnClickListener(this); + UserModel.get().getUserInfo(uid).subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) { + mCompositeDisposable.add(d); + } + + @Override + public void onSuccess(@NonNull UserInfo userInfo) { + setUserInfo(userInfo); + } + + @Override + public void onError(@NonNull Throwable e) { + e.printStackTrace(); + LogUtils.d("showLiveFinishView error"); + + } + }); + AvRoomDataManager.get().release(); + } + + private void dismissRedPackageDialog() { + if (mCurrentFragment != null) { + mCurrentFragment.dismissSendRedPackageDialog(); + } + } + + + private void setUserInfo(UserInfo userInfo) { + if (avatarBg == null || avatar == null || nick == null) return; + if (userInfo != null) { + ImageLoadUtils.loadImageWithBlurTransformation(this, userInfo.getAvatar(), avatarBg); + ImageLoadUtils.loadAvatarBig(userInfo.getAvatar(), avatar); + Drawable badgeDrawable = null; + if (userInfo.getNobleInfo() != null) { + // 勋章 + String badge = userInfo.getNobleInfo().getBadge(); + badgeDrawable = NobleUtil.getDrawable(this, badge); + // 头饰 + String headWear = userInfo.getNobleInfo().getHeadWear(); + NobleUtil.loadResource(headWear, ivHeadWear); + } + String nick = (badgeDrawable == null ? "" : " ") + userInfo.getNick(); + SpannableStringBuilder builder = new SpannableStringBuilder(nick); + if (badgeDrawable != null) { + badgeDrawable.setBounds(0, 0, Utils.dip2px(this, 18), Utils.dip2px(this, 18)); + CustomImageSpan imageSpan = new CustomImageSpan(badgeDrawable); + builder.setSpan(imageSpan, 0, 1, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + } + Drawable drawable = ContextCompat.getDrawable(this, + userInfo.getGender() == 1 ? R.drawable.ic_gender_male : R.drawable.ic_gender_female); + this.nick.setCompoundDrawablesWithIntrinsicBounds(null, null, drawable, null); + this.nick.setText(builder); + } else { + avatar.setImageResource(R.drawable.default_avatar); + } + } + + private void updateRoomInfo() { + getMvpPresenter().requestRoomInfoFromService(String.valueOf(roomUid)); + } + + private void showRoomPwdDialog(final RoomInfo roomInfo) { + if (!isValid()) return; + // fix bugs + if (afterOnSavedInstanceState) { + finish(); + return; + } + mPwdDialogFragment = InputPwdDialogFragment.newInstance(getString(R.string.input_pwd), + getString(R.string.ok), + getString(R.string.cancel), + roomInfo.getRoomPwd()); + mPwdDialogFragment.setStyle(DialogFragment.STYLE_NO_TITLE, R.style.TranslucentNoTitle); + if (getSupportFragmentManager() == null) return; + mPwdDialogFragment.show(getSupportFragmentManager(), "pwdDialog"); + + mPwdDialogFragment.setOnDialogBtnClickListener(new InputPwdDialogFragment.OnDialogBtnClickListener() { + @Override + public void onBtnConfirm() { + enterRoom(roomInfo); + } + + @Override + public void onBtnCancel() { + mPwdDialogFragment.dismiss(); + finish(); + } + }); + } + + @Override + public void exitRoom(RoomInfo currentRoomInfo) { + if (currentRoomInfo != null && currentRoomInfo.getUid() == roomUid) { + finish(); + } + } + + @Override + public void onRoomOnlineNumberSuccess(int onlineNumber) { + if (mCurrentFragment != null) + mCurrentFragment.onRoomOnlineNumberSuccess(onlineNumber); + } + + @Override + public void getMonsterInfoSuccess(MonsterInfo monsterInfo) { + // 把请求回来的数据缓存到内存里 + MonsterDataManager.get().setMonsterInfo(monsterInfo.getAppearRoomUid(), monsterInfo); + switch (monsterInfo.getMonsterStatus()) { + case MonsterInfo.MONSTER_STATUS_DID_APPEAR: + if (monsterInfo.getBeforeDisappearSeconds() >= 0) { + if (monsterDialog != null && monsterDialog.isShowing()) { + monsterDialog.dismiss(); + } + } + break; + } + } + + @Override + public void getMonsterInfoFail(String error) { + toast(error); + } + + public void toBack() { + toBack(false); + } + + /** + * @param justClosePage ture的话 表示 退出聊天室的方法不调用,关闭当前界面就行 + * 把退出聊天室交给Main执行 + */ + public void toBack(boolean justClosePage) { + EventBus.getDefault().post(new FinishAvRoomEvent()); + //陪伴房的弹框提示去掉,直接关闭即可 + if (!justClosePage) { + getMvpPresenter().exitRoom(); + } + AudioEngineManager.get().setNotRecord(false); + finish(); + } + + @Override + protected boolean needSteepStateBar() { + return true; + } + + @Override + protected void setStatusBar() { + super.setStatusBar(); + StatusBarUtil.transparencyBar(this); + } + + @Override + protected void onDestroy() { + AvRoomDataManager.get().hasAvRoomAct = false; + //关闭这么多弹窗,鬼知道哪个出问题了,简单的try catch下 + try { + // 确保关闭 dialog,避免出现 leak window 异常 + getDialogManager().dismissDialog(); + if (AvRoomDataManager.get().haveStartDragon) { + giveUpDragonBar(); + } + + // 避免 ISE + if (mPwdDialogFragment != null && mPwdDialogFragment.isAdded() + && !isFinishing()) { + mPwdDialogFragment.dismiss(); + mPwdDialogFragment = null; + } + if (monsterDialog != null) { + monsterDialog.cancelCountDownTimer(); + monsterDialog.dismiss(); + monsterDialog = null; + } + if (giftDialog != null && giftDialog.isShowing()) { + giftDialog.setOnDismissListener(null); + giftDialog.dismiss(); + giftDialog = null; + } + + if (limitEnterRoomHelper != null) { + limitEnterRoomHelper.release(); + } + dismissLoadingDialog(); + } catch (Exception e) { + Logger.i("关闭弹窗失败" + e.getMessage()); +// CrashReport.postCatchedException(e); + } + GiftModel.get().cancelCountDownTimer(); + EventBus.getDefault().unregister(this); + DemoCache.saveBoolean("FirstCharge", false); + if (svgaCache != null) { + svgaCache.clear(); + } + svgaCache = null; + GlobalNotifyManager.INSTANCE.clearQueue(); + super.onDestroy(); + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.home_page_btn: + if (mRoomInfo != null) { + UserInfoActivity.Companion.start(this, mRoomInfo.getUid()); + finish(); + } + break; + case R.id.back_btn: + finish(); + break; + default: + } + } + + @Override + public void onBackPressed() { + if (closeBaiShunGame()) { + return; + } + if (AvRoomDataManager.get().isGamePlaying(AvRoomDataManager.get().getMicPosition(AuthModel.get().getCurrentUid()))) { + getDialogManager().showOkCancelDialog(ResUtil.getString(R.string.avroom_activity_avroomactivity_09), false, + this::minRoomCode); + return; + } + if (mNobleOpenNoticeView != null && mNobleOpenNoticeView.getVisibility() == VISIBLE) { + mNobleOpenNoticeView.setVisibility(View.GONE); + } else if (AvRoomDataManager.get().haveStartDragon) { + getDialogManager().showOkCancelDialog(ResUtil.getString(R.string.avroom_activity_avroomactivity_010), false, new DialogManager.OkCancelDialogListener() { + @Override + public void onCancel() { + } + + @SuppressLint("CheckResult") + @Override + public void onOk() { + + //noinspection ResultOfMethodCallIgnored + giveUpDragonBar().subscribe(s -> { + new HomePartyPresenter().cancelDragon(); + minRoomCode(); + }); + + } + }); + } else { + minRoomCode(); + } + } + + /** + * 最小化房间的代码,放在一处 + */ + private void minRoomCode() { + EventBus.getDefault().post(new FinishAvRoomEvent()); + AvRoomDataManager.get().roomNoDestory = false; + super.onBackPressed(); + } + + @SuppressLint("CheckResult") + @Override + public void requestRoomInfoSuccessView(RoomInfo roomInfo) { + mRoomInfo = roomInfo; + if (mCurrentFragment != null) { + mCurrentFragment.setRoomBg(roomInfo); + } + // 超管绕过密码直接进房 + if (SuperAdminUtil.isSuperAdmin()) { + enterRoom(roomInfo); + return; + } + + if (!AvRoomDataManager.get().isFirstEnterRoomOrChangeOtherRoom(roomInfo.getUid()) + || TextUtils.isEmpty(roomInfo.getRoomPwd()) + || roomInfo.getUid() == AuthModel.get().getCurrentUid()) { + if (AvRoomDataManager.get().isCpRoom() && AvRoomDataManager.get().isRoomOwner()) { + getDialogManager().showOkCancelDialog(ResUtil.getString(R.string.avroom_activity_avroomactivity_011), false, new DialogManager.OkCancelDialogListener() { + @Override + public void onCancel() { + // cp房切换嗨聊房,弹框点击拒绝:防止从首页小图标重新进入cp房循环展示切换房间弹框; + AvRoomDataManager.get().setIsParty(false); + finish(); + } + + @Override + public void onOk() { + enterRoom(roomInfo); + } + }); + } else { + enterRoom(roomInfo); + } + } else { + if (isFinishing()) { + return; + } + HallModel.get().getRoomSuperAdminList(roomUid) + .map(superAdminInfos -> { + for (SuperAdminInfo superAdminInfo : superAdminInfos) { + if (superAdminInfo.getUid() == AuthModel.get().getCurrentUid()) { + return true; + } + } + return false; + }) + .subscribe(isSuperAdmin -> { + if (isSuperAdmin) { + enterRoom(roomInfo); + } else { + showRoomPwdDialog(roomInfo); + } + }, throwable -> showRoomPwdDialog(roomInfo)); + } + } + + private void enterRoom(RoomInfo roomInfo) { + if (getMvpPresenter() != null) { + getMvpPresenter().enterRoom(roomInfo, fromType, fromNick, fromUid); + } + } + + @Override + public void requestRoomInfoFailView(Throwable throwable) { + dismissLoadingDialog(); + getDialogManager().dismissDialog(); + if (throwable instanceof PmRoomLimitException) { + getLimitEnterRoomHelper().handleThisContext(context, throwable.getMessage(), false, () -> { + finish(); + //如果本身房间存在,这个时候直接finish,没有退出房间,应当退出 + EventBus.getDefault().post(new CloseMinRoomEvent()); + }); + return; + } + toast(throwable.getMessage()); + finish(); + } + + @Override + public void enterRoomSuccess() { + showRoomFragment(false); + //获取管理员 + getMvpPresenter().getNormalChatMember(); + getMvpPresenter().getSuperAdminList(); + getMvpPresenter().checkNewUserGift(); + if (UserUtils.getUserInfo().isFirstCharge()) { + getMvpPresenter().checkFirstCharge(); + } + if (fromType == FROM_TYPE_HELLO) { + getMvpPresenter().checkHelloMessage(); + } + if (!AvRoomDataManager.get().isRoomOwner() && + DemoCache.readNewUserChargeGift() == 0) { + DemoCache.saveNewUserChargeGift(1); + } + dismissLoadingDialog(); + + LogUtils.d("roomLog RoomBoomManager 第一次进 "); + RoomBoomManager.INSTANCE.setMRoomUid(AvRoomDataManager.get().getRoomUid()); + IMNetEaseManager.get().getChatRoomEventObservable().onNext(new RoomEvent().setEvent(RoomEvent.MSG_SELF_ENTER_ROOM)); + + } + + @Override + public void enterRoomFail(int code, String error) { + dismissDialog(); + dismissLoadingDialog(); + AvRoomDataManager.get().release(); + toast(error); + finish(); + } + + @Override + public void showFinishRoomView(long uid) { + dismissLoadingDialog(); + dismissDialog(); + showLiveFinishView(uid); + } + + @Override + public void showBlackEnterRoomView() { + dismissLoadingDialog(); + dismissDialog(); + AvRoomDataManager.get().release(); + toast(getString(R.string.add_black_list)); + finish(); + } + + @Override + public void showHelloMessageDialog(HelloMessageInfo helloMessageInfo) { + HelloMessageDialog.Companion.newInstance(helloMessageInfo).show(this); + } + + @Override + public void dismissLoadingDialog() { + getDialogManager().dismissDialog(); + } + + public void showLoadingDialog() { + getDialogManager().showProgressDialog(this, false); + } + + private void dismissDialog() { + getDialogManager().dismissDialog(); + if (mPwdDialogFragment != null) { + mPwdDialogFragment.dismiss(); + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onLogoutEvent(LogoutEvent event) { + finish(); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onPKStateEvent(PKStateEvent event) { + isPKModel = event != null && event.isCreate(); + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo != null && mCurrentFragment != null) { + mCurrentFragment.setRoomBg(roomInfo); + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onRoomTaskTipsEvent(RoomTaskTipsEvent event) { + if (TextUtils.isEmpty(event.getTaskCompleteMsg()) || TextUtils.isEmpty(event.getTaskUrl())) + return; + if (llTaskTips == null) { + llTaskTips = (LinearLayout) vsTaskTips.inflate(); + } + llTaskTips.setVisibility(VISIBLE); + llTaskTips.postDelayed(() -> llTaskTips.setVisibility(View.GONE), 3000); + TextView tvMsg = llTaskTips.findViewById(R.id.tv_tips_text); + tvMsg.setText(event.getTaskCompleteMsg()); + llTaskTips.setOnClickListener(v -> { + llTaskTips.setVisibility(View.GONE); + CommonWebViewActivity.start(this, event.getTaskUrl()); + }); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onRoomExitEvent(RoomExitEvent event) { + toBack(); + } + + public Single giveUpDragonBar() { + return DragonBallModel.get() + .clearDragonBar() + .compose(bindToLifecycle()) + .doOnError(throwable -> toast(throwable.getMessage())) + .doOnSuccess(s -> { + AvRoomDataManager.get().haveStartDragon = false; + }); + } + + protected void registerGiftBroadcastMessage(boolean register) { + if (giftObserver == null) { + giftObserver = new GiftBroadcastObserver(this); + } + NIMSDK.getMsgServiceObserve().observeBroadcastMessage(giftObserver, register); + } + + /** + * 接收到全局广播信息 + * + * @param body 信息实体 + */ + protected void onReceivedGiftBroadcastMessage(String body) { + + if (UserUtils.getUserInfo() == null || + AvRoomDataManager.get().isSelfGamePlaying()) + return; + BaseProtocol baseProtocol; + try { + baseProtocol = JSON.parseObject(body, BaseProtocol.class); + } catch (Exception e) { + baseProtocol = null; + } + if (baseProtocol == null) return; + if (!isValid()) return; + switch (baseProtocol.getFirst()) { +// case CUSTOM_MSG_HEADER_TYPE_GIFT: +// if (giftList == null) { +// giftList = new LinkedList<>(); +// } +// int second2 = baseProtocol.getSecond(); +// AllServiceGiftProtocol.DataBean data = JSON.parseObject(String.valueOf(baseProtocol.getData()), AllServiceGiftProtocol.DataBean.class); +// if (data == null || (data.getGiftUrl()) == null) +// return; +// giftList.add(data); +// if (second2 == CUSTOM_MSG_ALL_SERVICE_GIFT) { +// if (giftDialog != null && giftDialog.isShowing()) { +// // 如果当前以及有礼物弹窗在展示,则需要等到他 dismiss 后再显示下一个 +// AllServiceGiftProtocol.DataBean dataBean = giftList.peekFirst(); +// if (dataBean != null) { +// return; +// } else { +// giftDialog.dismiss(); +// } +// } else { +// showGiftDialog(); +// } +// } +// break; +// case CUSTOM_MSG_BOX://寻爱之旅 +// if (baseProtocol.getSecond() == CUSTOM_MSG_SUB_BOX_ALL_ROOM_NOTIFY_BY_SVGA) { +// RoomBoxPrizeAttachment roomBoxPrizeAttachment = new RoomBoxPrizeAttachment(CUSTOM_MSG_BOX, CUSTOM_MSG_SUB_BOX_ALL_ROOM_NOTIFY_BY_SVGA); +// RoomBoxPrizeInfo roomBoxPrizeBean = JSON.parseObject(String.valueOf(baseProtocol.getData()), RoomBoxPrizeInfo.class); +// roomBoxPrizeAttachment.setUid(roomBoxPrizeBean.getUid()); +// roomBoxPrizeAttachment.setPrizeName(roomBoxPrizeBean.getPrizeName()); +// roomBoxPrizeAttachment.setNick(roomBoxPrizeBean.getNick()); +// roomBoxPrizeAttachment.setBoxTypeStr(roomBoxPrizeBean.getBoxTypeStr()); +// roomBoxPrizeAttachment.setRoomUid(roomBoxPrizeBean.getRoomUid()); +// roomBoxPrizeAttachment.setPrizeNum(roomBoxPrizeBean.getPrizeNum()); +// roomBoxPrizeAttachment.setUserLevelLimit(roomBoxPrizeBean.getUserLevelLimit()); +// if (AvRoomDataManager.get().isOpenPureMode()) { +// // 純凈模式打開後,僅能看跟自己相關的砸蛋消息 +// if (Objects.equals(roomBoxPrizeAttachment.getUid(), AuthModel.get().getCurrentUid())) { +// ChatRoomMessage message = ChatRoomMessageBuilder.createChatRoomCustomMessage(String.valueOf(AvRoomDataManager.get().getRoomId()), roomBoxPrizeAttachment); +// IMNetEaseManager.get().addMessages(message); +// } +// } else { +// ChatRoomMessage message = ChatRoomMessageBuilder.createChatRoomCustomMessage(String.valueOf(AvRoomDataManager.get().getRoomId()), roomBoxPrizeAttachment); +// IMNetEaseManager.get().addMessages(message); +// IMNetEaseManager.get().getChatRoomEventObservable() +// .onNext(new RoomEvent() +// .setEvent(RoomEvent.BOX_NOTIFY_SVGA) +// .setChatRoomMessage(message)); +// } +// } +// break; + case CustomAttachment.CUSTOM_MESS_TAROT: + if (baseProtocol.getSecond() == CustomAttachment.CUSTOM_MESS_TAROT_SENIOR_PRIZE_WINNING) { + TarotMsgBean tarotMsgBean = JSON.parseObject(String.valueOf(baseProtocol.getData()), TarotMsgBean.class); + TarotAttachment tarotAttachment = new TarotAttachment(CustomAttachment.CUSTOM_MESS_TAROT, + CustomAttachment.CUSTOM_MESS_TAROT_SENIOR_PRIZE_WINNING); + tarotAttachment.setTarotMsgBean(tarotMsgBean); + ChatRoomMessage message = ChatRoomMessageBuilder.createChatRoomCustomMessage( + String.valueOf(AvRoomDataManager.get().getRoomId()), tarotAttachment); + IMNetEaseManager.get().getChatRoomEventObservable() + .onNext(new RoomEvent() + .setEvent(RoomEvent.TAROT_NOTIFY_SVGA) + .setChatRoomMessage(message)); + AvRoomDataManager.get().addChatRoomMessage(message); + } + break; + case CustomAttachment.CUSTOM_MSG_NOTIFY_H5: + if (baseProtocol.getSecond() == CustomAttachment.CUSTOM_MSG_NOTIFY_H5_SUB_WHOLE_SERVICE) { + NotifyH5Info bean = JSON.parseObject(String.valueOf(baseProtocol.getData()), NotifyH5Info.class); + NotifyH5Attachment notifyH5Attachment = new NotifyH5Attachment(baseProtocol.getSecond()); + notifyH5Attachment.setBean(bean); + ChatRoomMessage notifyH5Msg = ChatRoomMessageBuilder.createChatRoomCustomMessage( + String.valueOf(AvRoomDataManager.get().getRoomId()), notifyH5Attachment); + IMNetEaseManager.get().getChatRoomEventObservable() + .onNext(new RoomEvent() + .setEvent(RoomEvent.NOTIFY_H5) + .setChatRoomMessage(notifyH5Msg)); + } + break; + case CUSTOM_MSG_LUCKY_SEA://星级厨房 + if (baseProtocol.getSecond() == CUSTOM_MSG_LUCKY_SEA_GIFT_SERVER_ALL) { + RoomLuckySeaAttachment attachment = new RoomLuckySeaAttachment(CUSTOM_MSG_LUCKY_SEA, CUSTOM_MSG_LUCKY_SEA_GIFT_SERVER_ALL); + attachment.setRoomLuckySeaMsgBean(JSON.parseObject(String.valueOf(baseProtocol.getData()), RoomLuckySeaMsgBean.class)); + ChatRoomMessage message = ChatRoomMessageBuilder.createChatRoomCustomMessage(String.valueOf(AvRoomDataManager.get().getRoomId()), attachment); + IMNetEaseManager.get().addMessages(message); + IMNetEaseManager.get().noticeRoomEvent(message, RoomEvent.LUCKY_SEA_GIFT_SERVER_NOTIFY); + } + break; +// case CUSTOM_MSG_LUCKY_GIFT://福袋 +// if (baseProtocol.getSecond() == CUSTOM_MSG_LUCKY_GIFT_SERVER_NOTIFY || baseProtocol.getSecond() == CUSTOM_MSG_LUCKY_GIFT_SERVER_ALL) { +// RoomReceivedLuckyGiftAttachment attachment = new RoomReceivedLuckyGiftAttachment(CUSTOM_MSG_LUCKY_GIFT_SERVER_NOTIFY); +// attachment.setLuckyBagNoticeInfo(JSON.parseObject(String.valueOf(baseProtocol.getData()), LuckyBagNoticeInfo.class)); +// ChatRoomMessage message = ChatRoomMessageBuilder.createChatRoomCustomMessage(String.valueOf(AvRoomDataManager.get().getRoomId()), attachment); +// IMNetEaseManager.get().noticeServiceLuckyBagNotice(message); +// IMNetEaseManager.get().addMessages(message); +// } +// break; + case CUSTOM_MSG_FAIRY://夺宝精灵 + if (baseProtocol.getSecond() == CUSTOM_MSG_SUB_DRAW_GIFT_L5) { + FairyMsgAttachment attachment = new FairyMsgAttachment(CUSTOM_MSG_FAIRY, CUSTOM_MSG_SUB_DRAW_GIFT_L5); + attachment.setFairyMsgInfo(JSON.parseObject(String.valueOf(baseProtocol.getData()), FairyMsgInfoBean.class)); + ChatRoomMessage message = ChatRoomMessageBuilder.createChatRoomCustomMessage(String.valueOf(AvRoomDataManager.get().getRoomId()), attachment); + IMNetEaseManager.get().noticeRoomEvent(message, RoomEvent.FAIRY_DRAW_GIFT_L5); + } + break; + case CUSTOM_MSG_ROOM_PK: + if (baseProtocol.getSecond() == CUSTOM_MSG_SUB_ROOM_PK_NOTIFY) { + RoomPKAttachment attachment = new RoomPKAttachment(CUSTOM_MSG_SUB_ROOM_PK_NOTIFY); + attachment.setRoomPkBean(JSON.parseObject(String.valueOf(baseProtocol.getData()), RoomPkBean.class)); + ChatRoomMessage message = ChatRoomMessageBuilder.createChatRoomCustomMessage(String.valueOf(AvRoomDataManager.get().getRoomId()), attachment); + IMNetEaseManager.get().noticeRoomEvent(message, RoomEvent.ROOM_PK_NOTIFY); + } + break; + default: + break; + } + } + + private void showGiftDialog() { + if (giftList.size() == 0) return; + AllServiceGiftProtocol.DataBean data = giftList.peekFirst(); + if (data == null) return; + giftDialog = generateAllServiceGiftDialog(this, data); + giftDialog.setOnDismissListener(dialog -> { + giftList.pollFirst(); + AllServiceGiftProtocol.DataBean dataBean = giftList.peekFirst(); + if (dataBean != null) { + if (isValid()) { + showGiftDialog(); + } else { + giftList.clear(); + } + } + }); + giftDialog.show(); + } + + private AllServiceGiftLevelDialog generateAllServiceGiftDialog(@NonNull Context context, @NonNull AllServiceGiftProtocol.DataBean dataBean) { + return new AllServiceGiftLevelDialog(context, dataBean); + } + + @Override + protected void onPause() { + super.onPause(); + registerGiftBroadcastMessage(false); + } + + private void handlePmExitRoom() { + EventBus.getDefault().post(new PmDismissAllLimitDialogEvent()); + getMvpPresenter().exitRoom(); + } + + public LimitEnterRoomHelper getLimitEnterRoomHelper() { + if (limitEnterRoomHelper == null) { + limitEnterRoomHelper = new LimitEnterRoomHelper(); + } + return limitEnterRoomHelper; + } + + @Override + public void recoverRoomMinWhenPmLimit(Throwable throwable) { + getLimitEnterRoomHelper().handleThisContext(this, throwable.getMessage(), true, + this::handlePmExitRoom); + } + + @Override + public void showNewUserDialog(GiftInfo giftInfo) { + new NewUserGiftDialog(giftInfo).show(this); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onImPushMsgPmLimitTimeEvent(ImPushMsgPmLimitTimeEvent event) { + //时间到限制时间段之后,后台推送im消息 + getLimitEnterRoomHelper().handleThisContext(this, event.getData(), true, this::handlePmExitRoom); + } + + @Nullable + @Override + public Activity getActivity() { + return this; + } + + @Override + public FragmentManager getFragmentManager() { + return super.getFragmentManager(); + } + + @Nullable + @Override + public RoomContext getRoomContext() { + return AudioRoomContext.Companion.get(); + } + + @NonNull + @Override + public LiveData getRoomContextLiveData() { + return AudioRoomContext.Companion.getContextLiveData(); + } + + @NonNull + @Override + public LifecycleOwner getLifecycleOwner() { + return this; + } + + @NonNull + @Override + public androidx.fragment.app.FragmentManager getViewFragmentManager() { + return getSupportFragmentManager(); + } + + @Nullable + @Override + public RoomWidget findWidget(@NonNull String name) { + return null; + } + + + private static class GiftBroadcastObserver implements Observer { + private WeakReference mReference; + + GiftBroadcastObserver(AVRoomActivity activity) { + mReference = new WeakReference<>(activity); + } + + @Override + public void onEvent(BroadcastMessage broadcastMessage) { + if (broadcastMessage != null) { + String contentStr = broadcastMessage.getContent(); + Logger.i(ResUtil.getString(R.string.avroom_activity_avroomactivity_014) + contentStr); + if (TextUtils.isEmpty(contentStr)) return; + AVRoomActivity activity = mReference.get(); + if (activity == null) return; + if (activity.isValid()) { + JSONObject jsonObject; + try { + jsonObject = JSON.parseObject(contentStr); + if (jsonObject == null) return; + if (jsonObject.containsKey("body")) { + String body = jsonObject.getString("body"); + if (TextUtils.isEmpty(body)) return; + activity.onReceivedGiftBroadcastMessage(body); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + } + + @Override + protected void onReceiveChatRoomEvent(RoomEvent roomEvent) { + super.onReceiveChatRoomEvent(roomEvent); + switch (roomEvent.getEvent()) { + case RoomEvent.UP_MIC: + case RoomEvent.DOWN_MIC: + resetViewPagerInputEnabled(); + break; + } + } + + /** + * 禁用VP滑动 + */ + private void disableViewPagerInput() { + this.viewPagerInputDisable = true; + resetViewPagerInputEnabled(); + } + + private void tryEnabledViewPagerInput() { + this.viewPagerInputDisable = false; + resetViewPagerInputEnabled(); + } + + private void resetViewPagerInputEnabled() { + if (viewPagerInputDisable) { + viewpager.setUserInputEnabled(false); + } else { + if (AvRoomDataManager.get().isSingleRoom() && !AvRoomDataManager.get().isOwnerOnMic()) { + // 个播+没在麦位=可以滑动 + viewpager.setUserInputEnabled(true); + } else { + viewpager.setUserInputEnabled(false); + } + } + } + + public void showBaiShunGame(String url, BaiShunGameConfig config) { + OtherExtKt.doLog("百顺游戏启动 showBaiShunGame"); + closeBaiShunGame(); + baiShunGameFragment = BaiShunGameWebFragment.Companion.newInstance(url, config); + baiShunGameFragment.setListener(new IBaiShunGameListener() { + @Override + public void onGameClose() { + closeBaiShunGame(); + } + }); + findViewById(R.id.layout_baishun_game).setVisibility(VISIBLE); + getSupportFragmentManager().beginTransaction().replace(R.id.layout_baishun_game, baiShunGameFragment).commitAllowingStateLoss(); + } + + public void showLeaderccGame(String url, BaiShunGameConfig config) { + OtherExtKt.doLog("Leadercc游戏启动 showLeaderccGame"); + closeBaiShunGame(); + StringBuffer newUrl = new StringBuffer(url); + newUrl.append("&uid="+AuthModel.get().getCurrentUid()); + newUrl.append("&token="+config.getCode()); + newUrl.append("&lang=").append(LanguageHelper.INSTANCE.getH5GameLeaderccLan()); + newUrl.append("&roomid=").append(AvRoomDataManager.get().getRoomUid()); + leaderccGameFragment = LeaderccGameWebFragment.Companion.newInstance(newUrl.toString(), config); + leaderccGameFragment.setListener(new IBaiShunGameListener() { + @Override + public void onGameClose() { + closeBaiShunGame(); + } + }); + findViewById(R.id.layout_baishun_game).setVisibility(VISIBLE); + getSupportFragmentManager().beginTransaction().replace(R.id.layout_baishun_game, leaderccGameFragment).commitAllowingStateLoss(); + } + + //https://test.joysdk.com/fish/? + //&token=fSaVi6CYgSjIlJUQMMhwjxFx3rPWHYiZV8qX4WVmBX1dAUIgRT1YTa%2F2RBQqVVYX9BIUKv5FPpvhHqZfdvicyEfplodzM%2FIi%2BJhFwBjp0VhzsII8luDSzcPwuG23wZwH + //&lan=en + //&appKey=pjxnkeuvurv6h7gdgnjq + //gameId=25 + //&mini=0 + public void showJoyPlayGame(String url, BaiShunGameConfig config) { + OtherExtKt.doLog("JoyPlay游戏启动 showJoyPlayGame"); + closeBaiShunGame(); + StringBuffer newUrl = new StringBuffer(url); + newUrl.append("?&uid="+AuthModel.get().getCurrentUid()); + newUrl.append("&roomId=").append(AvRoomDataManager.get().getRoomUid()); + newUrl.append("&token="+config.getCode()); + newUrl.append("&lan=").append(LanguageHelper.INSTANCE.getH5GameLeaderccLan()); + newUrl.append("&gameId=").append(config.getGameId()); + newUrl.append("&appKey=").append(config.getAppKey()); + if (config.getShowType() != null && config.getShowType() == 2) { + newUrl.append("&mini=1"); + } else { + newUrl.append("&mini=0"); + } + joyPlayGameWebFragment = JoyPlayGameWebFragment.Companion.newInstance(newUrl.toString(), config); + joyPlayGameWebFragment.setListener(new IBaiShunGameListener() { + @Override + public void onGameClose() { + closeBaiShunGame(); + } + }); + findViewById(R.id.layout_baishun_game).setVisibility(VISIBLE); + getSupportFragmentManager().beginTransaction().replace(R.id.layout_baishun_game, joyPlayGameWebFragment).commitAllowingStateLoss(); + } + + private boolean closeBaiShunGame() { + boolean isClose = false; + if (baiShunGameFragment != null) { + if (baiShunGameFragment.isAdded()) { + getSupportFragmentManager().beginTransaction().remove(baiShunGameFragment).commitAllowingStateLoss(); + isClose = true; + } + } + if (leaderccGameFragment != null) { + if (leaderccGameFragment.isAdded()) { + getSupportFragmentManager().beginTransaction().remove(leaderccGameFragment).commitAllowingStateLoss(); + isClose = true; + } + } + if (joyPlayGameWebFragment != null) { + if (joyPlayGameWebFragment.isAdded()) { + getSupportFragmentManager().beginTransaction().remove(joyPlayGameWebFragment).commitAllowingStateLoss(); + isClose = true; + } + } + findViewById(R.id.layout_baishun_game).setVisibility(View.GONE); + baiShunGameFragment = null; + leaderccGameFragment = null; + joyPlayGameWebFragment = null; + return isClose; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/activity/CreatePKActivity.java b/app/src/main/java/com/chwl/app/avroom/activity/CreatePKActivity.java new file mode 100644 index 0000000..808ba2a --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/activity/CreatePKActivity.java @@ -0,0 +1,446 @@ +package com.chwl.app.avroom.activity; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.CompoundButton; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.RadioButton; +import android.widget.TextView; + +import androidx.gridlayout.widget.GridLayout; + +import com.netease.nim.uikit.StatusBarUtil; +import com.netease.nim.uikit.support.glide.GlideApp; +import com.chwl.app.R; +import com.chwl.app.avroom.dialog.PKSelectPeopleDialog; +import com.chwl.app.avroom.dialog.PKTimePickerDialog; +import com.chwl.app.avroom.presenter.CreatePKPresenter; +import com.chwl.app.avroom.view.ICreatePKView; +import com.chwl.app.base.BaseMvpActivity; +import com.chwl.app.base.TitleBar; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.room.pk.bean.PKMemberInfo; +import com.chwl.core.room.pk.bean.PKTeamInfo; +import com.chwl.core.room.pk.model.PkModel; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.library.base.factory.CreatePresenter; +import com.chwl.library.utils.ResUtil; + +import java.util.ArrayList; +import java.util.List; + +import io.reactivex.SingleObserver; +import io.reactivex.disposables.Disposable; + +/** + * @author jack + * @Description + * @Date 2018/12/28 + */ +@CreatePresenter(CreatePKPresenter.class) +public class CreatePKActivity extends BaseMvpActivity + implements ICreatePKView { + + private GridLayout glRedTeam; + private GridLayout glBlueTeam; + private ImageView ivRedAvatar1; + private TextView tvRedName1; + private ImageView ivRedAvatar2; + private TextView tvRedName2; + private ImageView ivRedAvatar3; + private TextView tvRedName3; + private ImageView ivRedAvatar4; + private TextView tvRedName4; + private ImageView ivBlueAvatar1; + private TextView tvBlueName1; + private ImageView ivBlueAvatar2; + private TextView tvBlueName2; + private ImageView ivBlueAvatar3; + private TextView tvBlueName3; + private ImageView ivBlueAvatar4; + private TextView tvBlueName4; + private RadioButton rbVoteTypeGiftValue; + private RadioButton rbVoteTypeGiftMember; + private LinearLayout llSelectTime; + private TextView tvPkTime; + private TextView okBtn; + private LinearLayout llInPk; + private TextView tvRecreateBtn; + private TextView tvClosePkMode; + + private final List redTeamAvatar = new ArrayList<>(); + private final List redTeamName = new ArrayList<>(); + + private final List blueTeamAvatar = new ArrayList<>(); + private final List blueTeamName = new ArrayList<>(); + + private List redTeamMember = new ArrayList<>(); + private List blueTeamMember = new ArrayList<>(); + + public static void start(Context context) { + Intent intent = new Intent(context, CreatePKActivity.class); + context.startActivity(intent); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_create_pk); + glRedTeam = findViewById(R.id.gl_red_team); + glBlueTeam = findViewById(R.id.gl_blue_team); + ivRedAvatar1 = findViewById(R.id.iv_red_avatar_1); + tvRedName1 = findViewById(R.id.tv_red_name_1); + ivRedAvatar2 = findViewById(R.id.iv_red_avatar_2); + tvRedName2 = findViewById(R.id.tv_red_name_2); + ivRedAvatar3 = findViewById(R.id.iv_red_avatar_3); + tvRedName3 = findViewById(R.id.tv_red_name_3); + ivRedAvatar4 = findViewById(R.id.iv_red_avatar_4); + tvRedName4 = findViewById(R.id.tv_red_name_4); + ivBlueAvatar1 = findViewById(R.id.iv_blue_avatar_1); + tvBlueName1 = findViewById(R.id.tv_blue_name_1); + ivBlueAvatar2 = findViewById(R.id.iv_blue_avatar_2); + tvBlueName2 = findViewById(R.id.tv_blue_name_2); + ivBlueAvatar3 = findViewById(R.id.iv_blue_avatar_3); + tvBlueName3 = findViewById(R.id.tv_blue_name_3); + ivBlueAvatar4 = findViewById(R.id.iv_blue_avatar_4); + tvBlueName4 = findViewById(R.id.tv_blue_name_4); + rbVoteTypeGiftValue = findViewById(R.id.rb_vote_type_gift_value); + rbVoteTypeGiftMember = findViewById(R.id.rb_vote_type_gift_member); + llSelectTime = findViewById(R.id.ll_select_time); + tvPkTime = findViewById(R.id.tv_pk_time); + okBtn = findViewById(R.id.ok_btn); + llInPk = findViewById(R.id.ll_in_pk); + tvRecreateBtn = findViewById(R.id.tv_recreate_btn); + tvClosePkMode = findViewById(R.id.tv_close_pk_mode); + + redTeamAvatar.add(ivRedAvatar1); + redTeamAvatar.add(ivRedAvatar2); + redTeamAvatar.add(ivRedAvatar3); + redTeamAvatar.add(ivRedAvatar4); + redTeamName.add(tvRedName1); + redTeamName.add(tvRedName2); + redTeamName.add(tvRedName3); + redTeamName.add(tvRedName4); + + blueTeamAvatar.add(ivBlueAvatar1); + blueTeamAvatar.add(ivBlueAvatar2); + blueTeamAvatar.add(ivBlueAvatar3); + blueTeamAvatar.add(ivBlueAvatar4); + blueTeamName.add(tvBlueName1); + blueTeamName.add(tvBlueName2); + blueTeamName.add(tvBlueName3); + blueTeamName.add(tvBlueName4); + + + rbVoteTypeGiftValue.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (isChecked) { + getMvpPresenter().setPkVoteMode(PkModel.PK_VOTE_MODE_GIFT_VALUE); + } + } + }); + rbVoteTypeGiftMember.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (isChecked) { + getMvpPresenter().setPkVoteMode(PkModel.PK_VOTE_MODE_PEOPLE_COUNT); + } + } + }); + llSelectTime.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + showSelectTimeDialog(); + } + }); + + okBtn.setOnClickListener(v -> { + //提交pk + if (AvRoomDataManager.get().isQueuingMicro()) { + getDialogManager().showOkCancelDialog(ResUtil.getString(R.string.avroom_activity_createpkactivity_01), + true, + new DialogManager.OkCancelDialogListener() { + @Override + public void onCancel() { + + } + + @Override + public void onOk() { + createPk(); + } + }); + + return; + } + createPk(); + + }); + + glRedTeam.setOnClickListener(v -> { + PKSelectPeopleDialog dialog = new PKSelectPeopleDialog(this, PKTeamInfo.TEAM_RED, getPKMemberList()); + dialog.setOnSelectPeopleListener(new PKSelectPeopleDialog.OnSelectPeopleListener() { + @Override + public void onSelectPeople(List micEntityList) { + List userInfoList = new ArrayList<>(); + for (PKSelectPeopleDialog.MicEntity micEntity : micEntityList) { + if (micEntity.isSelect) { + UserInfo userInfo = new UserInfo(); + userInfo.setUid(Long.parseLong(micEntity.uid)); + userInfo.setAvatar(micEntity.avatar); + userInfo.setNick(micEntity.nick); + userInfo.setGender(micEntity.gender); + userInfo.setGroupType(PKTeamInfo.TEAM_RED); + userInfoList.add(userInfo); + } + } + redTeamMember = userInfoList; + for (int i = 0; i < redTeamAvatar.size(); i++) { + if (i < userInfoList.size()) { + GlideApp.with(CreatePKActivity.this) + .load(userInfoList.get(i).getAvatar()) + .placeholder(R.drawable.default_avatar) + .dontAnimate() + .into(redTeamAvatar.get(i)); + redTeamName.get(i).setText(userInfoList.get(i).getNick()); + } else { + redTeamAvatar.get(i).setImageResource(R.mipmap.ic_red_seat); + redTeamName.get(i).setText(String.valueOf(i+1)); + } + } + + + } + }); + dialog.show(); + }); + + glBlueTeam.setOnClickListener(v -> { + PKSelectPeopleDialog dialog = new PKSelectPeopleDialog(this, PKTeamInfo.TEAM_BLUE, getPKMemberList()); + dialog.setOnSelectPeopleListener(new PKSelectPeopleDialog.OnSelectPeopleListener() { + @Override + public void onSelectPeople(List micEntityList) { + List userInfoList = new ArrayList<>(); + for (PKSelectPeopleDialog.MicEntity micEntity : micEntityList) { + if (micEntity.isSelect) { + UserInfo userInfo = new UserInfo(); + userInfo.setUid(Long.parseLong(micEntity.uid)); + userInfo.setAvatar(micEntity.avatar); + userInfo.setNick(micEntity.nick); + userInfo.setGender(micEntity.gender); + userInfo.setGroupType(PKTeamInfo.TEAM_BLUE); + userInfoList.add(userInfo); + } + } + blueTeamMember = userInfoList; + for (int i = 0; i < blueTeamAvatar.size(); i++) { + if (i < userInfoList.size()) { + GlideApp.with(CreatePKActivity.this) + .load(userInfoList.get(i).getAvatar()) + .placeholder(R.drawable.default_avatar) + .dontAnimate() + .into(blueTeamAvatar.get(i)); + blueTeamName.get(i).setText(userInfoList.get(i).getNick()); + } else { + blueTeamAvatar.get(i).setImageResource(R.mipmap.ic_blue_seat); + blueTeamName.get(i).setText(String.valueOf(i+1)); + } + } + } + }); + dialog.show(); + }); + + if (AvRoomDataManager.get().isOpenPKMode()) { + llInPk.setVisibility(View.VISIBLE); + tvRecreateBtn.setOnClickListener(v -> { + getDialogManager().showOkCancelDialog( + ResUtil.getString(R.string.avroom_activity_createpkactivity_02), + true, + new DialogManager.OkCancelDialogListener() { + @Override + public void onCancel() { + + } + + @Override + public void onOk() { + getDialogManager().showProgressDialog(CreatePKActivity.this); + getMvpPresenter().createPKAgain( + redTeamMember, + blueTeamMember + ) + .subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) { + mCompositeDisposable.add(d); + } + + @Override + public void onSuccess(String s) { + + toast(s); + getDialogManager().dismissDialog(); + finish(); + } + + @Override + public void onError(Throwable e) { + getDialogManager().dismissDialog(); + toast(e.getMessage()); + } + }); + } + }); + }); + + tvClosePkMode.setOnClickListener(v -> { + //关闭pk 模式 + getDialogManager().showOkCancelDialog(ResUtil.getString(R.string.avroom_activity_createpkactivity_04), + true, + new DialogManager.OkCancelDialogListener() { + @Override + public void onCancel() { + + } + + @Override + public void onOk() { + getDialogManager().showProgressDialog(CreatePKActivity.this); + getMvpPresenter().closePkMode() + .subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) { + mCompositeDisposable.add(d); + } + + @Override + public void onSuccess(String s) { + toast(s); + getDialogManager().dismissDialog(); + finish(); + } + + @Override + public void onError(Throwable e) { + toast(e.getMessage()); + getDialogManager().dismissDialog(); + } + }); + } + }); + }); + } else { + llInPk.setVisibility(View.GONE); + } + + } + + private void createPk() { + getDialogManager().showProgressDialog(CreatePKActivity.this); + getMvpPresenter().createPK( + redTeamMember, + blueTeamMember + ) + .subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) { + mCompositeDisposable.add(d); + } + + @Override + public void onSuccess(String s) { + + toast(s); + getDialogManager().dismissDialog(); + finish(); + + } + + @Override + public void onError(Throwable e) { + getDialogManager().dismissDialog(); + toast(e.getMessage()); + } + }); + } + + private List getPKMemberList() { + List pkMemberInfoList = new ArrayList<>(); + for (UserInfo userInfo : redTeamMember) { + PKMemberInfo pkMemberInfo = new PKMemberInfo(); + pkMemberInfo.setTeamId(PKTeamInfo.TEAM_RED); + pkMemberInfo.setUserInfo(userInfo); + pkMemberInfoList.add(pkMemberInfo); + } + for (UserInfo userInfo : blueTeamMember) { + PKMemberInfo pkMemberInfo = new PKMemberInfo(); + pkMemberInfo.setTeamId(PKTeamInfo.TEAM_BLUE); + pkMemberInfo.setUserInfo(userInfo); + pkMemberInfoList.add(pkMemberInfo); + } + return pkMemberInfoList; + } + + @Override + protected void onResume() { + super.onResume(); + if (getMvpPresenter().getPkMode() == -1) { + getMvpPresenter().setPkMode(PkModel.PK_MODE_TEAM); + } + if (getMvpPresenter().getPkVoteMode() == -1) { + getMvpPresenter().setPkVoteMode(PkModel.PK_VOTE_MODE_GIFT_VALUE); + rbVoteTypeGiftValue.setChecked(true); + } + if (getMvpPresenter().getPkDuration() == -1) { + getMvpPresenter().setPkDuration(30); + tvPkTime.setText(30 + ResUtil.getString(R.string.avroom_activity_createpkactivity_06)); + } + } + + private void showSelectTimeDialog() { + PKTimePickerDialog pkTimePickerDialog = new PKTimePickerDialog(this); + pkTimePickerDialog.setOnSelectTime(new PKTimePickerDialog.OnSelectTime() { + @Override + public void selectTime(long timeSecond) { + if (timeSecond < 30 || timeSecond > 1800) { + toast(ResUtil.getString(R.string.avroom_activity_createpkactivity_07)); + return; + } + tvPkTime.setText((timeSecond / 60) + ResUtil.getString(R.string.avroom_activity_createpkactivity_08) + (timeSecond % 60) + ResUtil.getString(R.string.avroom_activity_createpkactivity_09)); + getMvpPresenter().setPkDuration(timeSecond); + } + }); + pkTimePickerDialog.show(); + + } + + @Override + public void initTitleBar() { + initWhiteTitleBar(getString(R.string.create_PK)); + mTitleBar.addAction(new TitleBar.TextAction(getString(R.string.PK_record), + getResources().getColor(R.color.text_normal_c6c6e9)) { + @Override + public void performAction(View view) { + RecordForPKActivity.start(CreatePKActivity.this); + } + }); + } + + @Override + protected boolean needSteepStateBar() { + return true; + } + + @Override + protected void setStatusBar() { + StatusBarUtil.transparencyBar(this); + StatusBarUtil.StatusBarLightMode(this); + } + +} diff --git a/app/src/main/java/com/chwl/app/avroom/activity/RecordForPKActivity.java b/app/src/main/java/com/chwl/app/avroom/activity/RecordForPKActivity.java new file mode 100644 index 0000000..5132ab5 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/activity/RecordForPKActivity.java @@ -0,0 +1,151 @@ +package com.chwl.app.avroom.activity; + +import android.content.Context; +import android.content.Intent; +import android.graphics.Color; +import android.os.Bundle; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import com.netease.nim.uikit.StatusBarUtil; +import com.trello.rxlifecycle3.android.ActivityEvent; +import com.chwl.app.R; +import com.chwl.app.avroom.adapter.RecordForPKAdapter; +import com.chwl.app.avroom.presenter.RecordForPKPresenter; +import com.chwl.app.avroom.view.IRecordForPKView; +import com.chwl.app.base.BaseMvpActivity; +import com.chwl.library.common.util.Utils; +import com.chwl.app.ui.widget.recyclerview.decoration.ColorDecoration; +import com.chwl.core.room.pk.bean.PKRecordInfo; +import com.chwl.library.base.factory.CreatePresenter; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; + +import java.util.List; + +import io.reactivex.SingleObserver; +import io.reactivex.disposables.Disposable; + +/** + * @author jack + * @Description + * @Date 2018/12/29 + */ +@CreatePresenter(RecordForPKPresenter.class) +public class RecordForPKActivity extends BaseMvpActivity + implements IRecordForPKView { + + + private SwipeRefreshLayout srlRefreshContainer; + private RecyclerView rvList; + private RecordForPKAdapter adapter; + + public static void start(Context context) { + Intent intent = new Intent(context, RecordForPKActivity.class); + context.startActivity(intent); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_record_for_pk); + + srlRefreshContainer = (SwipeRefreshLayout) findViewById(R.id.srl_refresh_container); + rvList = (RecyclerView) findViewById(R.id.rv_list); + + srlRefreshContainer.setOnRefreshListener(this::refreshData); + + rvList.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)); + rvList.addItemDecoration(new ColorDecoration(Color.TRANSPARENT, 0, Utils.dip2px(this, 10), true)); + adapter = new RecordForPKAdapter(this, null); + adapter.setEnableLoadMore(true); + adapter.setOnLoadMoreListener(this::loadMoreData, rvList); + rvList.setAdapter(adapter); + + srlRefreshContainer.setRefreshing(true); + refreshData(); + } + + @Override + public void onReloadDate() { + super.onReloadDate(); + refreshData(); + } + + @Override + public void initTitleBar() { + super.initWhiteTitleBar(getString(R.string.PK_record)); + } + + public void refreshData() { + getMvpPresenter().refreshData() + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .subscribe(new SingleObserver>() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onSuccess(List pkRecordInfos) { + srlRefreshContainer.setRefreshing(false); + if (ListUtils.isListEmpty(pkRecordInfos)) { + showNoData(R.drawable.icon_common_failure, ResUtil.getString(R.string.avroom_activity_recordforpkactivity_01)); + return; + } + adapter.setNewData(pkRecordInfos); + + } + + @Override + public void onError(Throwable e) { + srlRefreshContainer.setRefreshing(false); + showNetworkErr(); + toast(e.getMessage()); + + } + }); + } + + private void loadMoreData() { + getMvpPresenter().loadMoreData() + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .subscribe(new SingleObserver>() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onSuccess(List pkRecordInfos) { + adapter.loadMoreComplete(); + if (!ListUtils.isListEmpty(pkRecordInfos)) { + adapter.addData(pkRecordInfos); + } else { + adapter.loadMoreEnd(true); + } + } + + @Override + public void onError(Throwable e) { + adapter.loadMoreComplete(); + toast(e.getMessage()); + } + }); + } + + @Override + protected boolean needSteepStateBar() { + return true; + } + + @Override + protected void setStatusBar() { + StatusBarUtil.transparencyBar(this); + StatusBarUtil.StatusBarLightMode(this); + } + + +} diff --git a/app/src/main/java/com/chwl/app/avroom/activity/RoomBgSettingActivity.kt b/app/src/main/java/com/chwl/app/avroom/activity/RoomBgSettingActivity.kt new file mode 100644 index 0000000..6a2f38e --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/activity/RoomBgSettingActivity.kt @@ -0,0 +1,77 @@ +package com.chwl.app.avroom.activity + +import android.annotation.SuppressLint +import androidx.core.view.WindowCompat +import com.chwl.app.R +import com.chwl.app.avroom.adapter.RoomBgAdapter +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.databinding.RoomBgSettingActivityBinding +import com.chwl.core.auth.AuthModel +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.room.model.RoomSettingModel +import com.chwl.library.utils.ResUtil +import com.netease.nim.uikit.StatusBarUtil + +class RoomBgSettingActivity : BaseViewBindingActivity() { + private val adapter = RoomBgAdapter() + + private val model = RoomSettingModel() + override fun init() { + initWhiteTitleBar(ResUtil.getString(R.string.room_theme)) + mTitleBar.setTitleColor(resources.getColor(R.color.white)) + mTitleBar.setLeftImageResource(R.drawable.arrow_left_white) + binding.recyclerView.adapter = adapter + adapter.selectItem(AvRoomDataManager.get().mCurrentRoomInfo?.backPic) + adapter.setOnItemClickListener { _, view, position -> + adapter.getItem(position)?.let { + if (adapter.getSelectItem() != it) { + showUpdateRoomBackgroundTips(it) + } + } + } + val list = listOf( + "https://image.molistar.xyz/BG_0.webp", + "https://image.molistar.xyz/BG_1.webp", + "https://image.molistar.xyz/BG_2.webp", + "https://image.molistar.xyz/BG_3.webp", + "https://image.molistar.xyz/BG_4.webp", + "https://image.molistar.xyz/BG_5.webp" + ) + adapter.setNewData(list) + } + + private fun showUpdateRoomBackgroundTips(url: String) { + dialogManager.showOkCancelDialog( + getString(R.string.room_theme_changed_tips), + getString(R.string.btn_text_confirm_select_team_member) + ) { + updateRoomBackground(url) + } + } + + @SuppressLint("CheckResult") + private fun updateRoomBackground(url: String) { + dialogManager.showProgressDialog(this) + model.updateRoomBackground(AuthModel.get().currentUid, url) + .compose(bindToLifecycle()).subscribe({ + dialogManager.dismissDialog() + toast(R.string.avroom_dialog_roomimposedialog_04) + adapter.selectItem(url) + }, { + dialogManager.dismissDialog() + toast(it.message) + }) + } + + override fun needSteepStateBar(): Boolean { + return true + } + + override fun setStatusBar() { + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + WindowCompat.getInsetsController(window, window.decorView).let { + it.isAppearanceLightStatusBars = false + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/activity/RoomBlackListActivity.java b/app/src/main/java/com/chwl/app/avroom/activity/RoomBlackListActivity.java new file mode 100644 index 0000000..d418820 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/activity/RoomBlackListActivity.java @@ -0,0 +1,201 @@ +package com.chwl.app.avroom.activity; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.chwl.app.R; +import com.chwl.app.avroom.adapter.RoomNormalListAdapter; +import com.chwl.app.avroom.presenter.RoomBlackPresenter; +import com.chwl.app.avroom.view.IRoomBlackView; +import com.chwl.app.base.BaseMvpActivity; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.im.room.IIMRoomCoreClient; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.core.room.model.AvRoomModel; +import com.chwl.core.super_admin.model.SuperAdminModel; +import com.chwl.core.super_admin.util.SuperAdminUtil; +import com.chwl.core.utils.net.DontWarnObserver; +import com.chwl.library.base.factory.CreatePresenter; +import com.chwl.library.coremanager.CoreEvent; +import com.chwl.library.utils.JavaUtil; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; +import com.netease.nim.uikit.StatusBarUtil; +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMember; +import com.trello.rxlifecycle3.android.ActivityEvent; + +import java.util.List; +import java.util.ListIterator; +import java.util.Objects; + +/** + * 黑名单 + * + * @author chenran + * @date 2017/10/11 + */ +@CreatePresenter(RoomBlackPresenter.class) +public class RoomBlackListActivity extends BaseMvpActivity + implements RoomNormalListAdapter.OnRoomNormalListOperationClickListener, IRoomBlackView { + private RecyclerView recyclerView; + private RoomNormalListAdapter normalListAdapter; + + private SuperAdminModel mSuperAdminModel; + + public static void start(Context context) { + Intent intent = new Intent(context, RoomBlackListActivity.class); + context.startActivity(intent); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_room_black_list); + initWhiteTitleBar(ResUtil.getString(R.string.avroom_activity_roomblacklistactivity_01)); + initView(); + mSuperAdminModel = new SuperAdminModel(); + loadData(); + } + + private void loadData() { + queryBlackListSuccess(AvRoomDataManager.get().mRoomLimitMemberList); + } + + private void initView() { + recyclerView = findViewById(R.id.recycler_view); + normalListAdapter = new RoomNormalListAdapter(this); + normalListAdapter.setListOperationClickListener(this); + recyclerView.setLayoutManager(new LinearLayoutManager(this)); + recyclerView.setAdapter(normalListAdapter); + } + + @Override + public void onRemoveOperationClick(final ChatRoomMember chatRoomMember) { + getDialogManager().showOkCancelDialog( + ResUtil.getString(R.string.avroom_activity_roomblacklistactivity_02) + chatRoomMember.getNick() + ResUtil.getString(R.string.avroom_activity_roomblacklistactivity_03), + true, + new DialogManager.OkCancelDialogListener() { + @Override + public void onCancel() { + + } + + @Override + public void onOk() { + //如果登录用户是超管 + if (SuperAdminUtil.isSuperAdmin()) { + //使用接口移除 + AvRoomModel.get().removeBlack(JavaUtil.str2long(chatRoomMember.getAccount())) + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .subscribe(new DontWarnObserver() { + @Override + public void accept(String s, String error) { + super.accept(s, error); + if (error == null) { + toast(ResUtil.getString(R.string.doSuccess)); + loadData(); + } else { + toast(error); + } + } + }); + mSuperAdminModel.roomOperate(SuperAdminModel.REMOVE_BLACK_LIST, JavaUtil.str2long(chatRoomMember.getAccount())).subscribe(); + return; + } + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo != null) { + getMvpPresenter().markBlackList(roomInfo.getRoomId(), + chatRoomMember.getAccount(), false); + } + + } + }); + } + + @Override + public View.OnClickListener getLoadListener() { + return new View.OnClickListener() { + @Override + public void onClick(View v) { + showLoading(); + loadData(); + } + }; + } + + @CoreEvent(coreClientClass = IIMRoomCoreClient.class) + public void onMemberBeRemoveManager(String account) { + long uid = AuthModel.get().getCurrentUid(); + if (uid == Long.valueOf(account)) { + finish(); + toast(R.string.remove_room_manager); + } + } + + @Override + public void queryBlackListSuccess(List chatRoomMemberList) { + hideStatus(); + if (chatRoomMemberList != null && chatRoomMemberList.size() > 0) { + normalListAdapter.setNormalList(chatRoomMemberList); + normalListAdapter.notifyDataSetChanged(); + mTitleBar.setTitle(ResUtil.getString(R.string.avroom_activity_roomblacklistactivity_05) + chatRoomMemberList.size() + ResUtil.getString(R.string.avroom_activity_roomblacklistactivity_06)); + } else { + showNoData(ResUtil.getString(R.string.avroom_activity_roomblacklistactivity_07)); + mTitleBar.setTitle(ResUtil.getString(R.string.avroom_activity_roomblacklistactivity_08)); + } + } + + @Override + public void queryBlackListFail() { + showNetworkErr(); + } + + @Override + public void makeBlackListSuccess(ChatRoomMember chatRoomMember, boolean mark) { + if (chatRoomMember == null) return; + List normalList = normalListAdapter.getNormalList(); + if (!ListUtils.isListEmpty(normalList)) { + hideStatus(); + ListIterator iterator = normalList.listIterator(); + while (iterator.hasNext()) { + if (Objects.equals(iterator.next().getAccount(), chatRoomMember.getAccount())) { + iterator.remove(); + } + } + mTitleBar.setTitle(ResUtil.getString(R.string.avroom_activity_roomblacklistactivity_09) + normalList.size() + ResUtil.getString(R.string.avroom_activity_roomblacklistactivity_010)); + if (normalList.size() == 0) { + showNoData(ResUtil.getString(R.string.avroom_activity_roomblacklistactivity_011)); + } + } else { + showNoData(ResUtil.getString(R.string.avroom_activity_roomblacklistactivity_012)); + mTitleBar.setTitle(ResUtil.getString(R.string.avroom_activity_roomblacklistactivity_013)); + } + normalListAdapter.notifyDataSetChanged(); + toast(ResUtil.getString(R.string.avroom_activity_roomblacklistactivity_014)); + + } + + @Override + public void makeBlackListFail(int code, String error, boolean mark) { +// toast(ResUtil.getString(R.string.avroom_activity_roomblacklistactivity_015)); + } + + + @Override + protected boolean needSteepStateBar() { + return true; + } + + @Override + protected void setStatusBar() { + StatusBarUtil.transparencyBar(this); + StatusBarUtil.StatusBarLightMode(this); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/activity/RoomInviteActivity.java b/app/src/main/java/com/chwl/app/avroom/activity/RoomInviteActivity.java new file mode 100644 index 0000000..b2172b8 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/activity/RoomInviteActivity.java @@ -0,0 +1,237 @@ +package com.chwl.app.avroom.activity; + +import static com.chwl.core.noble.NobleResourceType.KEY_ENTER_HIDE; + +import android.content.Intent; +import android.os.Bundle; +import android.text.TextUtils; + +import androidx.fragment.app.FragmentActivity; +import androidx.recyclerview.widget.RecyclerView; + +import com.chwl.app.R; +import com.chwl.app.avroom.adapter.RoomInviteAdapter; +import com.chwl.app.avroom.presenter.RoomInvitePresenter; +import com.chwl.app.avroom.view.IRoomInviteView; +import com.chwl.app.base.BaseMvpActivity; +import com.chwl.core.Constants; +import com.chwl.core.noble.NobleResourceType; +import com.chwl.core.room.bean.RoomOnlineUserBean; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.library.base.factory.CreatePresenter; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; +import com.netease.nim.uikit.StatusBarUtil; +import com.netease.nim.uikit.common.util.sys.NetworkUtil; +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMember; +import com.scwang.smart.refresh.layout.SmartRefreshLayout; +import com.scwang.smart.refresh.layout.api.RefreshLayout; +import com.scwang.smart.refresh.layout.listener.OnRefreshLoadMoreListener; + +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +; +; + +/** + *

抱人上麦

+ * + * @author jiahui + * @date 2017/12/21 + */ +@CreatePresenter(RoomInvitePresenter.class) +public class RoomInviteActivity extends BaseMvpActivity + implements IRoomInviteView, RoomInviteAdapter.OnItemClickListener, RoomInviteAdapter.OnRoomOnlineNumberChangeListener { + private RoomInviteAdapter mRoomInviteAdapter; + private SmartRefreshLayout mRefreshLayout; + private RecyclerView mRecyclerView; + + private int mPage = Constants.PAGE_START; + private int micPosition; + private boolean onlyManager; + + public static void openActivity(FragmentActivity fragmentActivity, int micPosition,boolean onlyManager) { + Intent intent = new Intent(fragmentActivity, RoomInviteActivity.class); + intent.putExtra(Constants.KEY_POSITION, micPosition); + intent.putExtra("only_manager", onlyManager); + fragmentActivity.startActivityForResult(intent, 200); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_room_invite); + mRecyclerView = findViewById(R.id.recycler_view); + mRefreshLayout = findViewById(R.id.refresh_layout); + onlyManager = getIntent().getBooleanExtra("only_manager", false); + initWhiteTitleBar(onlyManager ? ResUtil.getString(R.string.avroom_activity_roominviteactivity_01) : getString(R.string.title_online)); + Intent intent = getIntent(); + if (intent != null) + micPosition = intent.getIntExtra(Constants.KEY_POSITION, Integer.MIN_VALUE); + + mRoomInviteAdapter = new RoomInviteAdapter(this, this); + mRecyclerView.setAdapter(mRoomInviteAdapter); + mRoomInviteAdapter.setOnRoomOnlineNumberChangeListener(this); + mRefreshLayout.setOnRefreshLoadMoreListener(new OnRefreshLoadMoreListener() { + @Override + public void onLoadMore(RefreshLayout refreshLayout) { + if (!NetworkUtil.isNetAvailable(RoomInviteActivity.this)) { + mRefreshLayout.finishLoadMore(); + return; + } + List data = mRoomInviteAdapter.getChatRoomMemberList(); + if (ListUtils.isListEmpty(data)) { + mRefreshLayout.finishLoadMore(); + return; + } + loadData(data.get(data.size() - 1).getEnterTime()); + } + + @Override + public void onRefresh(RefreshLayout refreshLayout) { + if (!NetworkUtil.isNetAvailable(RoomInviteActivity.this)) { + mRefreshLayout.finishRefresh(); + return; + } + firstLoad(); + } + }); + showLoading(); + firstLoad(); + } + + public void firstLoad() { + mPage = Constants.PAGE_START; + loadData(0); + } + + private void loadData(long time) { + getMvpPresenter().requestChatMemberByPage(mPage, time, onlyManager); + } + + + @Override + public void onRequestRoomOnlineListSuccess(List memberList) { + + } + + @Override + public void onRequestChatMemberByPageFail(String errorStr, int page) { + mPage = page; + if (mPage == Constants.PAGE_START) { + mRefreshLayout.finishRefresh(0); + showNoData(getString(R.string.data_error)); + } else { + mRefreshLayout.finishLoadMore(0); + } + } + + @Override + public void onMemberInRefresh() { + + } + + @Override + public void onRequestMemberByPageSuccess(List memberList, int page) { + + Iterator iterator = memberList.iterator(); + while (iterator.hasNext()) { + ChatRoomMember next = iterator.next(); + if (next.getExtension() != null) { + Map map = (Map) next.getExtension().get(next.getAccount()); + if (map != null && map.containsKey(KEY_ENTER_HIDE)) { + if (Boolean.TRUE.equals(map.get(KEY_ENTER_HIDE))){ + iterator.remove(); + } + } + } + } + + + mPage = page; + if (mPage == Constants.PAGE_START) { + List chatRoomMemberList = mRoomInviteAdapter.getChatRoomMemberList(); + if (!ListUtils.isListEmpty(chatRoomMemberList)) chatRoomMemberList.clear(); + mRefreshLayout.finishRefresh(0); + if (ListUtils.isListEmpty(memberList)) { + showNoData(ResUtil.getString(R.string.avroom_activity_roominviteactivity_02)); + } else { + hideStatus(); + mRoomInviteAdapter.addChatRoomMemberList(memberList); + } + } else { + mRefreshLayout.finishLoadMore(0); + if (!ListUtils.isListEmpty(memberList)) { + mRoomInviteAdapter.addChatRoomMemberList(memberList); + } + } + } + + @Override + public void onClick(ChatRoomMember chatRoomMember) { + if (chatRoomMember == null) return; + + boolean isRobot = true; + Map extension = chatRoomMember.getExtension(); + if (extension != null) { + Map map = (Map) extension.get(chatRoomMember.getAccount()); + if (map != null) { + String defUser = map.get(UserInfo.DEF_USER) == null ? null : map.get(UserInfo.DEF_USER) + ""; + String resource = map.get(NobleResourceType.KEY_LEVEL) == null ? null : map.get(NobleResourceType.KEY_LEVEL) + ""; + if ((!TextUtils.isEmpty(defUser) && Integer.parseInt(defUser) != UserInfo.USER_TYPE_ROBOT) + || (!TextUtils.isEmpty(resource) && Integer.parseInt(resource) > 0)) { + isRobot = false; + } + } + } + if (isRobot) { +// Toast.makeText(context, context.getResources().getString(R.string.unable_to_up_mic_by_level), Toast.LENGTH_SHORT).show(); + SingleToastUtil.showToastShort(R.string.unable_to_up_mic_by_level); + return; + } + + Intent intent = new Intent(); + intent.putExtra("account", chatRoomMember.getAccount()); + String nick = chatRoomMember.getNick(); + intent.putExtra("nick", nick == null ? "" : nick); + intent.putExtra(Constants.KEY_POSITION, micPosition); + setResult(100, intent); + finish(); + } + + @Override + public void onReloadDate() { + super.onReloadDate(); + showLoading(); + firstLoad(); + } + + @Override + public void onRoomOnlineNumberChange(int number) { + if (number == 0) { + showNoData(); + } + } + + @Override + protected void onDestroy() { + if (mRoomInviteAdapter != null) + mRoomInviteAdapter.onRelease(); + super.onDestroy(); + } + + + @Override + protected boolean needSteepStateBar() { + return true; + } + + @Override + protected void setStatusBar() { + StatusBarUtil.transparencyBar(this); + StatusBarUtil.StatusBarLightMode(this); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/activity/RoomManagerListActivity.java b/app/src/main/java/com/chwl/app/avroom/activity/RoomManagerListActivity.java new file mode 100644 index 0000000..c40ad6e --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/activity/RoomManagerListActivity.java @@ -0,0 +1,160 @@ +package com.chwl.app.avroom.activity; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.chwl.app.R; +import com.chwl.app.avroom.adapter.RoomNormalListAdapter; +import com.chwl.app.avroom.presenter.RoomManagerPresenter; +import com.chwl.app.avroom.view.IRoomManagerView; +import com.chwl.app.base.BaseMvpActivity; +import com.chwl.app.common.util.DialogCommonUtil; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.core.bean.response.ServiceResult; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.library.base.factory.CreatePresenter; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; +import com.netease.nim.uikit.StatusBarUtil; +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMember; + +import java.util.List; +import java.util.ListIterator; +import java.util.Objects; + +/** + * 房间管理员列表 + * + * @author chenran + * @date 2017/10/11 + */ +@CreatePresenter(RoomManagerPresenter.class) +public class RoomManagerListActivity extends BaseMvpActivity + implements RoomNormalListAdapter.OnRoomNormalListOperationClickListener, IRoomManagerView { + private RecyclerView recyclerView; + private RoomNormalListAdapter normalListAdapter; + + public static void start(Context context) { + Intent intent = new Intent(context, RoomManagerListActivity.class); + context.startActivity(intent); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_room_manager_list); + initWhiteTitleBar(ResUtil.getString(R.string.avroom_activity_roommanagerlistactivity_01)); + initView(); + showLoading(); + loadData(); + } + + private void loadData() { + getMvpPresenter().queryManagerList(500); + } + + private void initView() { + recyclerView = findViewById(R.id.recycler_view); + normalListAdapter = new RoomNormalListAdapter(this); + normalListAdapter.setListOperationClickListener(this); + recyclerView.setLayoutManager(new LinearLayoutManager(this)); + recyclerView.setAdapter(normalListAdapter); + } + + @Override + public void onRemoveOperationClick(final ChatRoomMember chatRoomMember) { + getDialogManager().showOkCancelDialog(ResUtil.getString(R.string.avroom_activity_roommanagerlistactivity_02) + chatRoomMember.getNick() + ResUtil.getString(R.string.avroom_activity_roommanagerlistactivity_03), + true, new DialogManager.OkCancelDialogListener() { + @Override + public void onCancel() { + + } + + @Override + public void onOk() { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo != null) { + getMvpPresenter().removeManagerList(roomInfo.getRoomId(), chatRoomMember.getAccount()); + } + } + }); + } + + @Override + public View.OnClickListener getLoadListener() { + return new View.OnClickListener() { + @Override + public void onClick(View v) { + showLoading(); + loadData(); + } + }; + } + + @Override + public void queryManagerListSuccess(List chatRoomMemberList) { + + hideStatus(); + if (chatRoomMemberList != null && chatRoomMemberList.size() > 0) { + normalListAdapter.setNormalList(chatRoomMemberList); + normalListAdapter.notifyDataSetChanged(); + mTitleBar.setTitle(ResUtil.getString(R.string.avroom_activity_roommanagerlistactivity_04) + chatRoomMemberList.size() + ResUtil.getString(R.string.avroom_activity_roommanagerlistactivity_05)); + } else { + showNoData(ResUtil.getString(R.string.avroom_activity_roommanagerlistactivity_06)); + mTitleBar.setTitle(ResUtil.getString(R.string.avroom_activity_roommanagerlistactivity_07)); + } + } + + @Override + public void queryManagerListFail() { + showNetworkErr(); + } + + @Override + public void markManagerListSuccess(ChatRoomMember chatRoomMember) { + if (chatRoomMember == null) return; + List list = normalListAdapter.getNormalList(); + if (!ListUtils.isListEmpty(list)) { + hideStatus(); + ListIterator iterator = list.listIterator(); + while (iterator.hasNext()) { + if (Objects.equals(iterator.next().getAccount(), chatRoomMember.getAccount())) { + iterator.remove(); + } + } + mTitleBar.setTitle(ResUtil.getString(R.string.avroom_activity_roommanagerlistactivity_08) + list.size() + ResUtil.getString(R.string.avroom_activity_roommanagerlistactivity_09)); + if (list.size() == 0) { + showNoData(ResUtil.getString(R.string.avroom_activity_roommanagerlistactivity_010)); + } + } else { + showNoData(ResUtil.getString(R.string.avroom_activity_roommanagerlistactivity_011)); + mTitleBar.setTitle(ResUtil.getString(R.string.avroom_activity_roommanagerlistactivity_012)); + } + normalListAdapter.notifyDataSetChanged(); + toast(ResUtil.getString(R.string.avroom_activity_roommanagerlistactivity_013)); + } + + @Override + public void markManagerListFail(int code, String error) { + if (code == ServiceResult.CODE_ROOM_MANAGER_LIMIT) { + DialogCommonUtil.showManagerLimit(context); + } + } + + @Override + protected boolean needSteepStateBar() { + return true; + } + + @Override + protected void setStatusBar() { + StatusBarUtil.transparencyBar(this); + StatusBarUtil.StatusBarLightMode(this); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/activity/RoomOnlineUserActivity.java b/app/src/main/java/com/chwl/app/avroom/activity/RoomOnlineUserActivity.java new file mode 100644 index 0000000..b2f82b0 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/activity/RoomOnlineUserActivity.java @@ -0,0 +1,69 @@ +package com.chwl.app.avroom.activity; + +import android.content.Context; +import android.content.Intent; + +import com.netease.nim.uikit.StatusBarUtil; +import com.chwl.app.R; +import com.chwl.app.avroom.fragment.OnlineUserFragment; +import com.chwl.app.base.BaseBindingActivity; +import com.chwl.app.databinding.ActivityRoomOnlineUserBinding; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.library.annatation.ActLayoutRes; +import com.chwl.library.utils.ResUtil; + +@ActLayoutRes(R.layout.activity_room_online_user) +public class RoomOnlineUserActivity extends BaseBindingActivity { + + private String[] bgPicture = new String[]{""}; + + public static void start(Context context) { + Intent intent = new Intent(context, RoomOnlineUserActivity.class); + context.startActivity(intent); + } + + @Override + protected void init() { + initWhiteTitleBar(ResUtil.getString(R.string.avroom_activity_roomonlineuseractivity_01)); + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + AVRoomActivity.setBackBg(this, roomInfo, mBinding.svgaImageViewBg, bgPicture); + getSupportFragmentManager().beginTransaction() + .add(R.id.fragment_container, + new OnlineUserFragment(), + OnlineUserFragment.class.getSimpleName()) + .commitAllowingStateLoss(); + } + + @Override + public void initWhiteTitleBar(String title) { + mTitleBar = findViewById(R.id.title_bar); + if (mTitleBar != null) { + mTitleBar.setTitle(title); + mTitleBar.setImmersive(false); + mTitleBar.setTitleColor(getResources().getColor(R.color.white)); + mTitleBar.setLeftImageResource(R.drawable.arrow_left_white); + mTitleBar.setBackgroundResource(R.color.transparent); + mTitleBar.setLeftClickListener(v -> onLeftClickListener() + ); + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (mBinding.svgaImageViewBg.isAnimating()) { + mBinding.svgaImageViewBg.clearAnimation(); + } + } + + @Override + protected boolean needSteepStateBar() { + return true; + } + + @Override + protected void setStatusBar() { + StatusBarUtil.transparencyBar(this); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/activity/RoomRankListActivity.java b/app/src/main/java/com/chwl/app/avroom/activity/RoomRankListActivity.java new file mode 100644 index 0000000..fdc8442 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/activity/RoomRankListActivity.java @@ -0,0 +1,87 @@ +package com.chwl.app.avroom.activity; + +import android.content.Context; +import android.content.Intent; +import android.view.View; + +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentStatePagerAdapter; +import androidx.viewpager.widget.ViewPager; +import androidx.viewpager2.widget.ViewPager2; + +import com.chwl.app.R; +import com.chwl.app.avroom.adapter.CommonVPAdapter; +import com.chwl.app.avroom.fragment.RoomCharmListFragment; +import com.chwl.app.avroom.fragment.RoomContributeListFragment; +import com.chwl.app.base.BaseBindingActivity; +import com.chwl.app.databinding.ActivityRoomRankListBinding; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.library.annatation.ActLayoutRes; + +import java.util.ArrayList; +import java.util.List; + +/** + * 房间排行榜,(魅力榜+贡献榜) + */ +@ActLayoutRes(R.layout.activity_room_rank_list) +public class RoomRankListActivity extends BaseBindingActivity { + + + public static void start(Context context) { + Intent intent = new Intent(context, RoomRankListActivity.class); + context.startActivity(intent); + } + + private String [] bgPicture = new String[]{""}; + + @Override + protected void init() { + mBinding.setClick(this); + List list = new ArrayList<>(); + list.add(RoomCharmListFragment.newInstance()); + list.add(new RoomContributeListFragment()); + mBinding.viewPager.setAdapter(new CommonVPAdapter(getSupportFragmentManager(),getLifecycle(),list)); + mBinding.viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback(){ + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + + } + + @Override + public void onPageSelected(int position) { + mBinding.setPosition(position); + } + + @Override + public void onPageScrollStateChanged(int state) { + + } + }); + AVRoomActivity.setBackBg(this, AvRoomDataManager.get().mCurrentRoomInfo, mBinding.svgaImageViewBg, bgPicture); + } + + @Override + public void onClick(View v) { + super.onClick(v); + switch (v.getId()) { + case R.id.iv_back: + finish(); + break; + case R.id.tv_charm_tab: + mBinding.viewPager.setCurrentItem(0); + break; + case R.id.tv_contribute_tab: + mBinding.viewPager.setCurrentItem(1); + break; + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (mBinding.svgaImageViewBg.isAnimating()) { + mBinding.svgaImageViewBg.clearAnimation(); + } + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/activity/RoomSettingActivity.java b/app/src/main/java/com/chwl/app/avroom/activity/RoomSettingActivity.java new file mode 100644 index 0000000..a49a831 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/activity/RoomSettingActivity.java @@ -0,0 +1,1045 @@ +package com.chwl.app.avroom.activity; + + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.Intent; +import android.graphics.Bitmap; +import android.net.Uri; +import android.os.Bundle; +import android.text.SpannableString; +import android.text.TextUtils; +import android.view.View; +import android.widget.CompoundButton; +import android.widget.ImageView; +import android.widget.RelativeLayout; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; +import androidx.databinding.DataBindingUtil; + +import com.chwl.app.R; +import com.chwl.app.application.App; +import com.chwl.app.avroom.dialog.SelectLabelDialog; +import com.chwl.app.avroom.giftvalue.GiftValueDialogUiHelper; +import com.chwl.app.avroom.presenter.RoomSettingPresenter; +import com.chwl.app.avroom.view.IRoomSettingView; +import com.chwl.app.avroom.widget.EditRoomTitleDialog; +import com.chwl.app.base.BaseMvpActivity; +import com.chwl.app.base.PhotoPickActivity; +import com.chwl.app.common.util.BitmapUtil; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.app.databinding.ActivityRoomSettingBinding; +import com.chwl.app.ui.webview.CommonWebViewActivity; +import com.chwl.app.utils.RegexUtil; +import com.chwl.core.UriProvider; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.auth.event.KickOutEvent; +import com.chwl.core.bean.RoomQueueInfo; +import com.chwl.core.file.FileModel; +import com.chwl.core.im.custom.bean.CustomAttachment; +import com.chwl.core.im.custom.bean.RoomNoticeAttachment; +import com.chwl.core.kick.KickModel; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.manager.IMNetEaseManager; +import com.chwl.core.manager.RoomEvent; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.core.room.bean.RoomMessageViewNoticeInfo; +import com.chwl.core.room.bean.RoomSettingTabInfo; +import com.chwl.core.room.bean.SingleRoomSortInfo; +import com.chwl.core.room.giftvalue.GiftValueModel; +import com.chwl.core.room.giftvalue.helper.GiftValueMrg; +import com.chwl.core.room.model.AvRoomModel; +import com.chwl.core.room.model.RoomSettingModel; +import com.chwl.core.room.queue.bean.MicMemberInfo; +import com.chwl.core.super_admin.util.SuperAdminUtil; +import com.chwl.core.utils.LogUtils; +import com.chwl.core.utils.myutil.MyUriUtils; +import com.chwl.core.utils.net.BeanObserver; +import com.chwl.core.utils.net.DontWarnObserver; +import com.chwl.core.utils.net.RxHelper; +import com.chwl.library.base.factory.CreatePresenter; +import com.chwl.library.common.file.FileHelper; +import com.chwl.library.common.util.PhotoCompressCallback; +import com.chwl.library.common.util.PhotoCompressUtil; +import com.chwl.library.net.rxnet.callback.CallBack; +import com.chwl.library.utils.CommonUtils; +import com.chwl.library.utils.JavaUtil; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; +import com.chwl.library.utils.codec.DESUtils; +import com.hjq.toast.ToastUtils; +import com.netease.nim.uikit.StatusBarUtil; +import com.netease.nimlib.sdk.chatroom.ChatRoomMessageBuilder; +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage; +import com.yalantis.ucrop.UCrop; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import io.reactivex.SingleObserver; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import kotlinx.coroutines.Job; + +/** + * @author chenran + * @date 2017/9/26 + */ +@CreatePresenter(RoomSettingPresenter.class) +public class RoomSettingActivity extends BaseMvpActivity implements View.OnClickListener, IRoomSettingView { + + private RelativeLayout managerLayout; + private RelativeLayout blackLayout; + private RelativeLayout mRoomBgLayout; + private RoomInfo roomInfo; + + private String selectLabel; + private RoomSettingTabInfo mSelectTabInfo; + private List tabInfoList; + + @Nullable + private Long singleRoomSortId; + @Nullable + private String singleRoomSortName; + @Nullable + private List sortInfoList; + + private ActivityRoomSettingBinding binding; + + private Uri mUri; + private Job mJob; + private final int PERMISSION_CODE_STORAGE = 12; + private final int REQUEST_CODE_OPEN_PHOTO_PROVIDER = 111; // 从相册中选择 + private final int REQUEST_CODE_STORAGE = 42; + private final int MAX_BITMAP_SIZE = 100 * 1024 * 1024; // 剪切的图片最大为100 MB + + public static void start(Context context) { + Intent intent = new Intent(context, RoomSettingActivity.class); + context.startActivity(intent); + } + + @SuppressLint("CheckResult") + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + binding = DataBindingUtil.setContentView(this, R.layout.activity_room_setting); + initWhiteTitleBar(getString(R.string.room_setting)); + binding.setClick(this); + EventBus.getDefault().register(this); + roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) { + toast(ResUtil.getString(R.string.avroom_activity_roomsettingactivity_01)); + return; + } + initView(); + initLeaveMode(); + loadGiftValueState(); + getMvpPresenter().requestRoomInfo(roomInfo.getUid()); + mRoomBgLayout.setVisibility(View.GONE); + if (!AvRoomDataManager.get().isRoomOwner() && !AvRoomDataManager.get().isSuperAdmin()) { + managerLayout.setVisibility(View.GONE); + } else { + managerLayout.setVisibility(View.VISIBLE); + if (AvRoomDataManager.get().isRoomOwner()) { + mRoomBgLayout.setVisibility(View.GONE); + } + } + if (AvRoomDataManager.get().isCpRoom() || AvRoomDataManager.get().isSingleRoom()) { + binding.queuingMicroModeLayout.setVisibility(View.GONE); + } + binding.layoutSingleRoomSort.setVisibility( + AvRoomDataManager.get().isRoomOwner() && AvRoomDataManager.get().isSingleRoom() + ? View.VISIBLE : View.GONE); + binding.setRoomAvatar.setVisibility((AvRoomDataManager.get().isRoomOwner() || AvRoomDataManager.get().isRoomAdmin()) ? View.VISIBLE : View.GONE); + //调用更改房间信息接口后,会发消息ROOM_INFO_UPDATE,在此处接收ui改动 + IMNetEaseManager.get().getChatRoomEventObservable() + .compose(bindToLifecycle()) + .filter(roomEvent -> roomEvent.getEvent() == RoomEvent.ROOM_INFO_UPDATE) + .subscribe(roomEvent -> updateRoomInfoView()); + + } + + @Override + protected void onDestroy() { + super.onDestroy(); + EventBus.getDefault().unregister(this); + if (mJob != null) { + mJob.cancel(null); + } + } + + private void initView() { + managerLayout = findViewById(R.id.manager_layout); + blackLayout = findViewById(R.id.black_layout); + mRoomBgLayout = findViewById(R.id.room_bg_layout); + + managerLayout.setOnClickListener(this); + blackLayout.setOnClickListener(this); + mRoomBgLayout.setOnClickListener(this); + binding.layoutTheme.setOnClickListener(this); + + binding.switchAudio.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (isChecked) { + getDialogManager().showOkCancelWithTitleDialog(ResUtil.getString(R.string.avroom_activity_roomsettingactivity_02), + new SpannableString(ResUtil.getString(R.string.avroom_activity_roomsettingactivity_03)), + ResUtil.getString(R.string.avroom_activity_roomsettingactivity_04), ResUtil.getString(R.string.avroom_activity_roomsettingactivity_05), new DialogManager.OkCancelDialogListener() { + @Override + public void onCancel() { + binding.switchAudio.setChecked(false); + } + + @Override + public void onOk() { + binding.switchAudio.setChecked(true); + } + }); + } + } + }); + updateRoomInfoView(); + } + + /** + * 非cp房,牌照房,房主可设置离开模式 + */ + private void initLeaveMode() { + + if (AvRoomDataManager.get().isRoomOwner() && + !AvRoomDataManager.get().isCpRoom() && + roomInfo.getIsPermitRoom() == 1 && + !AvRoomDataManager.get().isOpenGame() && + !AvRoomDataManager.get().isSingleRoom() + ) { + binding.leaveModeLayout.setVisibility(View.VISIBLE); + } else { + binding.leaveModeLayout.setVisibility(View.GONE); + } + } + + private void loadGiftValueState() { + if (SuperAdminUtil.isSuperAdmin()) { + binding.layoutGiftValue.setVisibility(View.GONE); + return; + } + if (AvRoomDataManager.get().isCpRoom()) { + binding.layoutGiftValue.setVisibility(View.GONE); + return; + } + if (!AvRoomDataManager.get().isManager()) { + binding.layoutGiftValue.setVisibility(View.GONE); + return; + } + if (AvRoomDataManager.get().isOpenKTV()) { + binding.layoutGiftValue.setVisibility(View.GONE); + return; + } + boolean openGiftValue = AvRoomDataManager.get().isShowGiftValue(); + binding.layoutGiftValue.setVisibility(View.VISIBLE); + setSelected(binding.switchGiftValue, openGiftValue); + } + + /** + * 更改房间设置的消息 + */ + private void updateRoomInfoView() { + if (AvRoomDataManager.get().mCurrentRoomInfo == null) { + return; + } + roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + binding.tvRoomName.setText(RegexUtil.getPrintableString(roomInfo.getTitle())); + + + selectLabel = roomInfo.getRoomTag(); + if (selectLabel == null) { + selectLabel = ""; + } + binding.tvRoomLabel.setText(selectLabel); + binding.tvSingleRoomSort.setText(roomInfo.getSortName()); + binding.switchAudio.setChecked(roomInfo.getAudioQuality() == 2); + if (TextUtils.isEmpty(roomInfo.getRoomPwd())) { + binding.layoutPwdResult.setVisibility(View.GONE); + binding.ivRoomLock.setSelected(false); + binding.ivRoomLock.setImageResource(R.drawable.icon_room_set_lock_false); + } else { + binding.layoutPwdResult.setVisibility(View.VISIBLE); + try { + binding.tvPassword.setText(DESUtils.DESAndBase64Decrypt(roomInfo.getRoomPwd())); + } catch (Exception e) { + e.printStackTrace(); + } + binding.ivRoomLock.setSelected(true); + binding.ivRoomLock.setImageResource(R.drawable.icon_room_set_lock_true); + } + setupSwitch(roomInfo); + if (roomInfo.getType() == RoomInfo.ROOMTYPE_CP) { + binding.rlPwd.setVisibility(View.GONE); + binding.layoutPwdResult.setVisibility(View.GONE); + } + } + + private void save(final String name, final String pwd, String label) { + save(name, null, pwd, label, false, roomInfo.isHasAnimationEffect()); + } + + /** + * 保存用户信息,不需要改动的传null + * + * @param name 房间名字 + * @param pwd 房间密码 + * @param label 房间标签 + * @param isUpdateGiftEffect 是否改动了礼物特效 + * @param giftEffect 是否开启礼物特效 + */ + private void save(final String name, final String avatar, final String pwd, String label, boolean isUpdateGiftEffect, + boolean giftEffect) { + String desc = null; + getDialogManager().showProgressDialog(this, ResUtil.getString(R.string.avroom_activity_roomsettingactivity_06)); + int id = roomInfo.tagId; + if (mSelectTabInfo != null) { + id = mSelectTabInfo.getId(); + } + //更新房间接口调用成功后,会发事件RoomEvent.ROOM_INFO_UPDATE + RoomSettingModel model = new RoomSettingModel(); + BeanObserver observer = new BeanObserver() { + @Override + public void onErrorMsg(String error) { + toast(error); + getDialogManager().dismissDialog(); + } + + @Override + public void onSuccess(RoomInfo info) { + getDialogManager().dismissDialog(); + ToastUtils.show(R.string.avroom_activity_roommanagerlistactivity_013); + if (info != null) { + if (isUpdateGiftEffect && !giftEffect) { + getMvpPresenter().updateGiftEffect(info); + } + } + } + }; + if (AvRoomDataManager.get().isRoomOwner()) { + model.updateRoomInfo(name, avatar, desc, roomInfo.getIntroduction(), pwd, label, id, + AuthModel.get().getCurrentUid(), + AuthModel.get().getTicket(), + giftEffect, + binding.switchAudio.isChecked() ? 2 : 1, + roomInfo.getLimitType(), roomInfo.isPureMode(), + roomInfo.getType(), + roomInfo.getMgId(), + singleRoomSortId) + .compose(bindToLifecycle()) + .subscribe(observer); + } else if (AvRoomDataManager.get().isRoomAdmin()) { + model.updateByAdmin(roomInfo.getUid(), name, avatar, desc, roomInfo.getIntroduction(), pwd, label, id, + AuthModel.get().getCurrentUid(), + AuthModel.get().getTicket(), + giftEffect, + binding.switchAudio.isChecked() ? 2 : 1, + roomInfo.isPureMode()) + .compose(bindToLifecycle()) + .doOnSuccess(s -> { + getDialogManager().dismissDialog(); + ToastUtils.show(R.string.avroom_activity_roommanagerlistactivity_013); + }) + .doOnError(throwable -> { + if (throwable != null && throwable.getMessage() != null) { + toast(throwable.getMessage()); + } + getDialogManager().dismissDialog(); + }) + .subscribe(); + } + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.layout_theme: + startActivity(new Intent(context, RoomBgSettingActivity.class)); + break; + case R.id.manager_layout: + RoomManagerListActivity.start(this); + break; + case R.id.black_layout: + RoomBlackListActivity.start(this); + break; + case R.id.room_bg_layout: + CommonWebViewActivity.start(this, UriProvider.getRoomBg()); + break; + + case R.id.layout_room_name_edit: + EditRoomTitleDialog nameDialog = new EditRoomTitleDialog(this, + EditRoomTitleDialog.TYPE_EDIT_NAME, binding.tvRoomName.getText().toString()); + nameDialog.show(); + nameDialog.setOnEditTitleListner(new EditRoomTitleDialog.OnEditTitleListner() { + @Override + public void onEditTitleListner(String newName) { + if (newName.equals(roomInfo.getTitle())) { + return; + } + save(newName, null, null); + } + }); + break; + case R.id.iv_room_lock: + if (binding.ivRoomLock.isSelected()) { + //直接调接口取消密码 + save(null, "", null); + break; + } + //不break调,走编辑密码的逻辑 + case R.id.tv_password: + EditRoomTitleDialog pwdDialog = new EditRoomTitleDialog(this, + EditRoomTitleDialog.TYPE_EDIT_PASSWORD, binding.tvPassword.getText().toString()); + pwdDialog.setOnEditTitleListner(new EditRoomTitleDialog.OnEditTitleListner() { + @Override + public void onEditPwdListner(String newPwd) { + String encryptPwd = DESUtils.DESAndBase64(newPwd); + if (encryptPwd.equals(roomInfo.getRoomPwd())) { + return; + } + save(null, encryptPwd, null); + } + }); + pwdDialog.show(); + break; + case R.id.layout_label: + if (CommonUtils.isFastDoubleClick(1000)) return; + if (ListUtils.isListEmpty(tabInfoList)) { + getDialogManager().showProgressDialog(this); + getMvpPresenter().requestTagAll(); + } else { + onResultRequestTagAllSuccess(tabInfoList); + } + break; + case R.id.layout_single_room_sort: + if (CommonUtils.isFastDoubleClick(1000)) return; + if (ListUtils.isListEmpty(sortInfoList)) { + getDialogManager().showProgressDialog(this); + getMvpPresenter().requestSingleRoomSort(); + } else { + onResultRequestSingleRoomSortSuccess(sortInfoList); + } + break; + case R.id.switch_gift: + if (binding.switchGift.isSelected()) { + getDialogManager().showOkCancelWithTitleDialog(ResUtil.getString(R.string.avroom_activity_roomsettingactivity_07), + new SpannableString(ResUtil.getString(R.string.avroom_activity_roomsettingactivity_08)), + ResUtil.getString(R.string.avroom_activity_roomsettingactivity_09), ResUtil.getString(R.string.avroom_activity_roomsettingactivity_010), new DialogManager.OkCancelDialogListener() { + @Override + public void onCancel() { + + } + + @Override + public void onOk() { + save(null, null, null, null, true, false); + } + }); + return; + } + //开启礼物特效 + save(null, null, null, null, true, true); + break; + case R.id.switch_screen: + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) return; + getDialogManager().showProgressDialog(this, ResUtil.getString(R.string.avroom_activity_roomsettingactivity_012)); + AvRoomModel.get().closeScreen(roomInfo.getRoomId(), + !roomInfo.isCloseScreen()) + .compose(bindToLifecycle()) + .flatMap(data -> IMNetEaseManager.get().closeOpenScreen( + data.getRoomId(), data)) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) { + } + + @Override + public void onSuccess(Object o) { + roomInfo.setCloseScreen(!roomInfo.isCloseScreen()); + binding.switchScreen.setImageResource(!roomInfo.isCloseScreen() ? + R.drawable.icon_room_set_lock_true : R.drawable.icon_room_set_lock_false); + getDialogManager().dismissDialog(); + } + + @Override + public void onError(Throwable e) { + getDialogManager().dismissDialog(); + } + }); + break; + + case R.id.switch_queuing_micro_mode: + if (AvRoomDataManager.get().isOpenPKMode()) { + toast(ResUtil.getString(R.string.avroom_activity_roomsettingactivity_013)); + return; + } + if (AvRoomDataManager.get().isDatingMode()) { + toast(ResUtil.getString(R.string.avroom_activity_roomsettingactivity_014)); + return; + } + if (!AvRoomDataManager.get().isQueuingMicro()) { + getDialogManager().showOkCancelWithTitleDialog(ResUtil.getString(R.string.avroom_activity_roomsettingactivity_015), + new SpannableString(ResUtil.getString(R.string.avroom_activity_roomsettingactivity_016)), + ResUtil.getString(R.string.avroom_activity_roomsettingactivity_017), ResUtil.getString(R.string.avroom_activity_roomsettingactivity_018), new DialogManager.OkCancelDialogListener() { + @Override + public void onCancel() { + + } + + @Override + public void onOk() { + getMvpPresenter().openQueuingMicMode(); + } + }); + } else { + getDialogManager().showOkCancelWithTitleDialog(ResUtil.getString(R.string.avroom_activity_roomsettingactivity_020), + new SpannableString(ResUtil.getString(R.string.avroom_activity_roomsettingactivity_021)), + ResUtil.getString(R.string.avroom_activity_roomsettingactivity_022), ResUtil.getString(R.string.avroom_activity_roomsettingactivity_023), new DialogManager.OkCancelDialogListener() { + @Override + public void onCancel() { + + } + + @Override + public void onOk() { + getMvpPresenter().closeQueuingMicMode(); + } + }); + } + break; + + case R.id.switch_room_pure_mode: + if (!AvRoomDataManager.get().isOpenPureMode()) { + getDialogManager().showOkCancelWithTitleDialog(ResUtil.getString(R.string.avroom_activity_roomsettingactivity_024), + new SpannableString(ResUtil.getString(R.string.avroom_activity_roomsettingactivity_025)), + ResUtil.getString(R.string.avroom_activity_roomsettingactivity_026), ResUtil.getString(R.string.avroom_activity_roomsettingactivity_027), new DialogManager.OkCancelDialogListener() { + @Override + public void onCancel() { + + } + + @Override + public void onOk() { + getMvpPresenter().openRoomPureMode(); + } + }); + } else { + getDialogManager().showOkCancelWithTitleDialog(ResUtil.getString(R.string.avroom_activity_roomsettingactivity_029), + new SpannableString(ResUtil.getString(R.string.avroom_activity_roomsettingactivity_030)), + ResUtil.getString(R.string.avroom_activity_roomsettingactivity_031), ResUtil.getString(R.string.avroom_activity_roomsettingactivity_032), new DialogManager.OkCancelDialogListener() { + @Override + public void onCancel() { + + } + + @Override + public void onOk() { + // TODO: 2019/3/12 调用打开纯净模式的接口 + getMvpPresenter().closeRoomPureMode(); + } + }); + } + break; + + case R.id.switch_leave_mode: // 离开模式 + RoomInfo roomInfo1 = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo1 == null) + return; + + if (roomInfo1.isOpenKTV) { + toast(ResUtil.getString(R.string.avroom_activity_roomsettingactivity_033)); + return; + } + + if (!roomInfo1.isLeaveMode()) { + getDialogManager().showOkCancelWithTitleDialog(ResUtil.getString(R.string.avroom_activity_roomsettingactivity_034), + new SpannableString(ResUtil.getString(R.string.avroom_activity_roomsettingactivity_035)), + ResUtil.getString(R.string.avroom_activity_roomsettingactivity_036), ResUtil.getString(R.string.avroom_activity_roomsettingactivity_037), new DialogManager.OkCancelDialogListener() { + @Override + public void onCancel() { + + } + + @Override + public void onOk() { + getDialogManager().showProgressDialog(RoomSettingActivity.this, ResUtil.getString(R.string.avroom_activity_roomsettingactivity_038)); + downMicroFirst(); + } + }); + + } else { + getDialogManager().showProgressDialog(RoomSettingActivity.this, ResUtil.getString(R.string.avroom_activity_roomsettingactivity_039)); + if (AvRoomDataManager.get().isShowGiftValue()) // 礼物值模式下关闭离开模式需要执行礼物值下麦清除礼物值 + GiftValueMrg.get().requestDownMic(-1, String.valueOf(AuthModel.get().getCurrentUid())); + getMvpPresenter().leaveModeClose(roomInfo1.getUid()); + } + break; + + case R.id.switch_gift_value: + switchGiftValue(); + break; + case R.id.setRoomAvatar: + checkStoragePermission(); + break; + default: + } + } + + private void checkStoragePermission() { + PhotoPickActivity.start(this, PhotoPickActivity.IMG); + } + + + private void switchGiftValue() { + if (AvRoomDataManager.get().isCpRoom()) { + return; + } + if (AvRoomDataManager.get().isDatingMode()) { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_029)); + return; + } + if (AvRoomDataManager.get().isOpenKTV()) { + SingleToastUtil.showToast(R.string.before_open_gift_value_should_close_ktv_model); + return; + } + //开启礼物值不需要弹框 + if (!AvRoomDataManager.get().isShowGiftValue()) { + handleOpenGiftValue(); + return; + } + if (!GiftValueDialogUiHelper.get().isNeedConfirmDialog( + GiftValueDialogUiHelper.TYPE_CLOSE_SHOW_GIFT_VALUE)) { + handleOpenGiftValue(); + return; + } + GiftValueDialogUiHelper.get().showGiftValueDialog(context, getDialogManager(), + GiftValueDialogUiHelper.TYPE_CLOSE_SHOW_GIFT_VALUE, + this::handleOpenGiftValue); + } + + private void handleOpenGiftValue() { + boolean isOpen = !binding.switchGiftValue.isSelected(); + getDialogManager().showProgressDialog(this); + GiftValueModel.get().openGiftValue(isOpen) + .compose(RxHelper.bindContext(context)) + .subscribe(new DontWarnObserver() { + @Override + public void accept(String s, String error) { + super.accept(s, error); + getDialogManager().dismissDialog(); + if (error != null) { + SingleToastUtil.showToast(error); + } else { + setSelected(binding.switchGiftValue, !binding.switchGiftValue.isSelected()); + } + } + }); + } + + @Override + public void onResultRequestTagAllSuccess(List tabInfoList) { + this.tabInfoList = tabInfoList; + getDialogManager().dismissDialog(); + if (ListUtils.isListEmpty(tabInfoList)) { + toast(ResUtil.getString(R.string.avroom_activity_roomsettingactivity_040)); + return; + } + List labels = new ArrayList<>(); + for (RoomSettingTabInfo tabInfo : tabInfoList) { + labels.add(tabInfo.getName()); + } + new SelectLabelDialog(this, ResUtil.getString(R.string.avroom_activity_roomsettingactivity_041), labels, roomInfo.getRoomTag(), (label, data, position) -> { + mSelectTabInfo = tabInfoList.get(position); + selectLabel = (String) data; + }, v -> { + //选择的是同一个则不处理 + if (TextUtils.isEmpty(selectLabel) || selectLabel.equals(roomInfo.getRoomTag())) { + return; + } + save(null, null, selectLabel); + }).show(); + } + + @Override + public void onResultRequestTagAllFail(String error) { + getDialogManager().dismissDialog(); + toast(error); + } + + @Override + public void onResultRequestSingleRoomSortSuccess(List tabInfoList) { + sortInfoList = tabInfoList; + getDialogManager().dismissDialog(); + if (ListUtils.isListEmpty(tabInfoList)) { + toast(ResUtil.getString(R.string.avroom_activity_roomsettingactivity_042)); + return; + } + List labels = new ArrayList<>(); + for (SingleRoomSortInfo tabInfo : tabInfoList) { + labels.add(tabInfo.getSortName()); + } + new SelectLabelDialog(this, ResUtil.getString(R.string.avroom_activity_roomsettingactivity_043), labels, roomInfo.getRoomTag(), (label, data, position) -> { + singleRoomSortId = tabInfoList.get(position).getId(); + singleRoomSortName = (String) data; + }, v -> { + //选择的是同一个则不处理 + if (TextUtils.isEmpty(singleRoomSortName) || Objects.equals(singleRoomSortName, roomInfo.getSortName())) { + return; + } + save(null, null, roomInfo.getRoomTag()); + }).show(); + } + + @Override + public void onResultRequestSingleRoomSortFail(String error) { + getDialogManager().dismissDialog(); + toast(error); + } + + @Override + public void reQuestRoomInfo(RoomInfo roomInfo) { + AvRoomDataManager.get().mCurrentRoomInfo = roomInfo; + setupSwitch(roomInfo); + } + + private void setupSwitch(RoomInfo roomInfo) { + // 礼物特效开关状态 + binding.switchGift.setSelected(roomInfo.isHasAnimationEffect()); + binding.switchGift.setImageResource(roomInfo.isHasAnimationEffect() ? + R.drawable.icon_room_set_lock_true : R.drawable.icon_room_set_lock_false); + // 公屏开关状态 + binding.switchScreen.setSelected(!roomInfo.isCloseScreen()); + binding.switchScreen.setImageResource(!roomInfo.isCloseScreen() ? + R.drawable.icon_room_set_lock_true : R.drawable.icon_room_set_lock_false); + // 排麦模式的开关状态 + boolean isQueuingMicro = AvRoomDataManager.get().isQueuingMicro() || AvRoomDataManager.get().isOpenPKMode(); + boolean hindMicroMode = AvRoomDataManager.get().isOpenGame() || AvRoomDataManager.get().isSingleRoom(); + binding.queuingMicroModeLayout.setVisibility(hindMicroMode ? View.GONE : View.VISIBLE); + binding.switchQueuingMicroMode.setSelected(isQueuingMicro); + binding.switchQueuingMicroMode.setImageResource(isQueuingMicro ? + R.drawable.icon_room_set_lock_true : R.drawable.icon_room_set_lock_false); + // 纯净模式的开关状态 + binding.switchRoomPureMode.setSelected(roomInfo.isPureMode()); + binding.switchRoomPureMode.setImageResource(roomInfo.isPureMode() ? + R.drawable.icon_room_set_lock_true : R.drawable.icon_room_set_lock_false); + // 纯净模式提示语 + binding.tvTipsRoomPureMode.setVisibility(binding.switchRoomPureMode.isSelected() ? + View.VISIBLE : View.GONE); + + // 离开模式 + binding.switchLeaveMode.setSelected(roomInfo.isLeaveMode()); + binding.switchLeaveMode.setImageResource(roomInfo.isLeaveMode() ? + R.drawable.icon_room_set_lock_true : R.drawable.icon_room_set_lock_false); + binding.tvTipsLeaveMode.setVisibility(roomInfo.isLeaveMode() ? View.VISIBLE : View.GONE); + } + + @Override + public void onSuccessToFinish() { + finish(); + } + + @Override + public void onFailToToast(String error) { + toast(error); + } + + @Override + public void onUpdateRoomPureMode(RoomInfo roomInfo) { + getDialogManager().dismissDialog(); + setupSwitch(roomInfo); + sendRoomPureModeMsg(roomInfo.isPureMode()); + } + + @SuppressWarnings("CheckResult") + private void downMicroFirst() { + RoomInfo tempRoomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (tempRoomInfo == null) + return; + + // 新版房主位优先判断麦序是否有人,麦序没人再判断是否是离开模式(防止新版展示离开模式,实际麦位有人) + + int position = AvRoomDataManager.get().getMicPosition(tempRoomInfo.getUid()); + if (position != AvRoomDataManager.POSITON_NOT_ON_MIC) { // 房主在麦上 + // 房主下麦 + IMNetEaseManager.get().downMicroPhoneBySdk(position, new CallBack() { + @Override + public void onSuccess(String data) { + getDialogManager().dismissDialog(); + getMvpPresenter().leaveModeOpen(AvRoomDataManager.get().getRoomUid()); + } + + @Override + public void onFail(int code, String error) { + getDialogManager().dismissDialog(); + } + }); + + if (position != -1) { // 房主不在房主位, 房主位上的用户下麦 + RoomQueueInfo queueInfo = AvRoomDataManager.get().getRoomQueueMemberInfoByMicPosition(-1); + if (queueInfo != null && queueInfo.mChatRoomMember != null) { // 房主麦没人 + MicMemberInfo tempChatRoomMember = queueInfo.mChatRoomMember; + long micUid = JavaUtil.str2long(tempChatRoomMember.getAccount()); + String nick = tempChatRoomMember.getNick(); + // 下麦旁听 + IMNetEaseManager.get().downMicroPhoneBySdk(-1, new CallBack() { + @Override + public void onSuccess(String data) { + IMNetEaseManager.get().kickMicroPhoneBySdk(micUid, nick, tempRoomInfo.getRoomId()).subscribe(chatRoomMessage -> { + KickModel.get().onSendRoomMessageSuccess(chatRoomMessage); + } + , Throwable::printStackTrace); + + } + + @Override + public void onFail(int code, String error) { + + } + }); + } + + } + + } else { // 房主不在麦上 + RoomQueueInfo queueInfo = AvRoomDataManager.get().getRoomQueueMemberInfoByMicPosition(-1); + if (queueInfo == null || queueInfo.mChatRoomMember == null) { // 房主麦没人 + getMvpPresenter().leaveModeOpen(AvRoomDataManager.get().getRoomUid()); + + } else {// 房主麦有人 + // 下麦旁听 + MicMemberInfo tempChatRoomMember = queueInfo.mChatRoomMember; + long micUid = JavaUtil.str2long(tempChatRoomMember.getAccount()); + String nick = tempChatRoomMember.getNick(); + + IMNetEaseManager.get().downMicroPhoneBySdk(-1, new CallBack() { + @Override + public void onSuccess(String data) { + getDialogManager().dismissDialog(); + getMvpPresenter().leaveModeOpen(AvRoomDataManager.get().getRoomUid()); + + IMNetEaseManager.get().kickMicroPhoneBySdk(micUid, nick, tempRoomInfo.getRoomId()).subscribe(chatRoomMessage -> { + KickModel.get().onSendRoomMessageSuccess(chatRoomMessage); + } + , Throwable::printStackTrace); + } + + @Override + public void onFail(int code, String error) { + getDialogManager().dismissDialog(); + } + }); + } + + } + + } + + @SuppressWarnings("CheckResult") + @Override + public void leaveModeOpenSuccess() { + getDialogManager().dismissDialog(); + } + + @Override + public void leaveModeOpenFail(String msg) { + getDialogManager().dismissDialog(); + } + + @Override + public void leaveModeCloseSuccess() { + getDialogManager().dismissDialog(); + RoomInfo roomInfo1 = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo1 == null) + return; + + if (roomInfo1.isShowGiftValue()) + GiftValueModel.get().downMic(-1, String.valueOf(AuthModel.get().getCurrentUid())).subscribe(); + } + + @Override + public void leaveModeCloseFail(String msg) { + getDialogManager().dismissDialog(); + + } + + @SuppressWarnings("CheckResult") + public void sendRoomPureModeMsg(boolean isRoomPureMode) { + String contentText; + if (isRoomPureMode) { + contentText = ResUtil.getString(R.string.avroom_activity_roomsettingactivity_044); + } else { + contentText = ResUtil.getString(R.string.avroom_activity_roomsettingactivity_045); + } + RoomMessageViewNoticeInfo messageViewNoticeInfo = new RoomMessageViewNoticeInfo(); + messageViewNoticeInfo.setTips(contentText); + RoomNoticeAttachment attachment = new RoomNoticeAttachment(CustomAttachment.CUSTOM_MSG_UPDATE_ROOM_INFO, + CustomAttachment.CUSTOM_MSG_UPDATE_ROOM_INFO_NOTICE); + attachment.setRoomMessageViewNoticeInfo(messageViewNoticeInfo); + ChatRoomMessage screenMsg = ChatRoomMessageBuilder.createChatRoomCustomMessage( + String.valueOf(AvRoomDataManager.get().getRoomId()), + attachment + ); + IMNetEaseManager.get().sendChatRoomMessage(screenMsg, false) + .subscribe((message, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + } else { + IMNetEaseManager.get().addMessagesImmediately(message); + } + }); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onKickedOutEvent(KickOutEvent event) { + finish(); + } + + @Override + protected void onReceiveChatRoomEvent(RoomEvent roomEvent) { + super.onReceiveChatRoomEvent(roomEvent); + int event = roomEvent.getEvent(); + switch (event) { + case RoomEvent.KICK_OUT_ROOM: + finish(); + break; + case RoomEvent.ROOM_MANAGER_REMOVE: + if (AvRoomDataManager.get().isOwner(roomEvent.getAccount())) { + toast(R.string.remove_room_manager); + finish(); + } + break; + default: + } + } + + @Override + protected boolean needSteepStateBar() { + return true; + } + + @Override + protected void setStatusBar() { + StatusBarUtil.transparencyBar(this); + StatusBarUtil.StatusBarLightMode(this); + } + + private void setSelected(ImageView imageView, boolean isSelected) { + imageView.setSelected(isSelected); + imageView.setImageResource(isSelected ? + R.drawable.icon_room_set_lock_true : R.drawable.icon_room_set_lock_false); + } + + @SuppressLint("CheckResult") + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (resultCode == RESULT_OK) { + switch (requestCode) { + case PhotoPickActivity.PICK_ACT_RESULT: + if (data != null) { + Uri uri = data.getData(); + mUri = Uri.parse("file://" + FileHelper.getRootCacheDir().getPath() + "/" + System.nanoTime() + ".jpg"); + if (uri != null && mUri != null) { + boolean isCopy = MyUriUtils.INSTANCE.copyFileToUrl(this, uri, mUri); + if (isCopy) { + crop(mUri, 1, mUri); + } else { + ToastUtils.show(R.string.exception_try_again); + } + } + } + break; + + case UCrop.REQUEST_CROP: + if (mUri != null && mUri.getPath() != null) { + try { + if (mJob != null) { + mJob.cancel(null); + } + mJob = PhotoCompressUtil.compress( + this, + mUri.getPath(), + PhotoCompressUtil.getCompressCachePath("roomAvatar"), new PhotoCompressCallback() { + @Override + public void onSuccess(@NonNull String compressedImg) { + getDialogManager().showProgressDialog(RoomSettingActivity.this, ResUtil.getString(R.string.ui_user_userinfomodifyactivity_09)); + FileModel.get() + .uploadFile(compressedImg) + .compose(bindToLifecycle()) + .subscribe((url, throwable) -> { + if (throwable != null) { + onUploadFail(throwable); + } else { + onUpload(url); + } + }); + } + + @Override + public void onFail(@NonNull Throwable e) { + toast(e.getMessage()); + } + }); + mJob.start(); + } catch (Exception e) { + + } + } + break; + } + } + } + + /** + * 第三方图片裁剪框架Ucrop + */ + private void crop(Uri sourceUri, long sourceSize, Uri destinationUri) { + if (sourceUri == null || destinationUri == null) { + return; + } //防止too large导致oom,大于100m不处理,内存大小 + if (BitmapUtil.getSdBitmapSize(sourceUri) >= MAX_BITMAP_SIZE) { + toast(R.string.text_bitmap_too_large); + return; + } + + + UCrop.Options options = new UCrop.Options(); + options.setCompressionQuality(100); + options.setShowCropGrid(false); + options.setToolbarColor(ContextCompat.getColor(App.gContext, android.R.color.black)); + options.setStatusBarColor(ContextCompat.getColor(App.gContext, android.R.color.black)); + options.setHideBottomControls(true); + options.setCompressionFormat(Bitmap.CompressFormat.JPEG); + options.setToolbarCancelDrawable(R.drawable.user_ucrop_ic_closs); + options.setToolbarCropDrawable(R.drawable.user_ucrop_ic_sure); + options.setToolbarWidgetColor(ContextCompat.getColor(App.gContext, R.color.color_white)); + UCrop.of(sourceUri, destinationUri).withOptions(options).withAspectRatio(1f, 1f).withMaxResultSize(800, 800).start(this); + + } + + private void onUpload(String url) { + LogUtils.d(" 请求接口 更新房间封面 url = " + url); + save(null, url, null, null, false, roomInfo.isHasAnimationEffect()); + } + + private void onUploadFail(Throwable throwable) { + toast(ResUtil.getString(R.string.ui_user_userinfomodifyactivity_08) + ":" + throwable.getMessage()); + getDialogManager().dismissDialog(); + } + + +} diff --git a/app/src/main/java/com/chwl/app/avroom/activity/RoomTitleEditActivity.java b/app/src/main/java/com/chwl/app/avroom/activity/RoomTitleEditActivity.java new file mode 100644 index 0000000..a079cd0 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/activity/RoomTitleEditActivity.java @@ -0,0 +1,191 @@ +package com.chwl.app.avroom.activity; + +import android.app.Activity; +import android.content.Intent; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.View; + +import com.chwl.app.R; +import com.chwl.app.base.BaseBindingActivity; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.app.databinding.ActivityRoomTitleEditBinding; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.core.room.model.RoomSettingModel; +import com.chwl.library.annatation.ActLayoutRes; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; +import com.netease.nim.uikit.StatusBarUtil; + +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.disposables.Disposable; +import io.reactivex.functions.BiConsumer; + +@ActLayoutRes(R.layout.activity_room_title_edit) +public class RoomTitleEditActivity extends BaseBindingActivity implements BiConsumer { + public static final int ROOM_TITLE_EDIT_REQUEST_CODE = 9999; + public static final String ROOM_TITLE_EDIT_REQUEST_RESULT = "room_info"; + + private CompositeDisposable mDisposable; + private DialogManager mDialogManager; + + public static void startForResult(Activity context, String title, String desc) { + Intent intent = new Intent(context, RoomTitleEditActivity.class); + intent.putExtra("title", title); + intent.putExtra("desc", desc); + + context.startActivityForResult(intent, ROOM_TITLE_EDIT_REQUEST_CODE); + } + + private TextWatcher mTitleWatcher = new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + mBinding.tvTitleCount.setText(s.length() + "/15"); + } + }; + + private TextWatcher mDescWatcher = new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + mBinding.tvDescCount.setText(s.length() + "/300"); + } + }; + + @Override + protected void init() { + initWhiteTitleBar(getResources().getString(R.string.title_room_title_edit)); + mBinding.setClick(this); + mBinding.etTitle.addTextChangedListener(mTitleWatcher); + mBinding.etDesc.addTextChangedListener(mDescWatcher); + + Intent intent = getIntent(); + + String title = intent.getStringExtra("title"); + String desc = intent.getStringExtra("desc"); + mBinding.etTitle.setText(title); + mBinding.etDesc.setText(desc); + + mDisposable = new CompositeDisposable(); + mDialogManager = new DialogManager(this); + + mBinding.tvConfirm.setOnClickListener(this); + + } + + private void commit(String desc, String introduction) { + + if (TextUtils.isEmpty(desc)) { +// Toast.makeText(this, ResUtil.getString(R.string.avroom_activity_roomtitleeditactivity_01), Toast.LENGTH_SHORT).show(); + SingleToastUtil.showToastShort(ResUtil.getString(R.string.avroom_activity_roomtitleeditactivity_02)); + return; + } + + if (TextUtils.isEmpty(introduction)) { + introduction = ""; + } +// if (TextUtils.isEmpty(introduction)) { +// Toast.makeText(this, ResUtil.getString(R.string.avroom_activity_roomtitleeditactivity_03), Toast.LENGTH_SHORT).show(); +// return; +// } + + RoomInfo info = AvRoomDataManager.get().mCurrentRoomInfo; + if (info == null) return; + + RoomSettingModel roomSettingModel = new RoomSettingModel(); + long currentUid = AuthModel.get().getCurrentUid(); + String ticket = AuthModel.get().getTicket(); + if (AvRoomDataManager.get().isRoomOwner()) { + mDialogManager.showProgressDialog(this); + Disposable disposable = roomSettingModel.updateRoomInfo(info.title,null,desc, introduction, info.roomPwd, info.getRoomTag(), info.tagId, currentUid, + ticket, info.isHasAnimationEffect(), info.getAudioQuality(), info.getLimitType(),info.isPureMode(), info.getType(), + info.getMgId()) + .subscribe(this); + + mDisposable.add(disposable); + + } else if (AvRoomDataManager.get().isRoomAdmin()) { + mDialogManager.showProgressDialog(this); + Disposable disposable = roomSettingModel.updateByAdmin(info.getUid(), info.title,null, desc, introduction, info.roomPwd, info.getRoomTag(), info.tagId, currentUid, + ticket, info.isHasAnimationEffect(), info.getAudioQuality(),info.isPureMode()) + .subscribe((s, throwable) -> { + if (throwable != null) { + SingleToastUtil.showToastShort(ResUtil.getString(R.string.avroom_activity_roomtitleeditactivity_05)); + } else { + finish(); + } + }); + mDisposable.add(disposable); + } + + } + + @Override + public void onClick(View v) { + super.onClick(v); + switch (v.getId()) { + case R.id.tv_confirm: + commit(mBinding.etTitle.getText().toString().trim(), + mBinding.etDesc.getText().toString().trim()); + break; + } + + } + + @Override + public void accept(RoomInfo roomInfo, Throwable throwable) throws Exception { + mDialogManager.dismissDialog(); + + if (throwable != null) { +// Toast.makeText(this, ResUtil.getString(R.string.avroom_activity_roomtitleeditactivity_04), Toast.LENGTH_SHORT).show(); + SingleToastUtil.showToastShort(ResUtil.getString(R.string.avroom_activity_roomtitleeditactivity_05)); + } else { +// Intent intent = new Intent(); +// Bundle bundle = new Bundle(); +// bundle.putSerializable(ROOM_TITLE_EDIT_REQUEST_RESULT, roomInfo); +// intent.putExtras(bundle); +// setResult(RESULT_OK, intent); + finish(); + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + mDialogManager.dismissDialog(); + mDisposable.clear(); + } + + @Override + protected boolean needSteepStateBar() { + return true; + } + + @Override + protected void setStatusBar() { + StatusBarUtil.transparencyBar(this); + StatusBarUtil.StatusBarLightMode(this); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/activity/RoomTypeSwitchActivity.kt b/app/src/main/java/com/chwl/app/avroom/activity/RoomTypeSwitchActivity.kt new file mode 100644 index 0000000..1cbb6b0 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/activity/RoomTypeSwitchActivity.kt @@ -0,0 +1,396 @@ +package com.chwl.app.avroom.activity + +import android.content.Context +import android.content.Intent +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.bindadapter.BaseBindingAdapter +import com.chwl.app.bindadapter.BaseBindingViewHolder +import com.chwl.app.databinding.ItemRoomModeBinding +import com.chwl.app.databinding.RoomTypeSwitchActivityBinding +import com.chwl.app.home.helper.OpenRoomHelper +import com.chwl.app.ui.utils.load +import com.chwl.app.ui.utils.loadFromUrl +import com.chwl.app.ui.webview.CommonWebViewActivity +import com.chwl.app.utils.NumberUtils +import com.chwl.core.UriProvider +import com.chwl.core.bean.response.ServiceResult +import com.chwl.core.gift.bean.RoomLevelInfo +import com.chwl.core.gift.bean.RoomMicDress +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.room.bean.RoomInfo +import com.chwl.core.super_admin.util.SuperAdminUtil +import com.chwl.core.utils.net.RxHelper +import com.chwl.library.common.util.ClickUtils.click +import com.chwl.library.common.util.doToast +import com.chwl.library.common.util.isVerify +import com.chwl.library.common.util.setVis +import com.chwl.library.common.util.toColor +import com.chwl.library.net.rxnet.RxNet +import com.chwl.library.utils.ResUtil +import com.chwl.library.utils.SingleToastUtil +import com.example.lib_utils.ktx.getString +import io.reactivex.Single +import retrofit2.http.GET +import retrofit2.http.Query + + +//切换麦位页面 +class RoomTypeSwitchActivity : BaseViewBindingActivity() { + + + companion object { + fun isCanSwitch(): Boolean { + if (SuperAdminUtil.isSuperAdmin()) { + return false + } + + if (AvRoomDataManager.get().roomType != RoomInfo.ROOMTYPE_HOME_PARTY + && AvRoomDataManager.get().roomType != RoomInfo.ROOMTYPE_PARTY + && AvRoomDataManager.get().roomType != RoomInfo.ROOMTYPE_REVELRY + && AvRoomDataManager.get().roomType != RoomInfo.ROOMTYPE_19_ROOM + && AvRoomDataManager.get().roomType != RoomInfo.ROOMTYPE_20_ROOM + ) { + return false + } + + if (AvRoomDataManager.get().isDatingMode) { + return false + } + + val roomInfo = AvRoomDataManager.get().mCurrentRoomInfo + if (roomInfo == null || roomInfo.isPermitRoom == 1) { + return false + } + + return AvRoomDataManager.get().isManager + } + + fun start(context: Context) { + context.startActivity(Intent(context, RoomTypeSwitchActivity::class.java)) + } + } + + + private var mCurrentMicType: Int? = null + private var mCurrentMicSkins: Int? = null + private var mCurrentMicEffects: Int? = null + private var mCurrentLevel = 0 + + private val mMicTypeAdapter = RoomModeAdapter() + private val mMicSkinsAdapter = RoomModeAdapter() + private val mMicEffectsAdapter = RoomModeAdapter() + + + private var mTypeSet = true + private var micSkinsEffectsSet = true + + override fun init() { + + initView() + initListener() + initData() + + } + + private fun initView() { + initDarkTitleBar(R.string.Room_Mode.getString()) + + setListView(binding.rvListType, mMicTypeAdapter) + setListView(binding.rvListSkins, mMicSkinsAdapter) + setListView(binding.rvListEffects, mMicEffectsAdapter) + + } + + + private fun initListener() { + + binding.btnConfirm.click { + switchRoomMicType() + } + + binding.btnMore.click { + CommonWebViewActivity.start(this, UriProvider.getRoomLevelRule()) + } + + } + + private fun initData() { + val mCurrentRoomInfo = AvRoomDataManager.get().mCurrentRoomInfo + mCurrentMicType = mCurrentRoomInfo?.type + + getBoomLevelInfo(AvRoomDataManager.get().roomUid).compose(bindToLifecycle()) + .doOnSuccess { + + if (it != null) { + + val levelExp = it.nextLevelExp - it.currentLevelExp + val proExp = it.roomVal - it.currentLevelExp + val nexExp = levelExp - proExp + + binding.proExp.max = levelExp.toInt() + binding.proExp.progress = proExp.toInt() + + + binding.avatar.load(mCurrentRoomInfo?.avatar) + binding.nick.text = mCurrentRoomInfo?.title + binding.levelIcon.load(it.getCurrentLevelIcon()) + binding.roomValue.text = R.string.Room_Value_s.getString(it.roomVal.toLong().toString()) + binding.roomAdmin.text = R.string.Room_Admin_s.getString(it.currentManagerNum,it.managerLimitNum) + binding.currentLevel.text = R.string.LV_s.getString(it.currentLevel) + binding.nextLevel.text = R.string.LV_s.getString(it.nextLevel) + binding.nextExp.text = R.string.Next_LV_EXP_s.getString(NumberUtils.format(nexExp)) + + if (it.nextLevel == 0) { + binding.nextExp.setVis(false,true) + binding.proExp.max = 1 + binding.proExp.progress = 1 + binding.nextLevel.text = R.string.LV_s.getString(it.currentLevel) + binding.currentLevel.text = R.string.LV_s.getString(it.currentLevel-1) + } + + + mCurrentMicSkins = it.usedMicSkinId + mCurrentMicEffects = it.usedMicEffectId + mCurrentLevel = it.currentLevel + + val typeArr = mutableListOf( + RoomInfo.ROOMTYPE_HOME_PARTY, + RoomInfo.ROOMTYPE_PARTY, + RoomInfo.ROOMTYPE_REVELRY, + RoomInfo.ROOMTYPE_20_ROOM, + RoomInfo.ROOMTYPE_19_ROOM, + ) + val typeNArr = arrayOf( + R.drawable.ic_room_mic_type_9_n, + R.drawable.ic_room_mic_type_10_n, + R.drawable.ic_room_mic_type_15_n, + R.drawable.ic_room_mic_type_20_n, + R.drawable.ic_room_mic_type_19_n, + ) + val typeSArr = arrayOf( + R.drawable.ic_room_mic_type_9_s, + R.drawable.ic_room_mic_type_10_s, + R.drawable.ic_room_mic_type_15_s, + R.drawable.ic_room_mic_type_20_s, + R.drawable.ic_room_mic_type_19_s, + ) + val nameArr = arrayOf( + R.string.Classic, + R.string.Party, + R.string.Carnival, + R.string.Celebration, + R.string.Unique, + ) + + + if (!it.isHasUnique) { + typeArr.remove(RoomInfo.ROOMTYPE_19_ROOM) + typeArr.remove(RoomInfo.ROOMTYPE_20_ROOM) + } + + val typeData = mutableListOf() + typeArr.filterIndexed { index, micType -> + typeData.add(RoomMicDress().apply { + id = micType + dressType = RoomMicDress.RoomDressType.T_Type + isSelect = micType == mCurrentMicType + normalRes = typeNArr[index] + selectRes = typeSArr[index] + name = nameArr[index].getString() + }) + } + mMicTypeAdapter.setNewData(typeData as List?) + + if (it.getMicSkins().isVerify()) { + val micSkins = it.getMicSkins() + micSkins.add(0, RoomMicDress().apply { + id = 0 + normalRes = R.drawable.icon_room_up_micro + }) + micSkins.forEach { it.isSelect = (it.id == mCurrentMicSkins) } + mMicSkinsAdapter.setNewData(micSkins) + } + + if (it.getMicEffects().isVerify()) { + val micEffects = it.getMicEffects() + micEffects.add(0, RoomMicDress().apply { + id = 0 + normalRes = R.drawable.shape_463a26_circle + }) + micEffects.forEach { it.isSelect = (it.id == mCurrentMicEffects) } + mMicEffectsAdapter.setNewData(it.getMicEffects()) + } + + } + }.doOnError { it?.message?.doToast() }.subscribe() + + + } + + private fun setListView(rvList: RecyclerView, adapter: RoomModeAdapter) { + adapter.setOnItemClickListener { adapter, view, position -> + + val clickData = adapter?.data?.get(position) + if (clickData != null && clickData is RoomMicDress){ + if (mCurrentLevel < clickData.reachLevel) { + R.string.roomLevelErrorTips.doToast() + return@setOnItemClickListener + } + } + + + adapter?.data?.forEachIndexed { index, feData -> + if (feData is RoomMicDress) { + feData.isSelect = index == position + } + } + adapter?.notifyDataSetChanged() + } + + rvList.layoutManager = GridLayoutManager(context, 3, RecyclerView.VERTICAL, false) + rvList.adapter = adapter + } + + + private fun switchRoomMicType() { + var typeId = -1 + var skinsId = -1 + var effectId = -1 + var isLevelError = false + + mMicTypeAdapter.data?.forEach { + if (it.isSelect) { + typeId = it.id + } + } + + mMicSkinsAdapter.data?.forEach { + if (it.isSelect) { + if (it.id > 0) { + skinsId = it.id + } + if (mCurrentLevel < it.reachLevel) { + isLevelError = true + } + } + } + + mMicEffectsAdapter.data?.forEach { + if (it.isSelect) { + if (it.id > 0) { + effectId = it.id + } + if (mCurrentLevel < it.reachLevel) { + isLevelError = true + } + } + } + + if (isLevelError) { + R.string.roomLevelErrorTips.doToast() + } else { + + if ((typeId != -1 && typeId != mCurrentMicType) || (effectId != mCurrentMicEffects) || (skinsId != mCurrentMicSkins)) { + dialogManager.showOkCancelDialog( + ResUtil.getString(R.string.switch_room_type_tips), + ResUtil.getString(R.string.login_fragment_adduserinfofragment_04) + ) { + + binding.btnConfirm.post { + mTypeSet = false + dialogManager.showProgressDialog(context) + + val newRoomInfo = RoomInfo() + newRoomInfo.uid = AvRoomDataManager.get().roomUid + newRoomInfo.type = typeId + newRoomInfo.usedMicSkinId = skinsId + newRoomInfo.usedMicEffectId = effectId + + OpenRoomHelper.updateRoomInfoEx(newRoomInfo) + .compose(bindToLifecycle()) + .doOnSuccess { + mTypeSet = true + dialogManager.dismissDialog() +// val mCurrentRoomInfo = AvRoomDataManager.get().mCurrentRoomInfo +// mCurrentRoomInfo?.type = typeId +// mCurrentRoomInfo?.usedMicSkinId = skinsId +// mCurrentRoomInfo?.usedMicEffectId = effectId + finish() + } + .doOnError { + SingleToastUtil.showToast(it.message) + dialogManager.dismissDialog() + } + .subscribe() + } + } + } else { + finish() + } + + } + + + } + + override fun needSteepStateBar(): Boolean { + return true + } + + override fun transparencyBar() = true + + class RoomModeAdapter : BaseBindingAdapter() { + override fun convert( + helper: BaseBindingViewHolder, + item: RoomMicDress + ) { + helper?.binding?.let { binding -> + binding.bg.changeStrikeColor(if (item.isSelect) "#ff8c03".toColor() else "#1b1b1d".toColor()) + binding.bg.changeSoildColor(if (item.isSelect) "#261800".toColor() else "#1b1b1d".toColor()) + binding.tvName.alpha = (if (item.isSelect) 1f else 0.5f) + binding.tvName.setVis(item.dressType == RoomMicDress.RoomDressType.T_Type) + binding.tvName.text = item.name + + binding.ivType.setVis(false) + binding.ivSkins.setVis(false) + binding.ivEffect.setVis(false) + + if (item.id == 0) { + binding.ivSkins.setImageResource(item.normalRes) + binding.ivSkins.setVis(true) + } else { + if (item.dressType == RoomMicDress.RoomDressType.T_Type) { + binding.ivType.setImageResource(if (item.isSelect) item.selectRes else item.normalRes) + binding.ivType.setVis(true) + } else if (item.dressType == RoomMicDress.RoomDressType.T_Skin) { + binding.ivSkins.load(item.normalMicUrl) + binding.ivSkins.setVis(true) + } else if (item.dressType == RoomMicDress.RoomDressType.T_Effects) { + binding.ivEffect.setVis(true) + binding.ivEffect.loadFromUrl(item.normalMicUrl) + } + } + } + } + } + + private fun getBoomLevelInfo(roomUid: Long): Single { + return api.getBoomLevelInfo(roomUid) + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()) + } + + private val api: Api = RxNet.create(Api::class.java); + + interface Api { + //房间 等级信息 + @GET("/room/level/info") + fun getBoomLevelInfo(@Query("roomUid") roomUid: Long): Single> + + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/AuctionListAdapter.java b/app/src/main/java/com/chwl/app/avroom/adapter/AuctionListAdapter.java new file mode 100644 index 0000000..c375b78 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/AuctionListAdapter.java @@ -0,0 +1,36 @@ +package com.chwl.app.avroom.adapter; + +import com.chwl.library.list.ArrayListAdapter; +import com.chwl.library.list.ListItem; + +import java.util.List; + +/** + * Created by chenran on 2017/8/9. + */ + +public class AuctionListAdapter extends ArrayListAdapter{ + public static final int VIEW_TYPE_COUNT = 5;//列表有4种类型 + + public static final int VIEW_TYPE_WEEK_ITEM = 0;//周榜 + public static final int VIEW_TYPE_TOTAL_ITEM = 1;//总榜 + public static final int VIEW_TYPE_EMPTY = 2;//空内容 + public static final int VIEW_TYPE_WEEK_HEADER = 3;//周榜header + public static final int VIEW_TYPE_TOTAL_HEADER = 4;//总榜header + + + private List items = getItems(); + + public void clear(int except) { + if (except >= 0 && except < items.size()) { + ListItem item = items.get(except); + items.clear(); + items.add(item); + } + } + + @Override + public int getViewTypeCount() { + return VIEW_TYPE_COUNT; + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/AuctionListEmptyItem.java b/app/src/main/java/com/chwl/app/avroom/adapter/AuctionListEmptyItem.java new file mode 100644 index 0000000..a3fbebd --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/AuctionListEmptyItem.java @@ -0,0 +1,42 @@ +package com.chwl.app.avroom.adapter; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.chwl.app.R; +import com.chwl.library.list.BaseGroupItem; +import com.chwl.library.list.ViewHolder; + +/** + * Created by chenran on 2017/8/9. + */ + +public class AuctionListEmptyItem extends BaseGroupItem{ + + public AuctionListEmptyItem(Context context, int viewType) { + super(context, viewType); + } + + @Override + public ViewHolder createViewHolder(ViewGroup group) { + View view = LayoutInflater.from(getContext()).inflate(R.layout.list_item_auction_empty, null); + AuctionListEmptyItem.AuctionListEmptyHolder holder = new AuctionListEmptyItem.AuctionListEmptyHolder(view); + return holder; + } + + @Override + public void updateHolder(ViewHolder holder, int groupPos, int childPos) { + + } + + private static class AuctionListEmptyHolder extends ViewHolder { + private TextView textView; + public AuctionListEmptyHolder(View itemView) { + super(itemView); + + } + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/AuctionListHeaderItem.java b/app/src/main/java/com/chwl/app/avroom/adapter/AuctionListHeaderItem.java new file mode 100644 index 0000000..3ed048e --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/AuctionListHeaderItem.java @@ -0,0 +1,48 @@ +package com.chwl.app.avroom.adapter; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; + +import com.chwl.app.R; +import com.chwl.library.list.BaseGroupItem; +import com.chwl.library.list.ViewHolder; + +/** + * Created by chenran on 2017/8/9. + */ + +public class AuctionListHeaderItem extends BaseGroupItem{ + public AuctionListHeaderItem(Context context, int viewType) { + super(context, viewType); + } + + @Override + public ViewHolder createViewHolder(ViewGroup group) { + View view = LayoutInflater.from(getContext()).inflate(R.layout.list_item_auction_header, null); + AuctionListHeaderItem.AuctionListHeaderHolder holder = new AuctionListHeaderItem.AuctionListHeaderHolder(view); + return holder; + } + + @Override + public void updateHolder(ViewHolder holder, int groupPos, int childPos) { + AuctionListHeaderItem.AuctionListHeaderHolder auctionListHolder = (AuctionListHeaderItem.AuctionListHeaderHolder) holder; + if (auctionListHolder != null) { + if (getViewType() == AuctionListAdapter.VIEW_TYPE_WEEK_HEADER) { + auctionListHolder.image.setImageResource(R.drawable.icon_week_auction_list); + } else { + auctionListHolder.image.setImageResource(R.drawable.icon_total_auction_list); + } + } + } + + private static class AuctionListHeaderHolder extends ViewHolder { + private ImageView image; + public AuctionListHeaderHolder(View itemView) { + super(itemView); + image = (ImageView) itemView.findViewById(R.id.auction_list_header); + } + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/AuctionListItem.java b/app/src/main/java/com/chwl/app/avroom/adapter/AuctionListItem.java new file mode 100644 index 0000000..9b809ed --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/AuctionListItem.java @@ -0,0 +1,123 @@ +package com.chwl.app.avroom.adapter; + +import android.content.Context; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.chwl.app.R; +import com.chwl.app.common.widget.CircleImageView; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.room.auction.bean.AuctionListUserInfo; +import com.chwl.library.list.BaseGroupItem; +import com.chwl.library.list.ViewHolder; + +/** + * Created by chenran on 2017/8/9. + */ + +public class AuctionListItem extends BaseGroupItem implements View.OnClickListener{ + private AuctionListUserInfo auctionListUserInfo; + private OnAuctionListItemClick onAuctionListItemClick; + private int position; + + public AuctionListItem(Context context, int viewType, AuctionListUserInfo auctionListUserInfo, int position) { + super(context, viewType); + this.auctionListUserInfo = auctionListUserInfo; + this.position = position; + } + + public void setOnAuctionListItemClick(OnAuctionListItemClick onAuctionListItemClick) { + this.onAuctionListItemClick = onAuctionListItemClick; + } + + @Override + public ViewHolder createViewHolder(ViewGroup group) { + View view = LayoutInflater.from(getContext()).inflate(R.layout.list_item_auction_list, null); + AuctionListHolder holder = new AuctionListHolder(view); + return holder; + } + + @Override + public void updateHolder(ViewHolder holder, int groupPos, int childPos) { + AuctionListHolder auctionListHolder = (AuctionListHolder) holder; + if (auctionListHolder != null) { + auctionListHolder.nick.setText(auctionListUserInfo.getNick()); + auctionListHolder.coinText.setText(auctionListUserInfo.getPrice() + ""); + auctionListHolder.avatar.setOnClickListener(this); + ImageLoadUtils.loadAvatar(getContext(), auctionListUserInfo.getAvatar(), auctionListHolder.avatar); + Drawable drawable; + if (auctionListUserInfo.getGender() == 1) { + Drawable drawMan = getContext().getResources().getDrawable(R.drawable.ic_gender_male); + drawable = drawMan; + } else { + Drawable drawFemale = getContext().getResources().getDrawable(R.drawable.ic_gender_female); + drawable = drawFemale; + } + auctionListHolder.nick.setCompoundDrawablesWithIntrinsicBounds(null, null, drawable, null); + + if (getViewType() == AuctionListAdapter.VIEW_TYPE_WEEK_ITEM) { + if (position <= 2) { + auctionListHolder.numberText.setVisibility(View.GONE); + auctionListHolder.numberImage.setVisibility(View.VISIBLE); + if (position == 0) { + auctionListHolder.numberImage.setImageResource(R.drawable.icon_auction_week_list_first); + } else if (position == 1) { + auctionListHolder.numberImage.setImageResource(R.drawable.icon_auction_week_list_second); + } else { + auctionListHolder.numberImage.setImageResource(R.drawable.icon_auction_week_list_third); + } + } else { + auctionListHolder.numberText.setVisibility(View.VISIBLE); + auctionListHolder.numberImage.setVisibility(View.GONE); + auctionListHolder.numberText.setText("NO."+(position+1)); + } + } else { + auctionListHolder.numberText.setVisibility(View.VISIBLE); + auctionListHolder.numberImage.setVisibility(View.GONE); + auctionListHolder.numberText.setText("NO."+(position + 1)); + if (position <= 2) { + auctionListHolder.numberText.setTextColor(0xffeecb7f); + } else { + auctionListHolder.numberText.setTextColor(Color.WHITE); + } + } + } + } + + @Override + public boolean isEnabled() { + return false; + } + + @Override + public void onClick(View v) { + if(onAuctionListItemClick != null) { + onAuctionListItemClick.onAuctionListItemClick(auctionListUserInfo); + } + } + + private static class AuctionListHolder extends ViewHolder { + private ImageView numberImage; + private TextView numberText; + private TextView nick; + private TextView coinText; + private CircleImageView avatar; + public AuctionListHolder(View itemView) { + super(itemView); + numberImage = (ImageView) itemView.findViewById(R.id.auction_number_image); + numberText = (TextView) itemView.findViewById(R.id.auction_number_text); + nick = (TextView) itemView.findViewById(R.id.nick); + avatar = (CircleImageView) itemView.findViewById(R.id.avatar); + coinText = (TextView) itemView.findViewById(R.id.coin_text); + } + } + + public interface OnAuctionListItemClick { + void onAuctionListItemClick(AuctionListUserInfo auctionListUserInfo); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/BaseMicroViewAdapter.java b/app/src/main/java/com/chwl/app/avroom/adapter/BaseMicroViewAdapter.java new file mode 100644 index 0000000..501acd7 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/BaseMicroViewAdapter.java @@ -0,0 +1,691 @@ +package com.chwl.app.avroom.adapter; + +import android.content.Context; +import android.graphics.Color; +import android.graphics.drawable.BitmapDrawable; +import android.text.TextUtils; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.PopupWindow; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.lifecycle.Observer; +import androidx.recyclerview.widget.RecyclerView; + +import com.chwl.app.R; +import com.chwl.app.avroom.activity.AVRoomActivity; +import com.chwl.app.avroom.widget.BravoCoinView; +import com.chwl.app.common.widget.CircleImageView; +import com.chwl.app.ui.utils.ImageLoadKt; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.app.ui.webview.DialogWebViewActivity; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.utils.AvatarHelper; +import com.chwl.app.utils.RegexUtil; +import com.chwl.app.utils.ResourceManager; +import com.chwl.core.UriProvider; +import com.chwl.core.bean.RoomMicInfo; +import com.chwl.core.bean.RoomQueueInfo; +import com.chwl.core.decoration.headwear.bean.HeadWearInfo; +import com.chwl.core.gift.bean.RoomMicDress; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.noble.NobleResourceType; +import com.chwl.core.noble.NobleUtil; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.core.room.giftvalue.bean.GiftValueData; +import com.chwl.core.room.giftvalue.helper.GiftValueFormat; +import com.chwl.core.room.pk.bean.PKTeamInfo; +import com.chwl.core.room.queue.bean.MicMemberInfo; +import com.chwl.core.user.UserModel; +import com.chwl.core.utils.ActivityUtil; +import com.chwl.core.utils.extension.StringExtensionKt; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.config.BasicConfig; +import com.chwl.library.widget.SVGAView; +import com.coorchice.library.SuperTextView; +import com.example.lib_utils.StringUtils2; +import com.netease.nim.uikit.common.util.string.StringUtil; +import com.opensource.svgaplayer.SVGAImageView; + +/** + * @author xiaoyu + * @date 2017/12/18 + */ +public abstract class BaseMicroViewAdapter extends RecyclerView.Adapter { + // 麦位类型;用于左右滑动切换房间时判断是否需要更换麦位adapter + public static final String MICRO_TYPE_NULL = "null"; + public static final String MICRO_TYPE_CP = "cp"; + public static final String MICRO_TYPE_KTV = "ktv"; + public static final String MICRO_TYPE_NORMAL = "normal"; + public static final String MICRO_TYPE_DATING = "dating"; + public static final String MICRO_TYPE_DATING_VIP = "dating_vip"; + public static final String MICRO_TYPE_SINGLE = "single"; + public static final String MICRO_TYPE_PARTY = "party"; + public static final String MICRO_TYPE_REVELRY = "revelry"; + public static final String MICRO_TYPE_REVELRY_19 = "revelry_19"; + public static final String MICRO_TYPE_REVELRY_20 = "revelry_20"; + + protected static final int TYPE_KING = 2; + protected static final int TYPE_BOSS = 1; + protected static final int TYPE_NORMAL = 0; + protected static final int TYPE_INVALID = -2; + protected OnMicroItemClickListener onMicroItemClickListener = null; + protected Context context; + + public BaseMicroViewAdapter(Context context) { + this.context = context; + setHasStableIds(true); + } + + public void setOnMicroItemClickListener(OnMicroItemClickListener onMicroItemClickListener) { + this.onMicroItemClickListener = onMicroItemClickListener; + } + + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, final int position) { + RoomQueueInfo roomQueueInfo = AvRoomDataManager.get().getRoomQueueMemberInfoByMicPosition(position - 1); + if (roomQueueInfo == null) return; + NormalMicroViewHolder holder = (NormalMicroViewHolder) viewHolder; + holder.micPositionNameOffset = getMicPositionNameOffset(); + holder.bind(roomQueueInfo, position - 1); + } + + public abstract String microType(); + + protected int getMicPositionNameOffset() { + return 2; + } + + @Override + public int getItemCount() { + return 9; + } + + @Override + public int getItemViewType(int position) { + return (position == 0) ? TYPE_BOSS : TYPE_NORMAL; + } + + @Override + public long getItemId(int position) { + return position; + } + + public void clear(NormalMicroViewHolder holder) { + holder.clear(); + } + + public abstract void bindToRecyclerView(RecyclerView recyclerView); + + @Override + public void onDetachedFromRecyclerView(RecyclerView recyclerView) { + onMicroItemClickListener = null; + super.onDetachedFromRecyclerView(recyclerView); + } + + public void setBossViewGender(TextView tvNick, boolean isMale) { + + tvNick.setCompoundDrawablePadding(4); + tvNick.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); + +// if (AvRoomDataManager.get().isOpenPKMode()) { // pk模式不加性别背景 +// tvNick.setCompoundDrawablePadding(4); +// tvNick.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); +// } else { +// if (isMale) { +// tvNick.setCompoundDrawablePadding(4); +// tvNick.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_gender_male, 0); +// } else { +// tvNick.setCompoundDrawablePadding(4); +// tvNick.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_gender_female, 0); +// } +// } + } + + public class NormalMicroViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { + View rootView; + + LinearLayout llNick; + View microLayout; + TextView tvNick; + ImageView ivUpImage; + ImageView ivLockImage; + ImageView ivMuteImage; + ImageView ivAvatar; + SVGAImageView ivHalo; + + @Nullable + SVGAView ivHeadWear; + @Nullable + ImageView ivCharmLevelTag; + + @Nullable + ImageView ivKickGuard; + + BravoCoinView coinAnim; + + + RoomQueueInfo info; + int position = TYPE_INVALID; + int micPositionNameOffset = 2; + + int micType = 0; //特殊麦位type , 麦位图片特殊处理 + + NormalMicroViewHolder(View itemView) { + super(itemView); + rootView = itemView.findViewById(R.id.rootView); + microLayout = itemView.findViewById(R.id.micro_layout); + ivHalo = itemView.findViewById(R.id.iv_halo); + ivUpImage = itemView.findViewById(R.id.up_image); + ivLockImage = itemView.findViewById(R.id.lock_image); + ivMuteImage = itemView.findViewById(R.id.mute_image); + ivAvatar = itemView.findViewById(R.id.avatar); + ivHeadWear = itemView.findViewById(R.id.iv_head_wear); + tvNick = itemView.findViewById(R.id.nick); + llNick = itemView.findViewById(R.id.ll_nick); + ivCharmLevelTag = itemView.findViewById(R.id.iv_charm_level_tag); + ivKickGuard = itemView.findViewById(R.id.iv_kick_guard); + coinAnim = itemView.findViewById(R.id.coinAnim); + + ivUpImage.setOnClickListener(this); + ivLockImage.setOnClickListener(this); + ivAvatar.setOnClickListener(this); + if (ivHeadWear != null) { + ivHeadWear.bindCache(AVRoomActivity.getSvgaCache()); + } + } + + public void clear() { + info = null; + position = TYPE_INVALID; + ivHalo.setBackground(null); + ivHalo.clearAnimation(); + ivHalo.clear(); + clearHeadWear(); + ivUpImage.setVisibility(View.VISIBLE); + ivLockImage.setVisibility(View.GONE); + ivMuteImage.setVisibility(View.GONE); + ivAvatar.setVisibility(View.GONE); + if (coinAnim != null) { + coinAnim.setVisibility(View.GONE); + } + tvNick.setVisibility(View.INVISIBLE); + if (ivCharmLevelTag != null) { + ivCharmLevelTag.setVisibility(View.GONE); + } + } + + void bind(@NonNull RoomQueueInfo info, int position) { + this.info = info; + this.position = position; + RoomMicInfo roomMicInfo = info.mRoomMicInfo; + MicMemberInfo chatRoomMember = info.mChatRoomMember; + if (ivCharmLevelTag != null) { + ivCharmLevelTag.setVisibility(View.GONE); + } + + if (micType == 0) { + // 麦位皮肤 + // ivUpImage = up_image = icon_room_up_micro - 可上麦 + // ivLockImage = lock_image = icon_room_lock_micro - 锁麦 + RoomMicDress roomMicSkins = ResourceManager.INSTANCE.getRoomMicSkins(); + if (roomMicSkins != null) { + ImageLoadKt.loadImage(ivUpImage,roomMicSkins.normalMicUrl); + ImageLoadKt.loadImage(ivLockImage,roomMicSkins.normalMicLockUrl); + }else { + ivUpImage.setImageResource(R.drawable.icon_room_up_micro); + ivLockImage.setImageResource(R.drawable.icon_room_lock_micro); + } + } + + if (roomMicInfo == null) { + ivUpImage.setVisibility(View.VISIBLE); + ivLockImage.setVisibility(View.GONE); + ivMuteImage.setVisibility(View.GONE); + ivAvatar.setVisibility(View.GONE); + if (ivCharmLevelTag != null) { + ivCharmLevelTag.setVisibility(View.GONE); + } + if (ivKickGuard != null) { + ivKickGuard.setVisibility(View.GONE); + } + setDefalutText(position); + return; + } + + //显示,先展示人,无视坑的锁 + if (chatRoomMember != null) { + ivLockImage.setVisibility(View.GONE); + ivMuteImage.setVisibility(roomMicInfo.isMicMute() ? View.VISIBLE : View.GONE); + + if (!TextUtils.isEmpty(chatRoomMember.getAccount()) && Long.valueOf(chatRoomMember.getAccount()) > 0) { + ivUpImage.setVisibility(View.GONE); + ivAvatar.setVisibility(View.VISIBLE); + setSelectText(position, chatRoomMember.getNick(), chatRoomMember.getGender()); + ImageLoadUtils.loadAvatar(chatRoomMember.getAvatar(), ivAvatar); + // 加载贵族 + updateNobleView(chatRoomMember); + //增加贵族昵称颜色 + tvNick.setTextColor(StringExtensionKt.toColorInt(chatRoomMember.getMicNickColor(), "#FFFFFF")); + if (ivKickGuard != null) { + ivKickGuard.setVisibility(chatRoomMember.isPreventKick() ? View.VISIBLE : View.GONE); + } + if (coinAnim != null) { + coinAnim.setData(chatRoomMember.getAccount()); + } + } else { + clearHeadWear(); + ivUpImage.setVisibility(View.VISIBLE); + ivAvatar.setVisibility(View.GONE); + if (ivCharmLevelTag != null) { + ivCharmLevelTag.setVisibility(View.GONE); + } + if (ivKickGuard != null) { + ivKickGuard.setVisibility(View.GONE); + } + setDefalutText(position); + if (coinAnim != null) { + coinAnim.setData(null); + } + + } + } else { + // 清除动画 + ivHalo.setBackground(null); + ivHalo.clearAnimation(); + ivHalo.clear(); + // 清除头饰 + clearHeadWear(); + //锁坑 + ivMuteImage.setVisibility(roomMicInfo.isMicMute() ? View.VISIBLE : View.GONE); + if (roomMicInfo.isMicLock()) { + ivUpImage.setVisibility(View.GONE); + ivLockImage.setVisibility(View.VISIBLE); + ivAvatar.setVisibility(View.GONE); + } else { + ivUpImage.setVisibility(View.VISIBLE); + ivAvatar.setVisibility(View.GONE); + ivLockImage.setVisibility(View.GONE); + } + if (ivCharmLevelTag != null) { + ivCharmLevelTag.setVisibility(View.GONE); + } + if (ivKickGuard != null) { + ivKickGuard.setVisibility(View.GONE); + } + setDefalutText(position); + if (coinAnim != null) { + coinAnim.setData(null); + } + + } + + + } + + private void clearHeadWear() { + if (ivHeadWear == null) return; + ivHeadWear.clearAnimation(); + ivHeadWear.stopAnimation(); + ivHeadWear.setImageDrawable(null); + ivHeadWear.setTag(R.id.mic_item_head_wear, null); + ivHeadWear.setVisibility(View.GONE); + } + + protected void setDefalutText(int index) { + tvNick.setTextColor(Color.WHITE); + tvNick.setText(getMicPositionName(index)); + } + + protected String getMicPositionName(int index) { + return "NO." + (index + micPositionNameOffset); + } + + protected void setSelectText(int index, String nick, int gender) { + tvNick.setText(StringExtensionKt.subAndReplaceDot(StringUtil.removeBlanks(nick), 7)); + tvNick.setTextColor(context.getResources().getColor(R.color.white)); + } + + //优先使用MicMemberInfo里面的头饰 + private void updateNobleView(MicMemberInfo chatRoomMember) { + if (ivHeadWear == null) return; + String headWear = chatRoomMember.getHeadWearUrl(); + int headWearType = chatRoomMember.getHeadWearType(); + if (TextUtils.isEmpty(headWear)) { + headWear = NobleUtil.getHeadResource(HeadWearInfo.EFFECT, chatRoomMember) != null ? + NobleUtil.getHeadResource(HeadWearInfo.EFFECT, chatRoomMember) : + NobleUtil.getHeadResource(HeadWearInfo.PIC, chatRoomMember); + String type = NobleUtil.getHeadResource(HeadWearInfo.TYPE, chatRoomMember); + headWearType = StringUtils2.INSTANCE.toInt(type); + } + String nobleHeadWear = (String) NobleUtil.getResource(NobleResourceType.KEY_HEAD_WEAR, chatRoomMember); + if (!TextUtils.isEmpty(headWear)) { + ivHeadWear.setVisibility(View.VISIBLE); + //只有头饰发生改变才更新,防止闪烁 + if (!headWear.equals(ivHeadWear.getTag(R.id.mic_item_head_wear))) { + ivHeadWear.setTag(R.id.mic_item_head_wear, headWear); + AvatarHelper.loadAvatarFrame(ivHeadWear, headWear, headWearType); + } + } else if (!TextUtils.isEmpty(nobleHeadWear)) { + // 头饰 + ivHeadWear.setVisibility(View.VISIBLE); + NobleUtil.loadResource(nobleHeadWear, ivHeadWear); + } else { + clearHeadWear(); + } + } + + @Override + public void onClick(View v) { + if (info == null || position == TYPE_INVALID || + onMicroItemClickListener == null) return; + if (v.getId() == R.id.up_image || v.getId() == R.id.lock_image) { + onMicroItemClickListener.onUpMicBtnClick(position, info.mChatRoomMember); + } else if (v.getId() == R.id.lock_image) { + onMicroItemClickListener.onLockBtnClick(position); + } else if (v.getId() == R.id.avatar) { + onMicroItemClickListener.onAvatarBtnClick(position); + } else if (v.getId() == R.id.tv_room_desc || v.getId() == R.id.fr_title) { + onMicroItemClickListener.onRoomSettingsClick(); + } + } + } + + public class BasicMicroViewHolder extends NormalMicroViewHolder { + + TextView tvPkMark; + + public BasicMicroViewHolder(View itemView) { + super(itemView); + tvPkMark = (TextView) itemView.findViewById(R.id.tv_pk_mark); + } + + @Override + public void clear() { + super.clear(); + if (tvPkMark != null) { + tvPkMark.setVisibility(View.GONE); + } + } + + @Override + void bind(RoomQueueInfo info, int position) { + super.bind(info, position); + if (tvPkMark == null) { + return; + } + MicMemberInfo micMemberInfo = info.mChatRoomMember; + if (micMemberInfo != null) { + if (micMemberInfo.getGroupType() == PKTeamInfo.TEAM_RED) { + tvPkMark.setVisibility(View.VISIBLE); + tvPkMark.setBackgroundResource(R.drawable.shape_pk_mic_queue_mark_red); + tvPkMark.setText(ResUtil.getString(R.string.avroom_adapter_basemicroviewadapter_02)); + } else if (micMemberInfo.getGroupType() == PKTeamInfo.TEAM_BLUE) { + tvPkMark.setVisibility(View.VISIBLE); + tvPkMark.setBackgroundResource(R.drawable.shape_pk_mic_queue_mark_blue); + tvPkMark.setText(ResUtil.getString(R.string.avroom_adapter_basemicroviewadapter_03)); + } else { + tvPkMark.setVisibility(View.GONE); + } + } else { + tvPkMark.setVisibility(View.GONE); + } + + } + } + + /** + * 增加礼物值展示 + */ + public class GiftValueViewHolder extends MicroViewAdapter.BasicMicroViewHolder { + + TextView tvCharmValue; + View llCharmClick; + + GiftValueViewHolder(View itemView) { + super(itemView); + tvCharmValue = itemView.findViewById(R.id.tv_charm_value); + llCharmClick = itemView.findViewById(R.id.ll_charm_click); + } + + @Override + void bind(RoomQueueInfo info, int position) { + super.bind(info, position); + //增加非空判断,防止被非法继承 + if (isNpe()) { + return; + } + if (info == null) { + return; + } + GiftValueData charmData = info.giftValueData; + if (charmData == null) { + return; + } + + charmData.removeObserver(); + //控制是否展示礼物值 + Observer showObserver = showValue -> + llCharmClick.setVisibility(showValue != null && showValue ? View.VISIBLE : View.GONE); + charmData.getLdShow().observeForever(showObserver); + charmData.setShowObserver(showObserver); + //礼物值的增加显示 + Observer valueObserver = longValue -> { + if (longValue == null) { + return; + } + if (isNpe()) { + return; + } + tvCharmValue.setText(GiftValueFormat.longToString(longValue)); + llCharmClick.setOnClickListener(v -> { + if (info.mChatRoomMember != null) { + DialogWebViewActivity.start(context, + UriProvider.getPersonalCharismaRank() + "?uid=" + info.mChatRoomMember.getAccount()); + } + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) + return; + if (roomInfo.isLeaveMode() && position == -1) { + DialogWebViewActivity.start(context, + UriProvider.getPersonalCharismaRank() + "?uid=" + roomInfo.getUid()); + } + }); + llCharmClick.setOnLongClickListener(v -> { + if (longValue < 100 * 10000L) { + //小于100万,不需要长按弹框 + return false; + } + View contentView = View.inflate(context, R.layout.popwindow_mic_charm_value, null); + SuperTextView stv_mic_charm_value = contentView.findViewById(R.id.stv_mic_charm_value); + String gvString; + if (longValue >= 10000 * 10000L) { + gvString = "99999999+"; + } else { + gvString = String.valueOf(longValue); + } + stv_mic_charm_value.setText(gvString); + PopupWindow window = new PopupWindow(contentView, ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT, true); + //设置透明度 + ActivityUtil.addAlpha(context, 0.7f); + window.getContentView().measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); + window.setOutsideTouchable(true); + window.setFocusable(true); + window.setBackgroundDrawable(new BitmapDrawable()); + int width = window.getContentView().getMeasuredWidth(); + + int[] location = new int[2]; + llCharmClick.getLocationOnScreen(location); + int showWidth = UIUtil.getScreenWidth(context) - location[0] - UIUtil.dip2px(context, 1); + int offsetX = width / 2; + //以下的处理就是当popWindow靠近屏幕右边的时候,要计算箭头的位置 + if (showWidth < offsetX) { + View iv_center_arrow = contentView.findViewById(R.id.iv_center_arrow); + View iv_move_arrow = contentView.findViewById(R.id.iv_move_arrow); + iv_center_arrow.setVisibility(View.GONE); + iv_move_arrow.setVisibility(View.VISIBLE); + if (iv_move_arrow.getLayoutParams() instanceof RelativeLayout.LayoutParams) { + RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) iv_move_arrow.getLayoutParams(); + params.leftMargin = width / 2 + offsetX - showWidth - UIUtil.dip2px(context, 6.5f); + } + offsetX = offsetX + offsetX - showWidth + UIUtil.dip2px(context, 2); + } + int offsetY = UIUtil.dip2px(context, 19.5f + 39f); + window.showAsDropDown(llCharmClick, + -offsetX, -offsetY); + window.setOnDismissListener(() -> ActivityUtil.removeAlpha(context)); + return true; + }); + }; + + charmData.getLdValue().observeForever(valueObserver); + charmData.setValueObserver(valueObserver); + + //控制最高最低头饰 + Observer headWearObserver = headWearValue -> { + if (ivCharmLevelTag == null) return; + if (headWearValue == 1) { + ivCharmLevelTag.setVisibility(View.GONE); +// ivCharmLevelTag.setVisibility(View.VISIBLE); +// ivCharmLevelTag.setImageDrawable(context.getResources().getDrawable(R.drawable.ic_charm_level_min)); + } else if (headWearValue == 2) { + ivCharmLevelTag.setVisibility(View.VISIBLE); + ivCharmLevelTag.setImageDrawable(context.getResources().getDrawable(R.drawable.ic_charm_level_max)); + } else { + ivCharmLevelTag.setVisibility(View.GONE); + } + }; + charmData.getLdHeadWear().observeForever(headWearObserver); + charmData.setHeadWearObserver(headWearObserver); + + + } + + private boolean isNpe() { + return tvCharmValue == null || llCharmClick == null; + } + } + + public class BossMicroViewHolder extends MicroViewAdapter.GiftValueViewHolder { + /** + * 主席位特有 + */ + View frTitle; + TextView tvRoomDesc; + ImageView ivTag; + TextView tvLabelLeaveMode; + CircleImageView ivLeaveMode; + + + BossMicroViewHolder(View itemView) { + super(itemView); + frTitle = itemView.findViewById(R.id.fr_title); + tvRoomDesc = itemView.findViewById(R.id.tv_room_desc); + ivTag = itemView.findViewById(R.id.iv_tag); + tvLabelLeaveMode = itemView.findViewById(R.id.tv_label_leave_mode); + ivLeaveMode = itemView.findViewById(R.id.iv_bg_leave_mode); + frTitle.setOnClickListener(this); + tvRoomDesc.setOnClickListener(this); + } + + @Override + void bind(RoomQueueInfo info, int position) { + super.bind(info, position); + onRoomInfoUpdate(); + + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) + return; + + // 新版房主位优先判断麦序是否有人,麦序没人再判断是否是离开模式(防止新版展示离开模式,实际麦位有人) + MicMemberInfo chatRoomMember = info.mChatRoomMember; + if (chatRoomMember == null) { + if (roomInfo.isLeaveMode() || AvRoomDataManager.get().isSingleRoom()) { + tvLabelLeaveMode.setVisibility(View.VISIBLE); + ivLeaveMode.setVisibility(View.VISIBLE); + ImageLoadUtils.loadDefaultImage(BasicConfig.INSTANCE.getAppContext(), ivLeaveMode, R.drawable.bg_leave_mode); + + ivAvatar.setVisibility(View.VISIBLE); + ivLockImage.setVisibility(View.INVISIBLE); + ivUpImage.setVisibility(View.INVISIBLE); + + AvRoomDataManager avRoomDataManager = AvRoomDataManager.get(); + ImageLoadUtils.loadAvatar(BasicConfig.INSTANCE.getAppContext(), avRoomDataManager.avatar, ivAvatar); + setSelectText(-1, avRoomDataManager.nick, avRoomDataManager.gender); + + } else { + ivLeaveMode.setVisibility(View.GONE); + tvLabelLeaveMode.setVisibility(View.GONE); + } + + } else { + ivLeaveMode.setVisibility(View.GONE); + tvLabelLeaveMode.setVisibility(View.GONE); + } + + tvNick.setBackgroundColor(context.getResources().getColor(R.color.transparent)); + } + + @Override + protected void setDefalutText(int index) { + //重新覆盖掉用户名的逻辑 + tvNick.setText(""); + tvNick.setVisibility(View.GONE); + tvNick.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); + ivTag.setVisibility(View.GONE); + } + + @Override + protected void setSelectText(int index, String nick, int gender) { + super.setSelectText(index, nick, gender); + tvNick.setVisibility(View.VISIBLE); + if (UserModel.get().getCacheLoginUserInfo() != null && + UserModel.get().getCacheLoginUserInfo().getUserInfoSkillVo() != null) { + if (AvRoomDataManager.get().isRoomOwner() && !TextUtils.isEmpty(UserModel.get().getCacheLoginUserInfo().getUserInfoSkillVo().getSkillTag())) { +// ImageLoadUtils.loadImage(context, UserModel.get().getCacheLoginUserInfo().getUserInfoSkillVo().getSkillTag(), ivTag); + ivTag.setVisibility(View.GONE); + tvNick.setCompoundDrawablePadding(4); + tvNick.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); + } else { + setBossViewGender(tvNick, gender == 1); + ivTag.setVisibility(View.GONE); + } + } + + } + + void onRoomInfoUpdate() { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) return; + if (!TextUtils.isEmpty(roomInfo.getRoomDesc())) { + tvRoomDesc.setText(RegexUtil.getPrintableString(roomInfo.getRoomDesc())); + } else { + if (AvRoomDataManager.get().isManager()) { + tvRoomDesc.setText(BasicConfig.INSTANCE.getAppContext().getString(R.string.room_manager_edit_desc)); + } else { + tvRoomDesc.setText(BasicConfig.INSTANCE.getAppContext().getString(R.string.room_no_desc)); + } + } + } + + @Override + public void clear() { + super.clear(); + tvRoomDesc.setText(BasicConfig.INSTANCE.getAppContext().getString(R.string.room_no_desc)); + ivTag.setVisibility(View.GONE); + } + + @Override + public void onClick(View v) { + super.onClick(v); + } + } + +} diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/CommonVPAdapter.kt b/app/src/main/java/com/chwl/app/avroom/adapter/CommonVPAdapter.kt new file mode 100644 index 0000000..4218776 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/CommonVPAdapter.kt @@ -0,0 +1,25 @@ +package com.chwl.app.avroom.adapter + +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager +import androidx.lifecycle.Lifecycle +import androidx.viewpager2.adapter.FragmentStateAdapter + +/** + * ViewPager2适配器 + * Created by wushaocheng on 2022/12/07. + */ +class CommonVPAdapter( + fm: FragmentManager, + lifecycle: Lifecycle, + private val fragmentList: List +) : FragmentStateAdapter(fm, lifecycle) { + + override fun getItemCount(): Int { + return fragmentList.size + } + + override fun createFragment(position: Int): Fragment { + return fragmentList[position] + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/CpMicroViewAdapter.java b/app/src/main/java/com/chwl/app/avroom/adapter/CpMicroViewAdapter.java new file mode 100644 index 0000000..565d19a --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/CpMicroViewAdapter.java @@ -0,0 +1,140 @@ +package com.chwl.app.avroom.adapter; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.chwl.app.R; +import com.chwl.core.bean.RoomQueueInfo; +import com.chwl.library.utils.ResUtil; + +public class CpMicroViewAdapter extends BaseMicroViewAdapter { + + + public CpMicroViewAdapter(Context context) { + super(context); + } + + @Override + public String microType() { + return BaseMicroViewAdapter.MICRO_TYPE_CP; + } + + @Override + protected int getMicPositionNameOffset() { + return 1; + } + + @Override + public void bindToRecyclerView(RecyclerView recyclerView) { + GridLayoutManager layoutManager = new GridLayoutManager(context, 3); + layoutManager.setOrientation(LinearLayoutManager.VERTICAL); + layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { + @Override + public int getSpanSize(int position) { + if (position == 0) { + return 2; + } else { + return 1; + } + } + }); + recyclerView.setLayoutManager(layoutManager); + recyclerView.setAdapter(this); + } + + @Override + public int getItemCount() { + return 2; + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View item; + if (viewType == TYPE_BOSS) { + item = LayoutInflater.from(parent.getContext()). + inflate(R.layout.item_cp_boss_micro, parent, false); + return new CpBossMicroViewHolder(item); + } else { + item = LayoutInflater.from(parent.getContext()). + inflate(R.layout.list_item_micro_cp, parent, false); + return new CpMicroViewHolder(item); + } + } + + public class CpMicroViewHolder extends NormalMicroViewHolder { + CpMicroViewHolder(View itemView) { + super(itemView); + } + + @Override + void bind(RoomQueueInfo info, int position) { + super.bind(info, position); +// ViewAdapter.setViewBackground( +// tvNick, context.getResources().getColor(R.color.black_transparent_20), 50, 0, 0); + } + + @Override + protected void setDefalutText(int index) { + super.setDefalutText(index); + tvNick.setText(ResUtil.getString(R.string.avroom_adapter_cpmicroviewadapter_01)); + } + } + + public class CpBossMicroViewHolder extends NormalMicroViewHolder { + /** + * 主席位特有 + */ + TextView tvRoomType; + TextView tvRoomDesc; + View ivRoomCanEdit; + + CpBossMicroViewHolder(View itemView) { + super(itemView); +// tvRoomType = itemView.findViewById(R.id.tv_room_type); +// tvRoomDesc = itemView.findViewById(R.id.tv_room_desc); +// ivRoomCanEdit = itemView.findViewById(R.id.iv_room_can_edit); +// tvRoomDesc.setOnClickListener(this); +// tvRoomType.setOnClickListener(this); +// ivRoomCanEdit.setOnClickListener(this); + } + + @Override + void bind(RoomQueueInfo info, int position) { + super.bind(info, position); +// ViewAdapter.setViewBackground( +// tvNick, context.getResources().getColor(R.color.black_transparent_20), 50, 0, 0); + // onRoomInfoUpdate(); +// tvNick.setBackgroundColor(context.getResources().getColor(R.color.transparent)); +// tvNick.setTextColor(context.getResources().getColor(R.color.white)); +// if (AvRoomDataManager.get().isManager()) { +// ivRoomCanEdit.setVisibility(View.VISIBLE); +// } else { +// ivRoomCanEdit.setVisibility(View.GONE); +// } + } + @Override + protected void setDefalutText(int index) { + super.setDefalutText(index); + tvNick.setText(ResUtil.getString(R.string.avroom_adapter_cpmicroviewadapter_02)); + } + + @Override + public void clear() { + super.clear(); + } + + @Override + public void onClick(View v) { + super.onClick(v); + } + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/CreateRoomGameAdapter.kt b/app/src/main/java/com/chwl/app/avroom/adapter/CreateRoomGameAdapter.kt new file mode 100644 index 0000000..d0bc08f --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/CreateRoomGameAdapter.kt @@ -0,0 +1,18 @@ +package com.chwl.app.avroom.adapter + +import android.widget.ImageView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.ui.utils.load +import com.chwl.core.room.game.bean.GameInfo + +class CreateRoomGameAdapter : + BaseQuickAdapter(R.layout.item_room_create_game) { + + override fun convert(helper: BaseViewHolder, item: GameInfo) { + helper.getView(R.id.iv_cover).load(item.pic?:"",12f) + helper.itemView.isSelected = item.isSelect + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/CreateRoomGameGuideAdapter.kt b/app/src/main/java/com/chwl/app/avroom/adapter/CreateRoomGameGuideAdapter.kt new file mode 100644 index 0000000..6b6b4a6 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/CreateRoomGameGuideAdapter.kt @@ -0,0 +1,16 @@ +package com.chwl.app.avroom.adapter + +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.library.common.glide.GlideUtils +import com.chwl.core.room.game.bean.GameInfo + +class CreateRoomGameGuideAdapter : + BaseQuickAdapter(R.layout.item_room_create_game_guide) { + + override fun convert(helper: BaseViewHolder, item: GameInfo) { + GlideUtils.instance().load(item.pic?:"",R.drawable.default_cover,helper.getView(R.id.iv_cover)) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/DatingMicroViewAdapter.kt b/app/src/main/java/com/chwl/app/avroom/adapter/DatingMicroViewAdapter.kt new file mode 100644 index 0000000..0a13664 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/DatingMicroViewAdapter.kt @@ -0,0 +1,235 @@ +package com.chwl.app.avroom.adapter + +import android.annotation.SuppressLint +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import androidx.core.util.forEach +import androidx.core.view.isVisible +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.chwl.app.R +import com.chwl.app.ui.utils.load +import com.chwl.app.utils.UserUtils +import com.chwl.core.Constants +import com.chwl.core.bean.RoomQueueInfo +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.room.bean.RoomInfo +import com.chwl.library.utils.ResUtil + + +/** + * @author xiaoyu + * @date 2017/12/18 + */ +class DatingMicroViewAdapter(context: Context?) : BaseMicroViewAdapter(context) { + override fun getMicPositionNameOffset(): Int { + return 1 + } + + /** + * Set LayoutManager and bind this to RecyclerView + */ + override fun bindToRecyclerView(recyclerView: RecyclerView) { + val layoutManager = GridLayoutManager(context, 4) + layoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() { + override fun getSpanSize(position: Int): Int { + return if (position == 0) 4 else 1 + } + } + layoutManager.orientation = LinearLayoutManager.VERTICAL + recyclerView.layoutManager = layoutManager + recyclerView.adapter = this + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + return if (viewType == TYPE_BOSS) { + DatingBossMicroViewHolder( + LayoutInflater.from(parent.context) + .inflate(R.layout.item_micro_dating_boss, parent, false) + ) + } else { + DatingMicroViewHolder( + LayoutInflater.from(parent.context) + .inflate(R.layout.item_micro_dating, parent, false) + ) + } + } + + override fun getItemViewType(position: Int) = if (position == 0) TYPE_BOSS else TYPE_NORMAL + + override fun microType() = MICRO_TYPE_DATING + + + open inner class DatingMicroViewHolder constructor(itemView: View) : + GiftValueViewHolder(itemView) { + + private val viewGenderBg: View = itemView.findViewById(R.id.view_gender_bg) + private val tvSelectedStatus: TextView = itemView.findViewById(R.id.tv_selected_status) + private val ivCap: ImageView = itemView.findViewById(R.id.iv_cap) + protected val ivVipWear: ImageView = itemView.findViewById(R.id.iv_vip_wear) + + @SuppressLint("SetTextI18n") + public override fun bind(info: RoomQueueInfo, position: Int) { + super.bind(info, position) + val roomInfo = AvRoomDataManager.get().mCurrentRoomInfo ?: return + val roomMicInfo = info.mRoomMicInfo + val manMicro = Constants.maleIndex.contains(position) + val uid = UserUtils.getUserUid() + if (roomMicInfo != null) { + viewGenderBg.setBackgroundResource(if (manMicro) R.drawable.shape_circle_micro_man_bg else R.drawable.shape_circle_micro_woman_bg) + tvSelectedStatus.setBackgroundResource(if (manMicro) R.drawable.selector_dating_select_man_bg else R.drawable.selector_dating_select_woman_bg) + } + ivVipWear.setImageResource(R.drawable.icon_room_dating_vip) + info.mChatRoomMember?.let { + + if (roomInfo.blindDateState == RoomInfo.DATING_STATE_FLOW) { + tvSelectedStatus.isVisible = false + } else { + tvSelectedStatus.isVisible = true + if (it.isVipMic) { + tvSelectedStatus.background = null + ivVipWear.setImageResource(R.drawable.icon_room_dating_vip_have_present) + } + if (it.isHasSelectUser) { + tvSelectedStatus.isSelected = true + if (roomInfo.blindDateState == RoomInfo.DATING_STATE_PUBLISH || + uid == it.account.toLong() || + AvRoomDataManager.get().isPreside(uid) + ) { + tvSelectedStatus.text = + if (AvRoomDataManager.get().isDatingVipMic(it.selectMicPosition) + ) ResUtil.getString(R.string.avroom_adapter_datingmicroviewadapter_01) else "選${it.selectMicPosition + 1}號" + } else { + tvSelectedStatus.text = "已選擇" + } + } else { + tvSelectedStatus.isSelected = false + tvSelectedStatus.text = "未選擇" + } + } + + if (!it.capUrl.isNullOrEmpty()) { + ivCap.load(it.capUrl, 0f, 0) + ivCap.visibility = View.VISIBLE + } else { + ivCap.visibility = View.GONE + } + + ivVipWear.isVisible = it.isVipMic + if (it.isVipMic) { + ivHeadWear?.isVisible = false + } + } ?: run { + tvSelectedStatus.isVisible = false + ivCap.isVisible = false + ivVipWear.isVisible = false + if (AvRoomDataManager.POSITION_VIP_MIC == position) { + tvNick.text = "" + } else if (position != -1) { + tvNick.text = "號${if (manMicro) "男神" else "女神"}位" + } + } + + } + + } + + inner class DatingBossMicroViewHolder internal constructor(itemView: View) : + BossMicroViewHolder(itemView) { + private val rvVip: RecyclerView = itemView.findViewById(R.id.rv_vip) + private val ivVipWear: ImageView = itemView.findViewById(R.id.iv_vip_wear) + + public override fun bind(info: RoomQueueInfo, position: Int) { + super.bind(info, position) + if (info.mChatRoomMember == null) { + tvNick.alpha = 1f + tvNick.text = "主持人" + tvNick.isVisible = true + ivVipWear.isVisible = false + } else { + if (info.mChatRoomMember.isVipMic) { + ivHeadWear?.isVisible = false + ivVipWear.isVisible = true + } else { + ivVipWear.isVisible = false + } + } + + val mMicQueueMemberMap = AvRoomDataManager.get().mMicQueueMemberMap + var showVipMicro = true + mMicQueueMemberMap.forEach { key, value -> + value?.mChatRoomMember?.let { + if (it.isVipMic && AvRoomDataManager.POSITION_VIP_MIC != key) { + showVipMicro = false + } + } + } + + rvVip.isVisible = showVipMicro + + if (showVipMicro) { + var adapter: VipMicroViewAdapter? = rvVip.adapter as? VipMicroViewAdapter + if (adapter == null) { + adapter = VipMicroViewAdapter(context) + adapter.bindToRecyclerView(rvVip) + adapter.setOnMicroItemClickListener(onMicroItemClickListener) + } + adapter.notifyDataSetChanged() + } + + } + } + + inner class VipMicroViewAdapter(context: Context?) : BaseMicroViewAdapter(context) { + + /** + * Set LayoutManager and bind this to RecyclerView + */ + override fun bindToRecyclerView(recyclerView: RecyclerView) { + val layoutManager = LinearLayoutManager(context) + layoutManager.orientation = LinearLayoutManager.VERTICAL + recyclerView.layoutManager = layoutManager + recyclerView.adapter = this + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + return VipMicroViewHolder( + LayoutInflater.from(parent.context) + .inflate(R.layout.item_micro_dating, parent, false) + ) + } + + override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, position: Int) { + val roomQueueInfo = + AvRoomDataManager.get() + .getRoomQueueMemberInfoByMicPosition(AvRoomDataManager.POSITION_VIP_MIC) + ?: return + (viewHolder as NormalMicroViewHolder).bind( + roomQueueInfo, + AvRoomDataManager.POSITION_VIP_MIC + ) + } + + override fun microType() = MICRO_TYPE_DATING_VIP + + override fun getItemCount() = 1 + + inner class VipMicroViewHolder constructor(itemView: View) : + DatingMicroViewHolder(itemView) { + + override fun bind(info: RoomQueueInfo, position: Int) { + super.bind(info, position) + ivVipWear.isVisible = true + ivHeadWear?.isVisible = false + } + + } + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/ExitRoomAdapter.kt b/app/src/main/java/com/chwl/app/avroom/adapter/ExitRoomAdapter.kt new file mode 100644 index 0000000..3761842 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/ExitRoomAdapter.kt @@ -0,0 +1,22 @@ +package com.chwl.app.avroom.adapter + +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.core.home.bean.HomeRoomInfo +import com.chwl.core.utils.extension.subAndReplaceDot +import com.chwl.library.common.util.isVerify + +class ExitRoomAdapter : + BaseQuickAdapter(R.layout.item_exit_room) { + + override fun convert(helper: BaseViewHolder, item: HomeRoomInfo) { + + ImageLoadUtils.loadImage(mContext, item.avatar, helper.getView(R.id.iv_avatar)) + ImageLoadUtils.loadImage(mContext, item.tagPict, helper.getView(R.id.iv_tag)) + helper.setText(R.id.tv_online_num, item.onlineNum.toString()) + .setText(R.id.tv_title, item.title.subAndReplaceDot(8)) + helper.setVisible(R.id.iv_tag, item.tagPict.isVerify()) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/GameMicroViewAdapter.kt b/app/src/main/java/com/chwl/app/avroom/adapter/GameMicroViewAdapter.kt new file mode 100644 index 0000000..fd9d85c --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/GameMicroViewAdapter.kt @@ -0,0 +1,98 @@ +package com.chwl.app.avroom.adapter + +import android.annotation.SuppressLint +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.core.view.isVisible +import androidx.core.view.updateLayoutParams +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.netease.nim.uikit.common.util.sys.ScreenUtil +import com.chwl.app.R +import com.chwl.core.bean.RoomQueueInfo +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.library.utils.ResUtil + + +/** + * @author xiaoyu + * @date 2017/12/18 + */ +class GameMicroViewAdapter(context: Context?) : BaseMicroViewAdapter(context) { + + /** + * Set LayoutManager and bind this to RecyclerView + */ + override fun bindToRecyclerView(recyclerView: RecyclerView) { + val layoutManager = LinearLayoutManager(context) + layoutManager.orientation = LinearLayoutManager.HORIZONTAL + recyclerView.layoutManager = layoutManager + recyclerView.adapter = this + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + return GameMicroViewHolder( + LayoutInflater.from(parent.context) + .inflate(R.layout.item_micro_game, parent, false) + ) + } + + override fun microType() = MICRO_TYPE_DATING + + inner class GameMicroViewHolder constructor(itemView: View) : + GiftValueViewHolder(itemView) { + + private val tvGameStatus: TextView = itemView.findViewById(R.id.tv_game_status) + + @SuppressLint("SetTextI18n") + public override fun bind(info: RoomQueueInfo, position: Int) { + + itemView.updateLayoutParams { + width = when (itemCount) { + 6 -> ScreenUtil.screenWidth / 6 + 7 -> ScreenUtil.screenWidth / 7 + else -> (ScreenUtil.screenWidth / 6f).toInt() + } + } + super.bind(info, position) + info.mChatRoomMember?.let { + if (it.gameStatus == 0 && !AvRoomDataManager.get().isRoomOwner(it.account)) { + tvGameStatus.isVisible = false + } else { + tvGameStatus.isVisible = true + val bgRes = when { + AvRoomDataManager.get().isRoomOwner(it.account) -> { + tvGameStatus.text = ResUtil.getString(R.string.avroom_adapter_gamemicroviewadapter_01) + R.drawable.bg_game_status_owner + } + it.gameStatus == 2 -> { + tvGameStatus.text = ResUtil.getString(R.string.avroom_adapter_gamemicroviewadapter_02) + R.drawable.bg_game_status_ready + } + it.gameStatus == 3 -> { + tvGameStatus.text = ResUtil.getString(R.string.avroom_adapter_gamemicroviewadapter_03) + R.drawable.bg_game_status_playing + } + else -> { + tvGameStatus.text = ResUtil.getString(R.string.avroom_adapter_gamemicroviewadapter_04) + R.drawable.bg_game_status_not_ready + } + } + tvGameStatus.setBackgroundResource(bgRes) + } + } ?: run { + tvGameStatus.isVisible = false + } + + } + + } + + override fun getItemCount(): Int { + return AvRoomDataManager.get().mgMicNum + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/GameMiniMicroViewAdapter.kt b/app/src/main/java/com/chwl/app/avroom/adapter/GameMiniMicroViewAdapter.kt new file mode 100644 index 0000000..3a6f3d4 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/GameMiniMicroViewAdapter.kt @@ -0,0 +1,68 @@ +package com.chwl.app.avroom.adapter + +import android.annotation.SuppressLint +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.chwl.app.R +import com.chwl.core.bean.RoomQueueInfo +import com.chwl.core.manager.AvRoomDataManager + + +/** + * @author xiaoyu + * @date 2017/12/18 + */ +class GameMiniMicroViewAdapter(context: Context?) : BaseMicroViewAdapter(context) { + + private var onClick: (() -> Unit)? = null + + /** + * Set LayoutManager and bind this to RecyclerView + */ + override fun bindToRecyclerView(recyclerView: RecyclerView) { + val layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) + recyclerView.layoutManager = layoutManager + recyclerView.adapter = this + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + return GameMicroViewHolder( + LayoutInflater.from(parent.context) + .inflate(R.layout.item_micro_game_mini, parent, false) + ) + } + + fun setOnClick(onClick: () -> Unit) { + this.onClick = onClick + } + + override fun microType() = "" + + + inner class GameMicroViewHolder constructor(itemView: View) : + NormalMicroViewHolder(itemView) { + + @SuppressLint("SetTextI18n") + public override fun bind(info: RoomQueueInfo, position: Int) { + super.bind(info, position) + itemView.setOnClickListener { + onClick?.invoke() + } + } + + override fun onClick(v: View?) { + onClick?.invoke() + } + + } + + override fun getItemCount(): Int { + return AvRoomDataManager.get().mgMicNum + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/HomePartyPageAdapter.java b/app/src/main/java/com/chwl/app/avroom/adapter/HomePartyPageAdapter.java new file mode 100644 index 0000000..101bc82 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/HomePartyPageAdapter.java @@ -0,0 +1,33 @@ +package com.chwl.app.avroom.adapter; + +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentPagerAdapter; + +import java.util.List; + +/** + *

+ * + * @author jiahui + * @date 2017/12/8 + */ +public class HomePartyPageAdapter extends FragmentPagerAdapter { + + private List mFragmentList; + + public HomePartyPageAdapter(FragmentManager fm, List fragmentList) { + super(fm); + mFragmentList = fragmentList; + } + + @Override + public Fragment getItem(int position) { + return (mFragmentList == null || mFragmentList.size() == 0 ? null : mFragmentList.get(position)); + } + + @Override + public int getCount() { + return mFragmentList == null ? 0 : mFragmentList.size(); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/Mic19ViewAdapter.java b/app/src/main/java/com/chwl/app/avroom/adapter/Mic19ViewAdapter.java new file mode 100644 index 0000000..6aded27 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/Mic19ViewAdapter.java @@ -0,0 +1,144 @@ +package com.chwl.app.avroom.adapter; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.recyclerview.widget.RecyclerView; + +import com.chwl.app.R; +import com.chwl.app.ui.utils.ImageLoadKt; +import com.chwl.app.ui.widget.recyclerview.layoutmanager.BoosRoomLayoutManager; +import com.chwl.app.utils.ResourceManager; +import com.chwl.core.bean.RoomQueueInfo; +import com.chwl.core.gift.bean.RoomMicDress; +import com.chwl.library.common.util.OtherExtKt; +import com.chwl.library.widget.SVGAView; +import com.example.lib_utils.ktx.ResourcesKtxKt; +import com.opensource.svgaplayer.SVGAImageView; + +public class Mic19ViewAdapter extends BaseMicroViewAdapter { + + //麦位 从-1 开始的 , 所以 8好麦的pos是6 + int BossPos = 7; + + public Mic19ViewAdapter(Context context) { + super(context); + } + + /** + * Set LayoutManager and bind this to RecyclerView + */ + @Override + public void bindToRecyclerView(RecyclerView recyclerView) { + recyclerView.setLayoutManager(new BoosRoomLayoutManager(5)); + recyclerView.setAdapter(this); + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + OtherExtKt.doLog(" Mic19ViewAdapter onCreateViewHolder "); + View item ; + item = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_micro,parent,false); + MicroViewHolder microViewHolder = new MicroViewHolder(item); + return microViewHolder; + } + + private void setViewDiff(View[] views , boolean isDiff) { + for (int i = 0; i { + + public MicQueueAdapter(List list) { + super(R.layout.item_mic_queue_list, list); + } + + @Override + protected void convert(BaseViewHolder helper, final QueuingMicMemeberInfo item) { + if (item == null) return; + helper.setText(R.id.tv_userName, item.getNick()) + .setText(R.id.tv_no, (helper.getAdapterPosition() + 1) + ""); + + CircleImageView ivAvatar = helper.getView(R.id.iv_avatar_view); + GlideApp.with(ivAvatar.getContext()) + .load(item.getAvatar()) + .placeholder(R.drawable.default_avatar) + .into(ivAvatar); + + AppCompatImageView ivGender = helper.getView(R.id.iv_gender); + if (item.getGender() == UserInfo.GENDER_MALE) { + ivGender.setImageResource(R.drawable.ic_gender_male); + } else { + ivGender.setImageResource(R.drawable.ic_gender_female); + } + + TextView tvOpt = helper.getView(R.id.tv_opt); + GradientDrawable attentionBg = (GradientDrawable) tvOpt.getBackground(); + if (AvRoomDataManager.get().isManager()) { + + if (item.getGroupType() == GroupType.MALE) { + tvOpt.setText(ResUtil.getString(R.string.avroom_adapter_micqueueadapter_01)); + attentionBg.setColor(mContext.getResources().getColor(R.color.color_518EFF)); + } else if (item.getGroupType() == GroupType.FEMALE) { + tvOpt.setText(ResUtil.getString(R.string.avroom_adapter_micqueueadapter_02)); + attentionBg.setColor(mContext.getResources().getColor(R.color.color_FF6B82)); + } else { + tvOpt.setText(ResUtil.getString(R.string.avroom_adapter_micqueueadapter_03)); + attentionBg.setColor(mContext.getResources().getColor(R.color.appColor)); + } + tvOpt.setTextColor(mContext.getResources().getColor(R.color.color_white)); + + final int itemPos = helper.getAdapterPosition(); + tvOpt.setOnClickListener(v -> { + if (onUpMicListener != null) { + onUpMicListener.onUpMic(item, itemPos); + } + }); + } else { + if (item.getGroupType() == GroupType.MALE) { + tvOpt.setText(ResUtil.getString(R.string.avroom_adapter_micqueueadapter_04)); + attentionBg.setColor(mContext.getResources().getColor(R.color.color_518EFF)); + } else if (item.getGroupType() == GroupType.FEMALE) { + tvOpt.setText(ResUtil.getString(R.string.avroom_adapter_micqueueadapter_05)); + attentionBg.setColor(mContext.getResources().getColor(R.color.color_FF6B82)); + } else { + tvOpt.setText(ResUtil.getString(R.string.avroom_adapter_micqueueadapter_06)); + tvOpt.setTextColor(mContext.getResources().getColor(R.color.appColor)); + attentionBg.setColor(mContext.getResources().getColor(R.color.color_f0f0f0)); + } + tvOpt.setOnClickListener(null); + } + + } + + public interface OnUpMicListener { + void onUpMic(QueuingMicMemeberInfo uid, int itemPos); + } + + private OnUpMicListener onUpMicListener; + + public void setOnUpMicListener(OnUpMicListener onUpMicListener) { + this.onUpMicListener = onUpMicListener; + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/MicroViewAdapter.java b/app/src/main/java/com/chwl/app/avroom/adapter/MicroViewAdapter.java new file mode 100644 index 0000000..ec13987 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/MicroViewAdapter.java @@ -0,0 +1,110 @@ +package com.chwl.app.avroom.adapter; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.chwl.app.R; +import com.chwl.core.bean.RoomQueueInfo; + +/** + * @author xiaoyu + * @date 2017/12/18 + */ + +public class MicroViewAdapter extends BaseMicroViewAdapter { + + public MicroViewAdapter(Context context) { + super(context); + } + + @Override + protected int getMicPositionNameOffset() { + return 1; + } + + /** + * Set LayoutManager and bind this to RecyclerView + */ + @Override + public void bindToRecyclerView(RecyclerView recyclerView) { + GridLayoutManager layoutManager = new GridLayoutManager(context, 4); + layoutManager.setOrientation(LinearLayoutManager.VERTICAL); + layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { + @Override + public int getSpanSize(int position) { + if (position == 0) { + return 4; + } else { + return 1; + } + } + }); + recyclerView.setLayoutManager(layoutManager); + recyclerView.setAdapter(this); + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View item; + if (viewType == TYPE_BOSS) { + item = LayoutInflater.from(parent.getContext()). + inflate(R.layout.item_boss_micro, parent, false); + return new BossMicroViewHolder(item); + } else { + item = LayoutInflater.from(parent.getContext()). + inflate(R.layout.list_item_micro, parent, false); + return new MicroViewHolder(item); + } + } + + + @Override + public String microType() { + return BaseMicroViewAdapter.MICRO_TYPE_NORMAL; + } + + @Override + public int getItemViewType(int position) { + if (position == 0) return TYPE_BOSS; + return TYPE_NORMAL; + } + + class MicroViewHolder extends BaseMicroViewAdapter.GiftValueViewHolder { + MicroViewHolder(View itemView) { + super(itemView); + } + + @Override + public void bind(RoomQueueInfo info, int position) { + super.bind(info, position); +// if (position == 7) { +// ivUpImage.setImageResource(R.drawable.icon_room_up_micro_vip); +// } else { +// ivUpImage.setImageResource(R.drawable.icon_room_up_micro); +// } + } + + @SuppressLint("SetTextI18n") + @Override + public void setDefalutText(int index) { +// if (index == 7) { +// tvNick.setTextColor(Color.WHITE); +// tvNick.setText(ResUtil.getString(R.string.avroom_adapter_microviewadapter_01)); +// if (tvNumber != null) { +// tvNumber.setBackgroundResource(R.drawable.shape_micro_vip); +// tvNumber.setTextColor(Color.WHITE); +// tvNumber.setText(String.valueOf((index + 1))); +// } +// } else { + super.setDefalutText(index); +// } + } + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/OnMicroItemClickListener.java b/app/src/main/java/com/chwl/app/avroom/adapter/OnMicroItemClickListener.java new file mode 100644 index 0000000..e60e800 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/OnMicroItemClickListener.java @@ -0,0 +1,17 @@ +package com.chwl.app.avroom.adapter; + +import com.chwl.core.room.queue.bean.MicMemberInfo; + +/** + * Created by lvzebiao on 2018/11/5. + */ +public interface OnMicroItemClickListener { + void onAvatarBtnClick(int position); + + void onUpMicBtnClick(int position, MicMemberInfo chatRoomMember); + + void onLockBtnClick(int position); + + void onRoomSettingsClick(); + +} diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/OnlineUserAdapter.java b/app/src/main/java/com/chwl/app/avroom/adapter/OnlineUserAdapter.java new file mode 100644 index 0000000..2c20269 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/OnlineUserAdapter.java @@ -0,0 +1,239 @@ +package com.chwl.app.avroom.adapter; + +import android.content.Context; +import android.text.TextUtils; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.appcompat.widget.AppCompatImageView; +import androidx.recyclerview.widget.RecyclerView; + +import com.chad.library.adapter.base.BaseMultiItemQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.utils.NamePlateHelper; +import com.chwl.core.level.UserLevelVo; +import com.chwl.core.room.bean.RoomOnlineUserBean; +import com.netease.nim.uikit.impl.cache.NimUserInfoCache; +import com.netease.nimlib.sdk.RequestCallbackWrapper; +import com.netease.nimlib.sdk.uinfo.constant.GenderEnum; +import com.netease.nimlib.sdk.uinfo.model.NimUserInfo; +import com.chwl.app.R; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.app.ui.widget.NobleAvatarView; +import com.chwl.app.utils.RegexUtil; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.level.UserLevelResourceType; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.manager.IMNetEaseManager; +import com.chwl.core.manager.RoomEvent; +import com.chwl.core.noble.NobleResourceType; +import com.chwl.core.noble.NobleUtil; +import com.chwl.core.room.bean.OnlineChatMember; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.library.utils.ListUtils; + +import java.util.List; + +import io.reactivex.disposables.Disposable; + +/** + *

房间在线人数列表 (上麦,房主,游客,管理员)

+ * + * @author Administrator + * @date 2017/12/4 + */ +public class OnlineUserAdapter extends BaseMultiItemQuickAdapter { + private boolean mIsHomeParty; + private Disposable mDisposable; + private OnRoomOnlineNumberChangeListener mListener; + + public OnlineUserAdapter(Context context, boolean isHomeParty) { + super(null); + addItemType(RoomOnlineUserBean.NORMAL, R.layout.list_item_online_user); + addItemType(RoomOnlineUserBean.NOBLE, R.layout.list_item_online_user_mystery); + mIsHomeParty = isHomeParty; + } + + @Override + public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) { + super.onAttachedToRecyclerView(recyclerView); + registerRoomEvent(); + } + + @Override + protected void convert(@NonNull BaseViewHolder helper, RoomOnlineUserBean item) { + if (item.getItemType() == OnlineChatMember.NOBLE) { + return; + } + // 性别 + final ImageView sexImage = helper.getView(R.id.sex); + if (item.getGender() == 1) { + sexImage.setVisibility(View.VISIBLE); + sexImage.setImageResource(R.drawable.ic_gender_male); + } else if (item.getGender() == 2) { + sexImage.setVisibility(View.VISIBLE); + sexImage.setImageResource(R.drawable.ic_gender_female); + } else { + sexImage.setVisibility(View.GONE); + } + + // 昵称 + helper.setText(R.id.nick, RegexUtil.getPrintableString(item.getNick())); + + // 头像 + NobleAvatarView nobleAvatarView = helper.getView(R.id.noble_avatar_view); + nobleAvatarView.setSize(37, 54, 0); + nobleAvatarView.setData(item); + + // 官字 + helper.getView(R.id.iv_user_official).setVisibility(item.isOfficial() ? View.VISIBLE : View.GONE); + + // 管理 + ImageView ivManager = helper.getView(R.id.manager_logo); + if (item.getMemberType() != null && item.getMemberType().equals("MANAGER")) { + ivManager.setVisibility(View.VISIBLE); + ivManager.setImageResource(R.drawable.icon_admin_logo); + } else if (item.getMemberType() != null && item.getMemberType().equals("CREATOR")) { + ivManager.setVisibility(View.VISIBLE); + ivManager.setImageResource(R.drawable.icon_user_list_room_ownner); + } else { + ivManager.setVisibility(View.GONE); + } + + // 在麦 + ImageView ivMic = helper.getView(R.id.room_online_tag); + ivMic.setVisibility(item.isInMic() ? View.VISIBLE : View.GONE); + + + //等级 + UserLevelVo levelVo = item.getUserLevelVo(); + String experLevelUrl = null; + String charmLevelUrl = null; + if (levelVo != null) { + experLevelUrl = levelVo.getExperUrl(); + charmLevelUrl = levelVo.getCharmUrl(); + } + //经验等级 + AppCompatImageView ivUserExper = helper.getView(R.id.iv_user_exper); + boolean isExperLevelUrlEmpty = TextUtils.isEmpty(experLevelUrl); + ivUserExper.setVisibility(!isExperLevelUrlEmpty ? View.VISIBLE : View.GONE); + if (!isExperLevelUrlEmpty) { + ImageLoadUtils.loadImage(mContext, experLevelUrl, ivUserExper); + } + //魅力等级 + AppCompatImageView ivUserCharm = helper.getView(R.id.iv_user_charm); + boolean isCharmLevelUrlEmpty = TextUtils.isEmpty(charmLevelUrl); + ivUserCharm.setVisibility(!isCharmLevelUrlEmpty ? View.VISIBLE : View.GONE); + if (!isCharmLevelUrlEmpty) { + ImageLoadUtils.loadImage(mContext, charmLevelUrl, ivUserCharm); + } + + // 铭牌 + View inNamePlate = helper.getView(R.id.in_nameplate); + NamePlateHelper.INSTANCE.load(inNamePlate, inNamePlate.findViewById(R.id.tv_official_mask), inNamePlate.findViewById(R.id.iv_official_mask), item); + } + + private void registerRoomEvent() { + mDisposable = IMNetEaseManager.get() + .getChatRoomEventObservable() + .subscribe(roomEvent -> { + if (roomEvent == null) return; + int event = roomEvent.getEvent(); + if (roomEvent.getEvent() == RoomEvent.ADD_BLACK_LIST || + roomEvent.getEvent() == RoomEvent.DOWN_MIC || + roomEvent.getEvent() == RoomEvent.KICK_OUT_ROOM) { + if (roomEvent.getEvent() == RoomEvent.ADD_BLACK_LIST || + roomEvent.getEvent() == RoomEvent.KICK_OUT_ROOM) { + if (mListener != null + && !AvRoomDataManager.get().isOwner(AuthModel.get().getCurrentUid())) { + mListener.addMemberBlack(); + return; + } + } + if (ListUtils.isListEmpty(mData)) return; + if (mIsHomeParty && roomEvent.getEvent() == RoomEvent.DOWN_MIC) { + updateDownUpMic(roomEvent.getAccount(), false); + return; + } + + if (mListener != null) + mListener.addMemberBlack(); + } else if (roomEvent.getEvent() == RoomEvent.ROOM_MANAGER_ADD + || roomEvent.getEvent() == RoomEvent.ROOM_MANAGER_REMOVE) { + updateManager(roomEvent); + } else if (roomEvent.getEvent() == RoomEvent.UP_MIC) { + updateDownUpMic(roomEvent.getAccount(), true); + } else if (event == RoomEvent.ROOM_MEMBER_IN) { + updateMemberIn(roomEvent); + } else if (event == RoomEvent.ROOM_MEMBER_EXIT) { + if (mListener != null) { + mListener.onMemberExit(roomEvent.getAccount()); + } + } + }); + } + + private void updateMemberIn(RoomEvent roomEvent) { + if (mListener != null) { + mListener.onMemberIn(roomEvent.getAccount()); + } + } + + private void updateManager(RoomEvent roomEvent) { + if (mListener != null) + mListener.onUpdateMemberManager(roomEvent.getAccount(), + roomEvent.getEvent() == RoomEvent.ROOM_MANAGER_REMOVE); + } + + private void updateDownUpMic(String account, boolean isUpMic) { + if (mListener != null) { + mListener.onMemberDownUpMic(account, isUpMic); + } + } + + public void release() { + if (mDisposable != null) { + mDisposable.dispose(); + mDisposable = null; + } + } + + public void setListener(OnRoomOnlineNumberChangeListener listener) { + mListener = listener; + } + + public interface OnRoomOnlineNumberChangeListener { + /** + * 成员进来回调 + * + * @param account + */ + void onMemberIn(String account); + + /** + * 成员出去回调 + * + * @param account + */ + void onMemberExit(String account); + + /** + * 成员上下麦更新 + * + * @param account + * @param isUpMic + */ + void onMemberDownUpMic(String account, boolean isUpMic); + + /** + * 设置管理员回调 + * + * @param account + */ + void onUpdateMemberManager(String account, boolean isRemoveManager); + + void addMemberBlack(); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/PKMicQueueAdapter.java b/app/src/main/java/com/chwl/app/avroom/adapter/PKMicQueueAdapter.java new file mode 100644 index 0000000..a8a7ea0 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/PKMicQueueAdapter.java @@ -0,0 +1,98 @@ +package com.chwl.app.avroom.adapter; + +import android.view.View; +import android.widget.TextView; + +import androidx.appcompat.widget.AppCompatImageView; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.netease.nim.uikit.support.glide.GlideApp; +import com.chwl.app.R; +import com.chwl.app.common.widget.CircleImageView; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.room.pk.bean.PKQueuingMicMemberInfo; +import com.chwl.core.room.pk.bean.PKTeamInfo; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.library.utils.ResUtil; + +import java.util.List; + +/** + * @author jack + * @Description + * @Date 2018/12/14 + */ +public class PKMicQueueAdapter extends BaseQuickAdapter { + + public PKMicQueueAdapter(List list) { + super(R.layout.item_pk_mic_queue_list, list); + } + + @Override + protected void convert(BaseViewHolder helper, final PKQueuingMicMemberInfo item) { + helper.setText(R.id.tv_userName, item.getNick()) + .setText(R.id.tv_no, (helper.getAdapterPosition() + 1) + ""); + + + CircleImageView ivAvatar = helper.getView(R.id.iv_avatar_view); + GlideApp.with(ivAvatar.getContext()) + .load(item.getAvatar()) + .placeholder(R.drawable.default_avatar) + .into(ivAvatar); + + AppCompatImageView ivGender = helper.getView(R.id.iv_gender); + if (item.getGender() == UserInfo.GENDER_MALE) { + ivGender.setImageResource(R.drawable.ic_gender_male); + } else { + ivGender.setImageResource(R.drawable.ic_gender_female); + } + + TextView tvOpt = helper.getView(R.id.tv_opt); + tvOpt.setTextColor(mContext.getResources().getColor(R.color.color_FFFFFF)); + if (AvRoomDataManager.get().isManager()) { + if (item.getGroupType() == PKTeamInfo.TEAM_RED) { + tvOpt.setText(ResUtil.getString(R.string.avroom_adapter_pkmicqueueadapter_01)); + tvOpt.setBackgroundResource(R.drawable.shape_pk_join_red_team_mark); + } else if (item.getGroupType() == PKTeamInfo.TEAM_BLUE) { + tvOpt.setText(ResUtil.getString(R.string.avroom_adapter_pkmicqueueadapter_02)); + tvOpt.setBackgroundResource(R.drawable.shape_pk_join_blue_team_mark); + } else { + tvOpt.setText(ResUtil.getString(R.string.avroom_adapter_pkmicqueueadapter_03)); + tvOpt.setBackgroundResource(R.drawable.shape_bg_add_attention); + } + final int itemPos = helper.getAdapterPosition(); + tvOpt.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (onUpMicListener != null) { + onUpMicListener.onUpMic(item, itemPos); + } + } + }); + } else { + if (item.getGroupType() == PKTeamInfo.TEAM_RED) { + tvOpt.setText(ResUtil.getString(R.string.avroom_adapter_pkmicqueueadapter_04)); + tvOpt.setBackgroundResource(R.drawable.shape_pk_join_red_team_mark); + } else if (item.getGroupType() == PKTeamInfo.TEAM_BLUE) { + tvOpt.setText(ResUtil.getString(R.string.avroom_adapter_pkmicqueueadapter_05)); + tvOpt.setBackgroundResource(R.drawable.shape_pk_join_blue_team_mark); + } else { + tvOpt.setText(ResUtil.getString(R.string.avroom_adapter_pkmicqueueadapter_06)); + tvOpt.setBackgroundResource(R.drawable.shape_bg_add_attention); + } + tvOpt.setOnClickListener(null); + } + + } + + public interface OnUpMicListener { + void onUpMic(PKQueuingMicMemberInfo memeberInfo, int itemPos); + } + + private OnUpMicListener onUpMicListener; + + public void setOnUpMicListener(OnUpMicListener onUpMicListener) { + this.onUpMicListener = onUpMicListener; + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/PartyMicroViewAdapter.java b/app/src/main/java/com/chwl/app/avroom/adapter/PartyMicroViewAdapter.java new file mode 100644 index 0000000..d3ae3c2 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/PartyMicroViewAdapter.java @@ -0,0 +1,78 @@ +package com.chwl.app.avroom.adapter; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.chwl.app.R; +import com.chwl.core.bean.RoomQueueInfo; + +/** + * @author xiaoyu + * @date 2017/12/18 + */ + +public class PartyMicroViewAdapter extends BaseMicroViewAdapter { + + public PartyMicroViewAdapter(Context context) { + super(context); + } + + /** + * Set LayoutManager and bind this to RecyclerView + */ + @Override + public void bindToRecyclerView(RecyclerView recyclerView) { + GridLayoutManager layoutManager = new GridLayoutManager(context, 5); + layoutManager.setOrientation(LinearLayoutManager.VERTICAL); + recyclerView.setLayoutManager(layoutManager); + recyclerView.setAdapter(this); + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View item; + item = LayoutInflater.from(parent.getContext()). + inflate(R.layout.list_item_micro, parent, false); + return new MicroViewHolder(item); + } + + @Override + public String microType() { + return BaseMicroViewAdapter.MICRO_TYPE_PARTY; + } + + @Override + public int getItemViewType(int position) { + return TYPE_NORMAL; + } + + @Override + public int getItemCount() { + return 10; + } + + class MicroViewHolder extends GiftValueViewHolder { + MicroViewHolder(View itemView) { + super(itemView); + } + + @Override + public void bind(RoomQueueInfo info, int position) { + super.bind(info, position); +// ivUpImage.setImageResource(R.drawable.icon_room_up_micro); + } + + @SuppressLint("SetTextI18n") + @Override + public void setDefalutText(int index) { + super.setDefalutText(index); + } + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/RecordForPKAdapter.java b/app/src/main/java/com/chwl/app/avroom/adapter/RecordForPKAdapter.java new file mode 100644 index 0000000..39df1f3 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/RecordForPKAdapter.java @@ -0,0 +1,153 @@ +package com.chwl.app.avroom.adapter; + +import android.content.Context; +import android.graphics.drawable.GradientDrawable; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.Nullable; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.core.room.pk.bean.PKRecordInfo; +import com.chwl.core.room.pk.bean.PKTeamInfo; +import com.chwl.core.room.pk.bean.PKTeamMember; +import com.chwl.core.room.pk.bean.RoomPkData; +import com.chwl.library.utils.FormatUtils; +import com.chwl.library.utils.ResUtil; + +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * @author jack + * @Description + * @Date 2018/12/29 + */ +public class RecordForPKAdapter extends BaseQuickAdapter { + + private Context context; + private SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd\nHH:mm:ss"); + + public RecordForPKAdapter(Context context, @Nullable List data) { + super(R.layout.item_record_for_pk, data); + this.context = context; + } + + @Override + protected void convert(BaseViewHolder helper, PKRecordInfo item) { + if (item.getVoteMode() == RoomPkData.VOTE_MODE_GIFT) { + helper.setText(R.id.tv_pk_type, context.getResources().getString(R.string.vote_type_gift_value)); + } else if (item.getVoteMode() == RoomPkData.VOTE_MODE_PERSON) { + helper.setText(R.id.tv_pk_type, context.getResources().getString(R.string.vote_type_gift_member)); + } + helper.setText(R.id.tv_time, formater.format(new Date(item.getBeginTime()))); + + LinearLayout llRedTeamMembers = (LinearLayout) helper.getView(R.id.ll_red_team_members); + LinearLayout llBlueTeamMembers = (LinearLayout) helper.getView(R.id.ll_blue_team_members); + + TextView tvRedTeamScore = (TextView) helper.getView(R.id.tv_red_team_score); + TextView tvRedTeamResult = (TextView) helper.getView(R.id.tv_red_team_result); + + TextView tvBlueTeamScore = (TextView) helper.getView(R.id.tv_blue_team_score); + TextView tvBlueTeamResult = (TextView) helper.getView(R.id.tv_blue_team_result); + GradientDrawable redTeamMembersBackground = (GradientDrawable) llRedTeamMembers.getBackground(); + GradientDrawable blueTeamMembersBackground = (GradientDrawable) llBlueTeamMembers.getBackground(); + + + TextView tvRedTeamMember1 = (TextView) helper.getView(R.id.tv_red_team_member_1); + TextView tvRedTeamMember3 = (TextView) helper.getView(R.id.tv_red_team_member_3); + TextView tvRedTeamMember2 = (TextView) helper.getView(R.id.tv_red_team_member_2); + TextView tvRedTeamMember4 = (TextView) helper.getView(R.id.tv_red_team_member_4); + TextView tvBlueTeamMember1 = (TextView) helper.getView(R.id.tv_blue_team_member_1); + TextView tvBlueTeamMember3 = (TextView) helper.getView(R.id.tv_blue_team_member_3); + TextView tvBlueTeamMember2 = (TextView) helper.getView(R.id.tv_blue_team_member_2); + TextView tvBlueTeamMember4 = (TextView) helper.getView(R.id.tv_blue_team_member_4); + + List redTeamMemberViews = new ArrayList<>(); + redTeamMemberViews.add(tvRedTeamMember1); + redTeamMemberViews.add(tvRedTeamMember2); + redTeamMemberViews.add(tvRedTeamMember3); + redTeamMemberViews.add(tvRedTeamMember4); + + List blueTeamMemberViews = new ArrayList<>(); + blueTeamMemberViews.add(tvBlueTeamMember1); + blueTeamMemberViews.add(tvBlueTeamMember2); + blueTeamMemberViews.add(tvBlueTeamMember3); + blueTeamMemberViews.add(tvBlueTeamMember4); + + + PKTeamInfo teamRed = findPKTeam(PKTeamInfo.TEAM_RED, item.getTeams()); + PKTeamInfo teamBlue = findPKTeam(PKTeamInfo.TEAM_BLUE, item.getTeams()); + + if (teamRed != null) { + tvRedTeamScore.setText(FormatUtils.formatPKValue(teamRed.getScore())); + for (int i = 0; i < redTeamMemberViews.size(); i++) { + if (i < teamRed.getTeamMembers().size()) { + PKTeamMember pkTeamMember = teamRed.getTeamMembers().get(i); + redTeamMemberViews.get(i).setVisibility(View.VISIBLE); + redTeamMemberViews.get(i).setText(pkTeamMember.getNick()); + } else { + redTeamMemberViews.get(i).setVisibility(View.GONE); + } + } + } + + if (teamBlue != null) { + tvBlueTeamScore.setText(FormatUtils.formatPKValue(teamBlue.getScore())); + for (int i = 0; i < blueTeamMemberViews.size(); i++) { + if (i < teamBlue.getTeamMembers().size()) { + PKTeamMember pkTeamMember = teamBlue.getTeamMembers().get(i); + blueTeamMemberViews.get(i).setVisibility(View.VISIBLE); + blueTeamMemberViews.get(i).setText(pkTeamMember.getNick()); + } else { + blueTeamMemberViews.get(i).setVisibility(View.GONE); + } + } + } + + if (PKTeamInfo.TEAM_RED == item.getResult()) { + redTeamMembersBackground.setColor(context.getResources().getColor(R.color.color_FD4D72)); + blueTeamMembersBackground.setColor(context.getResources().getColor(R.color.color_CCCCCC)); + tvRedTeamResult.setText(ResUtil.getString(R.string.avroom_adapter_recordforpkadapter_01)); + tvRedTeamResult.setBackgroundResource(R.drawable.bg_pk_record_red_team); + tvBlueTeamResult.setText(ResUtil.getString(R.string.avroom_adapter_recordforpkadapter_02)); + tvBlueTeamResult.setBackgroundResource(R.drawable.bg_pk_record_loser); + + } else if (PKTeamInfo.TEAM_BLUE == item.getResult()) { + redTeamMembersBackground.setColor(context.getResources().getColor(R.color.color_CCCCCC)); + blueTeamMembersBackground.setColor(context.getResources().getColor(R.color.color_3B74FE)); + tvRedTeamResult.setText(ResUtil.getString(R.string.avroom_adapter_recordforpkadapter_03)); + tvRedTeamResult.setBackgroundResource(R.drawable.bg_pk_record_loser); + tvBlueTeamResult.setText(ResUtil.getString(R.string.avroom_adapter_recordforpkadapter_04)); + tvBlueTeamResult.setBackgroundResource(R.drawable.bg_pk_record_blue_team); + } else if (RoomPkData.PK_RESULT_DRAW == item.getResult()) { + redTeamMembersBackground.setColor(context.getResources().getColor(R.color.color_CCCCCC)); + blueTeamMembersBackground.setColor(context.getResources().getColor(R.color.color_CCCCCC)); + tvRedTeamResult.setText(ResUtil.getString(R.string.avroom_adapter_recordforpkadapter_05)); + tvRedTeamResult.setBackgroundResource(R.drawable.bg_pk_record_loser); + tvBlueTeamResult.setText(ResUtil.getString(R.string.avroom_adapter_recordforpkadapter_06)); + tvBlueTeamResult.setBackgroundResource(R.drawable.bg_pk_record_loser); + } else { + redTeamMembersBackground.setColor(context.getResources().getColor(R.color.color_CCCCCC)); + blueTeamMembersBackground.setColor(context.getResources().getColor(R.color.color_CCCCCC)); + tvRedTeamResult.setText(ResUtil.getString(R.string.avroom_adapter_recordforpkadapter_07)); + tvRedTeamResult.setBackgroundResource(R.drawable.bg_pk_record_loser); + tvBlueTeamResult.setText(ResUtil.getString(R.string.avroom_adapter_recordforpkadapter_08)); + tvBlueTeamResult.setBackgroundResource(R.drawable.bg_pk_record_loser); + } + } + + private PKTeamInfo findPKTeam(int teamMark, List pkTeamInfoList) { + for (PKTeamInfo pkTeamInfo : pkTeamInfoList) { + if (teamMark == pkTeamInfo.getTeam()) { + return pkTeamInfo; + } + } + return null; + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/RevelryMicroViewAdapter.java b/app/src/main/java/com/chwl/app/avroom/adapter/RevelryMicroViewAdapter.java new file mode 100644 index 0000000..0fdd5f2 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/RevelryMicroViewAdapter.java @@ -0,0 +1,78 @@ +package com.chwl.app.avroom.adapter; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.chwl.app.R; +import com.chwl.core.bean.RoomQueueInfo; + +/** + * @author xiaoyu + * @date 2017/12/18 + */ + +public class RevelryMicroViewAdapter extends BaseMicroViewAdapter { + + public RevelryMicroViewAdapter(Context context) { + super(context); + } + + /** + * Set LayoutManager and bind this to RecyclerView + */ + @Override + public void bindToRecyclerView(RecyclerView recyclerView) { + GridLayoutManager layoutManager = new GridLayoutManager(context, 5); + layoutManager.setOrientation(LinearLayoutManager.VERTICAL); + recyclerView.setLayoutManager(layoutManager); + recyclerView.setAdapter(this); + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View item; + item = LayoutInflater.from(parent.getContext()). + inflate(R.layout.list_item_micro, parent, false); + return new MicroViewHolder(item); + } + + @Override + public String microType() { + return BaseMicroViewAdapter.MICRO_TYPE_REVELRY; + } + + @Override + public int getItemViewType(int position) { + return TYPE_NORMAL; + } + + @Override + public int getItemCount() { + return 15; + } + + class MicroViewHolder extends GiftValueViewHolder { + MicroViewHolder(View itemView) { + super(itemView); + } + + @Override + public void bind(RoomQueueInfo info, int position) { + super.bind(info, position); +// ivUpImage.setImageResource(R.drawable.icon_room_up_micro); + } + + @SuppressLint("SetTextI18n") + @Override + public void setDefalutText(int index) { + super.setDefalutText(index); + } + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/RoomBgAdapter.kt b/app/src/main/java/com/chwl/app/avroom/adapter/RoomBgAdapter.kt new file mode 100644 index 0000000..13c4d64 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/RoomBgAdapter.kt @@ -0,0 +1,45 @@ +package com.chwl.app.avroom.adapter + +import android.graphics.drawable.Drawable +import android.view.View +import android.widget.ImageView +import androidx.core.view.isVisible +import com.bumptech.glide.Glide +import com.bumptech.glide.load.DataSource +import com.bumptech.glide.load.engine.GlideException +import com.bumptech.glide.request.RequestListener +import com.bumptech.glide.request.target.Target +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.ui.utils.load + +class RoomBgAdapter : BaseQuickAdapter(R.layout.room_bg_setting_item) { + private var selectItem: String? = null + override fun convertPayloads( + helper: BaseViewHolder, + item: String?, + payloads: MutableList + ) { + super.convertPayloads(helper, item, payloads) + convertStatus(helper, item) + } + + override fun convert(helper: BaseViewHolder, item: String?) { + val imageView = helper.getView(R.id.iv_image) + imageView.load(item) + convertStatus(helper, item) + } + + private fun convertStatus(helper: BaseViewHolder, item: String?) { + val statusView = helper.getView(R.id.tv_status) + statusView.isVisible = item == selectItem + } + + fun getSelectItem() = selectItem + + fun selectItem(url: String?) { + selectItem = url + notifyItemRangeChanged(0, itemCount, true) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/RoomBlackListAdapter.java b/app/src/main/java/com/chwl/app/avroom/adapter/RoomBlackListAdapter.java new file mode 100644 index 0000000..b50d999 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/RoomBlackListAdapter.java @@ -0,0 +1,36 @@ +package com.chwl.app.avroom.adapter; + +import android.content.Context; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMember; +import com.chwl.app.R; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; + + +/** + * 右滑操作的,写了暂时不用 + * Created by lvzebiao + */ + +public class RoomBlackListAdapter extends BaseQuickAdapter{ + + private Context context; + + private int itemWidth; + + public RoomBlackListAdapter(Context context) { + super(R.layout.list_item_room_black); + this.context = context; + itemWidth = UIUtil.getScreenWidth(context); + } + + @Override + protected void convert(BaseViewHolder helper, ChatRoomMember chatRoomMember) { + helper.setText(R.id.nick, chatRoomMember.getNick()); + ImageLoadUtils.loadAvatar(context, chatRoomMember.getAvatar(), helper.getView(R.id.avatar)); + helper.getView(R.id.layout_item).getLayoutParams().width = itemWidth; + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/RoomConsumeListAdapter.java b/app/src/main/java/com/chwl/app/avroom/adapter/RoomConsumeListAdapter.java new file mode 100644 index 0000000..b43dffd --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/RoomConsumeListAdapter.java @@ -0,0 +1,196 @@ +package com.chwl.app.avroom.adapter; + +import android.content.Context; +import android.text.TextUtils; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import androidx.appcompat.widget.AppCompatImageView; + +import com.chad.library.adapter.base.BaseMultiItemQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.app.ui.widget.NobleAvatarView; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.utils.RegexUtil; +import com.chwl.core.noble.bean.NobleInfo; +import com.chwl.core.noble.NobleUtil; +import com.chwl.core.room.bean.RoomContributeUserInfo; +import com.chwl.core.room.bean.RoomRankMultiItem; +import com.chwl.library.utils.ResUtil; + +import java.math.BigDecimal; +import java.util.ArrayList; + +/** + *

房间消费adapter

+ * + * @author Administrator + * @date 2017/11/20 + */ +public class RoomConsumeListAdapter extends BaseMultiItemQuickAdapter { + + private Context context; + + public RoomConsumeListAdapter(Context context) { + super(new ArrayList<>()); + this.context = context; + addItemType(RoomContributeUserInfo.TYPE_GRID, R.layout.list_item_room_consume_first); + addItemType(RoomRankMultiItem.TYPE_LINEAR, R.layout.list_item_room_consume); + } + + @Override + protected void convert(BaseViewHolder baseViewHolder, RoomContributeUserInfo roomConsumeInfo) { + if (roomConsumeInfo == null) { + return; + } + if (roomConsumeInfo.getItemType() == RoomRankMultiItem.TYPE_LINEAR) { + setLinearData(baseViewHolder, roomConsumeInfo); + } else { + setGridData(baseViewHolder, roomConsumeInfo); + } + } + + private void setGridData(BaseViewHolder baseViewHolder, RoomContributeUserInfo roomConsumeInfo) { + RelativeLayout avatarContainer = baseViewHolder.getView(R.id.avatar_container); + int position = baseViewHolder.getLayoutPosition(); + RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) avatarContainer.getLayoutParams(); + + ImageView ivAvatar = baseViewHolder.getView(R.id.iv_avatar); + ViewGroup.LayoutParams avatarParams = ivAvatar.getLayoutParams(); + + RelativeLayout.LayoutParams nickLayoutParams = (RelativeLayout.LayoutParams) + baseViewHolder.getView(R.id.nick_layout).getLayoutParams(); + + if (position == 0) { //排行榜第二名 + params.topMargin = UIUtil.dip2px(context, 33); + params.width = params.height = UIUtil.dip2px(context, 90); + avatarParams.width = avatarParams.height = UIUtil.dip2px(context, 58); + nickLayoutParams.topMargin = UIUtil.dip2px(context, 118); + } else if (position == 1) {//排行榜第一名 + params.topMargin = 0; + params.width = params.height = UIUtil.dip2px(context, 110); + avatarParams.width = avatarParams.height = UIUtil.dip2px(context, 71); + nickLayoutParams.topMargin = UIUtil.dip2px(context, 105); + } else {//排行榜第三名 + params.topMargin = UIUtil.dip2px(context, 26); + params.width = params.height = UIUtil.dip2px(context, 90); + avatarParams.width = avatarParams.height = UIUtil.dip2px(context, 58); + nickLayoutParams.topMargin = UIUtil.dip2px(context, 111); + } + ImageView ivRankIcon = baseViewHolder.getView(R.id.iv_rank_icon); + int emptyPic; + //虚位以待,没数据展示,隐藏相关即可 + baseViewHolder.setVisible(R.id.tv_nick, !roomConsumeInfo.isEmptyBean()) + .setVisible(R.id.tv_erban_id, !roomConsumeInfo.isEmptyBean()) + .setVisible(R.id.coin_text, !roomConsumeInfo.isEmptyBean()) + .setVisible(R.id.tv_empty_text, roomConsumeInfo.isEmptyBean()); + if (roomConsumeInfo.isEmptyBean()) { + if (position == 0) { + emptyPic = R.drawable.icon_consume_second_empty; + } else if (position == 1) { + emptyPic = R.drawable.icon_consume_first_empty; + } else { + emptyPic = R.drawable.icon_consume_third_empty; + } + ivAvatar.setVisibility(View.GONE); + ivRankIcon.setImageResource(emptyPic); + } else { + if (position == 0) { + emptyPic = R.drawable.icon_consume_second; + } else if (position == 1) { + emptyPic = R.drawable.icon_consume_first; + } else { + emptyPic = R.drawable.icon_consume_third; + } + ivAvatar.setVisibility(View.VISIBLE); + if (roomConsumeInfo.isHide()) { + ImageLoadUtils.loadAvatarBig(context.getResources().getString(R.string.url_mystery_man), ivAvatar); + } else { + ImageLoadUtils.loadAvatarBig(roomConsumeInfo.getAvatar(), ivAvatar); + } + ivRankIcon.setImageResource(emptyPic); + + setCommonView(baseViewHolder, roomConsumeInfo); + + } + + + } + + private void setLinearData(BaseViewHolder baseViewHolder, RoomContributeUserInfo roomConsumeInfo) { + + NobleAvatarView nobleAvatarView = baseViewHolder.getView(R.id.noble_avatar_view); + nobleAvatarView.setSize(45, 66, 14); + NobleInfo nobleInfo = new NobleInfo(); + nobleInfo.setBadge(roomConsumeInfo.getBadge()); + nobleInfo.setHeadWear(roomConsumeInfo.getMicDecorate()); + if (roomConsumeInfo.isHide()) { + nobleAvatarView.setData(context.getResources().getString(R.string.url_mystery_man), nobleInfo); + } else { + nobleAvatarView.setData(roomConsumeInfo.getAvatar(), nobleInfo); + } + + AppCompatImageView ivNobleLevel = baseViewHolder.getView(R.id.iv_noble_level); + ivNobleLevel.setVisibility(View.GONE); + String nobleBadge; + if (!TextUtils.isEmpty((nobleBadge = roomConsumeInfo.getBadge()))) { + ivNobleLevel.setVisibility(View.VISIBLE); + NobleUtil.loadResource(nobleBadge, ivNobleLevel); + } + + AppCompatImageView ivUserLevel = baseViewHolder.getView(R.id.iv_user_level); + ivUserLevel.setVisibility(View.GONE); + if (!TextUtils.isEmpty(roomConsumeInfo.getExperUrl())) { + ivUserLevel.setVisibility(View.VISIBLE); + ImageLoadUtils.loadImage(mContext, roomConsumeInfo.getExperUrl(), ivUserLevel); + } + + + TextView numberText = baseViewHolder.getView(R.id.auction_number_text); + ImageView numberImage = baseViewHolder.getView(R.id.auction_number_image); + int position = baseViewHolder.getLayoutPosition(); + if (position <= 2) { + numberText.setVisibility(View.INVISIBLE); + numberImage.setVisibility(View.VISIBLE); + if (position == 0) { + numberImage.setImageResource(R.drawable.icon_auction_week_list_first); + } else if (position == 1) { + numberImage.setImageResource(R.drawable.icon_auction_week_list_second); + } else { + numberImage.setImageResource(R.drawable.icon_auction_week_list_third); + } + } else { + numberText.setVisibility(View.VISIBLE); + numberImage.setVisibility(View.GONE); + numberText.setText(mContext.getString(R.string.consume_position, (position + 1))); + } + setCommonView(baseViewHolder, roomConsumeInfo); + } + + /** + * 设置共同的部分 + */ + private void setCommonView(BaseViewHolder baseViewHolder, RoomContributeUserInfo roomConsumeInfo) { + String goldAmount; + if (roomConsumeInfo.getGoldAmount() >= 10000) { + BigDecimal b = new BigDecimal(roomConsumeInfo.getGoldAmount() / 10000.0); + double df = b.setScale(1, BigDecimal.ROUND_HALF_UP).doubleValue(); + goldAmount = String.valueOf(df) + ResUtil.getString(R.string.avroom_adapter_roomconsumelistadapter_01); + } else { + goldAmount = String.valueOf(roomConsumeInfo.getGoldAmount()); + } + baseViewHolder.setText(R.id.tv_erban_id, roomConsumeInfo.isHide() ? "****" : "ID:" + roomConsumeInfo.getErbanNo()) + .setImageResource(R.id.iv_sex, + roomConsumeInfo.getGender() == 1 ? R.drawable.ic_gender_male : R.drawable.ic_gender_female) + .setText(R.id.coin_text, goldAmount) + .setText(R.id.tv_nick, roomConsumeInfo.isHide() ? + context.getResources().getString(R.string.mystery_man) + : RegexUtil.getPrintableString(roomConsumeInfo.getNick())); + } + +} diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/RoomConsumerListAdapterTemp.java b/app/src/main/java/com/chwl/app/avroom/adapter/RoomConsumerListAdapterTemp.java new file mode 100644 index 0000000..028959a --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/RoomConsumerListAdapterTemp.java @@ -0,0 +1,205 @@ +package com.chwl.app.avroom.adapter; + +import android.content.Context; +import android.text.TextUtils; +import android.view.View; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import androidx.appcompat.widget.AppCompatImageView; + +import com.chad.library.adapter.base.BaseMultiItemQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.app.common.widget.CircleImageView; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.app.utils.RegexUtil; +import com.chwl.core.room.bean.RoomContributeUserInfo; +import com.chwl.core.room.bean.RoomRankMultiItem; + +import java.util.ArrayList; + +public class RoomConsumerListAdapterTemp extends BaseMultiItemQuickAdapter { + + public final static int TYPE_EMPTY = 3; + private RoomConsumerTopThreeListener mRoomConsumerTopThreeListener; + + public RoomConsumerListAdapterTemp(Context context) { + super(new ArrayList<>()); + addItemType(RoomContributeUserInfo.TYPE_GRID, R.layout.layout_room_rank_top_three); + addItemType(RoomRankMultiItem.TYPE_LINEAR, R.layout.list_item_room_consume); + addItemType(TYPE_EMPTY, R.layout.item_empty_list); + } + + public void setmRoomConsumerTopThreeListener(RoomConsumerTopThreeListener mRoomConsumerTopThreeListener) { + this.mRoomConsumerTopThreeListener = mRoomConsumerTopThreeListener; + } + + @Override + protected void convert(BaseViewHolder baseViewHolder, RoomRankMultiItem roomConsumeInfo) { + if (roomConsumeInfo == null) { + return; + } + if (roomConsumeInfo.getItemType() == RoomRankMultiItem.TYPE_LINEAR) { + setLinearData(baseViewHolder, roomConsumeInfo); + } else if (roomConsumeInfo.getItemType() == TYPE_EMPTY) { + + } else { + setGridView(baseViewHolder, roomConsumeInfo); + } + } + + private void setGridView(BaseViewHolder baseViewHolder, RoomRankMultiItem roomRankMultiItem) { + ArrayList data = (ArrayList) roomRankMultiItem.getData(); + View root = baseViewHolder.itemView; + + RelativeLayout rlTopOne = root.findViewById(R.id.layout_room_rank_top_1); + CircleImageView ciTopOne = root.findViewById(R.id.iv_room_rank_top_1_avatar); + ImageView ivGenderOne = root.findViewById(R.id.iv_room_rank_gender_one); + ImageView ivBgOne = root.findViewById(R.id.iv_room_rank_top_1_avatar_default); + TextView tvOneId = root.findViewById(R.id.tv_number_one_id); + TextView tvLabelOne = root.findViewById(R.id.tv_label_no_1); + TextView tvOneName = root.findViewById(R.id.tv_label_number_one); + + RelativeLayout rlTopTwo = root.findViewById(R.id.layout_room_rank_top_2); + CircleImageView ciTopTwo = root.findViewById(R.id.iv_room_rank_top_2_avatar); + ImageView ivGenderTwo = root.findViewById(R.id.iv_room_rank_gender_two); + ImageView ivBgTwo = root.findViewById(R.id.iv_room_rank_top_2_avatar_default); + TextView tvTwoId = root.findViewById(R.id.tv_number_two_id); + TextView tvLabelTwo = root.findViewById(R.id.tv_two_to_last); + TextView tvTwoName = root.findViewById(R.id.tv_label_number_two); + + RelativeLayout rlTopThree = root.findViewById(R.id.layout_room_rank_top_3); + CircleImageView ciTopThree = root.findViewById(R.id.iv_room_rank_top_3_avatar); + ImageView ivGenderThree = root.findViewById(R.id.iv_room_rank_gender_three); + ImageView ivBgThree = root.findViewById(R.id.iv_room_rank_top_3_avatar_default); + TextView tvThreeId = root.findViewById(R.id.tv_number_three_id); + TextView tvLabelThree = root.findViewById(R.id.tv_three_to_last); + TextView tvThreeName = root.findViewById(R.id.tv_label_number_three); + + if (data != null) { + + for (int i = 0; i < data.size(); i++) { + RoomContributeUserInfo userInfo = data.get(i); + + if (userInfo != null) { + // 无数据状态需要展示 虚位以待 + boolean isEmptyBean = userInfo.isEmptyBean(); + + if (i == 0) { + + if (!TextUtils.isEmpty(userInfo.getAvatar())) + ImageLoadUtils.loadAvatarBig(userInfo.getAvatar(), ciTopOne); + + + ivGenderOne.setVisibility(isEmptyBean ? View.GONE : View.VISIBLE); + ivGenderOne.setImageResource(userInfo.getGender() == 1 ? R.drawable.ic_gender_male : R.drawable.ic_gender_female); + + ciTopOne.setVisibility(isEmptyBean ? View.GONE : View.VISIBLE); + tvLabelOne.setText(isEmptyBean ? "" : String.valueOf(userInfo.getGoldAmount())); + ivBgOne.setImageResource(isEmptyBean ? R.drawable.icon_consume_first_empty : R.drawable.icon_consume_first); + tvOneId.setText(isEmptyBean? "" : "ID:" + userInfo.getErbanNo()); + tvOneName.setText(isEmptyBean ? "" : userInfo.getNick()); + rlTopOne.setOnClickListener(isEmptyBean ? null : new View.OnClickListener() { + @Override + public void onClick(View v) { + if (userInfo.isHide()) return; + if (userInfo.isEmptyBean()) return; + if (mRoomConsumerTopThreeListener != null) + mRoomConsumerTopThreeListener.topThreeListener(userInfo.getUid()); + } + }); + } else if (i == 1) { + + if (!TextUtils.isEmpty(userInfo.getAvatar())) + ImageLoadUtils.loadAvatarBig(userInfo.getAvatar(), ciTopTwo); + ivGenderTwo.setVisibility(isEmptyBean ? View.GONE : View.VISIBLE); + ivGenderTwo.setImageResource(userInfo.getGender() == 1 ? R.drawable.ic_gender_male : R.drawable.ic_gender_female); + + ciTopTwo.setVisibility(isEmptyBean ? View.GONE : View.VISIBLE); + tvLabelTwo.setVisibility(isEmptyBean ? View.GONE : View.VISIBLE); + ivBgTwo.setImageResource(isEmptyBean ? R.drawable.icon_consume_second_empty : R.drawable.icon_consume_second); + tvTwoId.setText(isEmptyBean ? "" : "ID:" + userInfo.getErbanNo()); + tvTwoName.setText(isEmptyBean ? "" : userInfo.getNick()); + tvLabelTwo.setText(String.valueOf(userInfo.getGoldAmount()));// RoomRankDialogUtils.getRoomRankValueText(userInfo.getGoldAmount()) + rlTopTwo.setOnClickListener(isEmptyBean ? null : new View.OnClickListener() { + @Override + public void onClick(View v) { + if (userInfo.isHide()) return; + if (userInfo.isEmptyBean()) return; + if (mRoomConsumerTopThreeListener != null) + mRoomConsumerTopThreeListener.topThreeListener(userInfo.getUid()); + } + }); + } else if (i == 2) { + + if (!TextUtils.isEmpty(userInfo.getAvatar())) + ImageLoadUtils.loadAvatarBig(userInfo.getAvatar(), ciTopThree); + + ivGenderThree.setVisibility(isEmptyBean ? View.GONE : View.VISIBLE); + ivGenderThree.setImageResource(userInfo.getGender() == 1 ? R.drawable.ic_gender_male : R.drawable.ic_gender_female); + + ciTopThree.setVisibility(isEmptyBean ? View.GONE : View.VISIBLE); + tvLabelThree.setVisibility(isEmptyBean ? View.GONE : View.VISIBLE); + ivBgThree.setImageResource(isEmptyBean ? R.drawable.icon_consume_third_empty : R.drawable.icon_consume_third); + tvThreeId.setText(isEmptyBean ? "" : "ID:" + userInfo.getErbanNo()); + tvThreeName.setText(isEmptyBean ? "" : userInfo.getNick()); + tvLabelThree.setText(String.valueOf(userInfo.getGoldAmount())); + rlTopThree.setOnClickListener(isEmptyBean ? null : new View.OnClickListener() { + @Override + public void onClick(View v) { + if (userInfo.isHide()) return; + if (userInfo.isEmptyBean()) return; + if (mRoomConsumerTopThreeListener != null) + mRoomConsumerTopThreeListener.topThreeListener(userInfo.getUid()); + } + }); + } + + + } + } + + } + + } + + private void setLinearData(BaseViewHolder baseViewHolder, RoomRankMultiItem roomConsumeInfo) { + + RoomContributeUserInfo roomContributeUserInfo = (RoomContributeUserInfo) roomConsumeInfo.getData(); + + CircleImageView avatarView = baseViewHolder.getView(R.id.avatar_view); + ImageLoadUtils.loadAvatar(mContext, roomContributeUserInfo.getAvatar(), avatarView); + + AppCompatImageView ivNobleLevel = baseViewHolder.getView(R.id.iv_noble_level); + ivNobleLevel.setVisibility(View.GONE); + + AppCompatImageView ivUserLevel = baseViewHolder.getView(R.id.iv_user_level); + ivUserLevel.setVisibility(View.GONE); + + ImageView numberImage = baseViewHolder.getView(R.id.auction_number_image); + numberImage.setVisibility(View.GONE); + + baseViewHolder.setText(R.id.auction_number_text,roomContributeUserInfo.getRanking()+""); + + baseViewHolder.setGone(R.id.iv_number,true); + setCommonView(baseViewHolder, roomContributeUserInfo); + } + + /** + * 设置共同的部分 + */ + private void setCommonView(BaseViewHolder baseViewHolder, RoomContributeUserInfo roomConsumeInfo) { + String goldAmount = String.valueOf(roomConsumeInfo.getGoldAmount()); + baseViewHolder.setText(R.id.tv_erban_id, "ID:" + roomConsumeInfo.getErbanNo()) + .setImageResource(R.id.iv_sex, + roomConsumeInfo.getGender() == 1 ? R.drawable.ic_gender_male : R.drawable.ic_gender_female) + .setText(R.id.coin_text, goldAmount) + .setText(R.id.tv_nick, RegexUtil.getPrintableString(roomConsumeInfo.getNick())); + } + + public interface RoomConsumerTopThreeListener { + void topThreeListener(long uid); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/RoomContributeListAdapter.java b/app/src/main/java/com/chwl/app/avroom/adapter/RoomContributeListAdapter.java new file mode 100644 index 0000000..7a4c391 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/RoomContributeListAdapter.java @@ -0,0 +1,35 @@ +package com.chwl.app.avroom.adapter; + +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentPagerAdapter; + +import java.util.List; + +/** + * Created by MadisonRong on 25/04/2018. + */ + +public class RoomContributeListAdapter extends FragmentPagerAdapter { + + private List fragmentList; + + public RoomContributeListAdapter(FragmentManager fm, List fragmentList) { + super(fm); + this.fragmentList = fragmentList; + } + + public RoomContributeListAdapter(FragmentManager fm) { + super(fm); + } + + @Override + public Fragment getItem(int position) { + return fragmentList.get(position); + } + + @Override + public int getCount() { + return fragmentList.size(); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/RoomGameListAdapter.kt b/app/src/main/java/com/chwl/app/avroom/adapter/RoomGameListAdapter.kt new file mode 100644 index 0000000..2b3287d4 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/RoomGameListAdapter.kt @@ -0,0 +1,18 @@ +package com.chwl.app.avroom.adapter + +import android.widget.ImageView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.ui.utils.load +import com.chwl.core.room.bean.RoomIcon +import com.chwl.core.room.game.bean.GameInfo + +class RoomGameListAdapter : + BaseQuickAdapter(R.layout.room_gameplay_item2) { + override fun convert(helper: BaseViewHolder, item: GameInfo?) { + helper.setText(R.id.tv_name, item?.name?:"") + val iconView = helper.getView(R.id.iv_icon) + iconView.load(item?.pic2?:"") + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/RoomGameplayAdapter.kt b/app/src/main/java/com/chwl/app/avroom/adapter/RoomGameplayAdapter.kt new file mode 100644 index 0000000..913c104 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/RoomGameplayAdapter.kt @@ -0,0 +1,23 @@ +package com.chwl.app.avroom.adapter + +import android.widget.ImageView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.avroom.bean.RoomGameplayItem +import com.chwl.app.ui.utils.load + +class RoomGameplayAdapter : + BaseQuickAdapter(R.layout.room_gameplay_item2) { + override fun convert(helper: BaseViewHolder, item: RoomGameplayItem?) { + helper.setText(R.id.tv_name, item?.getName()) + val iconView = helper.getView(R.id.iv_icon) + val iconRes = item?.getIconRes() + if (iconRes != null) { + iconView.setImageResource(iconRes) + } else { + val iconUrl = item?.getIconUrl() + iconView.load(iconUrl ?: "") + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/RoomInviteAdapter.java b/app/src/main/java/com/chwl/app/avroom/adapter/RoomInviteAdapter.java new file mode 100644 index 0000000..3efa35d --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/RoomInviteAdapter.java @@ -0,0 +1,246 @@ +package com.chwl.app.avroom.adapter; + +import android.content.Context; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.recyclerview.widget.DiffUtil; +import androidx.recyclerview.widget.RecyclerView; + +import com.chwl.app.R; +import com.chwl.app.avroom.ChatMemberDiffUtilCallback; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.manager.IMNetEaseManager; +import com.chwl.core.manager.RoomEvent; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.library.common.util.OtherExtKt; +import com.chwl.library.utils.ListUtils; +import com.netease.nim.uikit.impl.cache.NimUserInfoCache; +import com.netease.nimlib.sdk.RequestCallbackWrapper; +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMember; +import com.netease.nimlib.sdk.uinfo.constant.GenderEnum; +import com.netease.nimlib.sdk.uinfo.model.NimUserInfo; + +import java.util.ArrayList; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.Objects; + +import io.reactivex.disposables.Disposable; +import io.reactivex.functions.Consumer; + +/** + *

+ * + * @author jiahui + * @date 2017/12/21 + */ +public class RoomInviteAdapter extends RecyclerView.Adapter { + + private List mChatRoomMemberList; + private Context mContext; + private OnItemClickListener mOnItemClickListener; + private LayoutInflater mInflater; + private Disposable mDisposable; + + public RoomInviteAdapter(Context context, OnItemClickListener onItemClickListener) { + mInflater = LayoutInflater.from(context); + mContext = context; + mOnItemClickListener = onItemClickListener; + } + + @Override + public void onAttachedToRecyclerView(RecyclerView recyclerView) { + super.onAttachedToRecyclerView(recyclerView); + mDisposable = IMNetEaseManager.get().getChatRoomEventObservable() + .subscribe(new Consumer() { + @Override + public void accept(RoomEvent roomEvent) throws Exception { + if (roomEvent == null) return; + int event = roomEvent.getEvent(); + if (roomEvent.getEvent() == RoomEvent.ADD_BLACK_LIST || + roomEvent.getEvent() == RoomEvent.DOWN_MIC || + event == RoomEvent.ROOM_MEMBER_EXIT || + roomEvent.getEvent() == RoomEvent.KICK_OUT_ROOM) { + if (ListUtils.isListEmpty(mChatRoomMemberList)) return; + ListIterator iterator = mChatRoomMemberList.listIterator(); + for (; iterator.hasNext(); ) { + ChatRoomMember onlineChatMember = iterator.next(); + if (onlineChatMember != null + && Objects.equals(onlineChatMember.getAccount(), roomEvent.getAccount())) { + iterator.remove(); + } + } + notifyDataSetChanged(); + if (mOnRoomOnlineNumberChangeListener != null) + mOnRoomOnlineNumberChangeListener.onRoomOnlineNumberChange(getItemCount()); + } else if (event == RoomEvent.ROOM_MEMBER_IN) { + updateMemberIn(roomEvent); + } + } + }); + } + + public void onRelease() { + if (mDisposable != null) { + mDisposable.dispose(); + mDisposable = null; + } + } + + private void updateMemberIn(RoomEvent roomEvent) { + ChatRoomMember chatRoomMember = AvRoomDataManager.get().getChatRoomMember(roomEvent.getAccount()); + if (chatRoomMember == null) return; + if (!ListUtils.isListEmpty(mChatRoomMemberList)) { + for (ChatRoomMember temp : mChatRoomMemberList) { + if (Objects.equals(temp.getAccount(), chatRoomMember.getAccount())) + return; + } + } + List list = new ArrayList<>(1); + list.add(chatRoomMember); + addChatRoomMemberList(list); + if (mOnRoomOnlineNumberChangeListener != null) + mOnRoomOnlineNumberChangeListener.onRoomOnlineNumberChange(getItemCount()); + } + + public void addChatRoomMemberList(final List chatRoomMemberList) { + if (ListUtils.isListEmpty(mChatRoomMemberList)) { + mChatRoomMemberList = chatRoomMemberList; + notifyDataSetChanged(); + } else { + mChatRoomMemberList.addAll(chatRoomMemberList); + DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff( + new ChatMemberDiffUtilCallback(mChatRoomMemberList, chatRoomMemberList), true); + diffResult.dispatchUpdatesTo(this); + } + } + + public List getChatRoomMemberList() { + return mChatRoomMemberList; + } + + @Override + public RoomInviteViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return new RoomInviteViewHolder(mInflater.inflate(R.layout.room_invite_list_item_layout, parent, false)); + } + + @Override + public void onBindViewHolder(RoomInviteViewHolder holder, int position) { + + final ChatRoomMember chatRoomMember = mChatRoomMemberList.get(position); + if (chatRoomMember == null) return; + NimUserInfo nimUserInfo = NimUserInfoCache.getInstance().getUserInfo(chatRoomMember.getAccount()); + final ImageView sexImage = holder.sexImage; + if (nimUserInfo == null) { + NimUserInfoCache.getInstance().getUserInfoFromRemote(chatRoomMember.getAccount(), + new RequestCallbackWrapper() { + @Override + public void onResult(int i, NimUserInfo nimUserInfo, Throwable throwable) { + if (nimUserInfo != null) { + if (nimUserInfo.getGenderEnum() == GenderEnum.MALE) { + sexImage.setVisibility(View.VISIBLE); + sexImage.setImageResource(R.drawable.ic_gender_male); + } else if (nimUserInfo.getGenderEnum() == GenderEnum.FEMALE) { + sexImage.setVisibility(View.VISIBLE); + sexImage.setImageResource(R.drawable.ic_gender_female); + } else { + sexImage.setVisibility(View.GONE); + } + } + } + }); + } else { + if (nimUserInfo.getGenderEnum() == GenderEnum.MALE) { + sexImage.setVisibility(View.VISIBLE); + sexImage.setImageResource(R.drawable.ic_gender_male); + } else if (nimUserInfo.getGenderEnum() == GenderEnum.FEMALE) { + sexImage.setVisibility(View.VISIBLE); + sexImage.setImageResource(R.drawable.ic_gender_female); + } else { + sexImage.setVisibility(View.GONE); + } + } + + holder.mViewLine.setVisibility(position == getItemCount() - 1 ? View.GONE : View.VISIBLE); + ImageLoadUtils.loadAvatar(mContext, chatRoomMember.getAvatar(), holder.mIvAvatar); + holder.mTvMemberName.setText(chatRoomMember.getNick()); + + try { + Map map = (Map) chatRoomMember.getExtension().get(chatRoomMember.getAccount()); + String nick = map.get(UserInfo.NICK).toString(); + String avatar = map.get(UserInfo.AVATAR).toString(); + boolean enterHide = (boolean) map.get(UserInfo.ENTER_HIDE); + + if (enterHide) { + holder.mIvAvatar.setImageResource(R.drawable.ic_mystery); + } else { + if (chatRoomMember.getAvatar() == null || TextUtils.isEmpty(chatRoomMember.getAvatar())) { + ImageLoadUtils.loadAvatar(mContext, avatar, holder.mIvAvatar); + } + + CharSequence nickText = holder.mTvMemberName.getText(); + if (!OtherExtKt.isVerify(nickText)){ + if (OtherExtKt.isVerify(nick)) { + holder.mTvMemberName.setText(nick); + } + } + + } + + }catch (Exception e){ + + } + + holder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (mOnItemClickListener != null) + mOnItemClickListener.onClick(chatRoomMember); + } + }); + } + + @Override + public int getItemCount() { + return mChatRoomMemberList != null ? mChatRoomMemberList.size() : 0; + } + + + static class RoomInviteViewHolder extends RecyclerView.ViewHolder { + private ImageView mIvAvatar; + private ImageView sexImage; + private TextView mTvMemberName; + View mViewLine; + + RoomInviteViewHolder(View itemView) { + super(itemView); + mIvAvatar = itemView.findViewById(R.id.iv_avatar); + sexImage = itemView.findViewById(R.id.sex); + mTvMemberName = itemView.findViewById(R.id.tv_member_name); + mViewLine = itemView.findViewById(R.id.view_line); + } + } + + + public interface OnItemClickListener { + void onClick(ChatRoomMember chatRoomMember); + } + + private OnRoomOnlineNumberChangeListener mOnRoomOnlineNumberChangeListener; + + public void setOnRoomOnlineNumberChangeListener(OnRoomOnlineNumberChangeListener listener) { + mOnRoomOnlineNumberChangeListener = listener; + } + + public interface OnRoomOnlineNumberChangeListener { + void onRoomOnlineNumberChange(int number); + } + +} diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/RoomMessageIndicatorAdapter.java b/app/src/main/java/com/chwl/app/avroom/adapter/RoomMessageIndicatorAdapter.java new file mode 100644 index 0000000..ad3784b --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/RoomMessageIndicatorAdapter.java @@ -0,0 +1,106 @@ +package com.chwl.app.avroom.adapter; + +import android.content.Context; +import android.graphics.Color; +import android.view.Gravity; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.TextView; + +import androidx.core.content.ContextCompat; + +import com.chwl.app.R; +import com.chwl.app.ui.widget.XRecyclerView.ScaleTransitionPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.CommonNavigatorAdapter; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.indicators.GradientLineRoundPagerIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.indicators.LinePagerIndicator; + +import java.util.List; + +public class RoomMessageIndicatorAdapter extends CommonNavigatorAdapter { + private final Context mContext; + private final List mTitleList; + + private int textSize = 14; + private float minScale = 1f; + private boolean showIndicator = true; + private OnItemSelectListener mOnItemSelectListener; + + public RoomMessageIndicatorAdapter(Context context, List charSequences) { + this.mContext = context; + this.mTitleList = charSequences; + } + + @Override + public int getCount() { + return mTitleList == null ? 0 : mTitleList.size(); + } + + @Override + public IPagerTitleView getTitleView(Context context, final int i) { + ScaleTransitionPagerTitleView scaleTransitionPagerTitleView = new ScaleTransitionPagerTitleView(context, true); + scaleTransitionPagerTitleView.setNormalColor(ContextCompat.getColor(context, R.color.white_transparent_60)); + scaleTransitionPagerTitleView.setSelectedColor(ContextCompat.getColor(context, R.color.color_FFFFFF)); + scaleTransitionPagerTitleView.setMinScale(minScale); + scaleTransitionPagerTitleView.setTextSize(textSize); + int padding = UIUtil.dip2px(context, 13); + scaleTransitionPagerTitleView.setPadding(padding, 0, padding, 0); + scaleTransitionPagerTitleView.setText(mTitleList.get(i)); + scaleTransitionPagerTitleView.setOnClickListener(view -> { + if (mOnItemSelectListener != null) { + mOnItemSelectListener.onItemSelect(i, scaleTransitionPagerTitleView); + } + + }); + return scaleTransitionPagerTitleView; + } + + @Override + public IPagerIndicator getIndicator(Context context) { + LinePagerIndicator indicator = new LinePagerIndicator(context); + indicator.setMode(LinePagerIndicator.MODE_EXACTLY); + indicator.setLineHeight(UIUtil.dip2px(mContext, 1.5)); + indicator.setRoundRadius(UIUtil.dip2px(mContext, 1)); + indicator.setLineWidth(UIUtil.dip2px(mContext, 8)); + indicator.setColors(context.getResources().getColor(R.color.color_10ECD6)); + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); +// lp.bottomMargin = mBottomMargin; + indicator.setLayoutParams(lp); + return indicator; + } + + public int getTextSize() { + return textSize; + } + + public void setTextSize(int textSize) { + this.textSize = textSize; + } + + public float getMinScale() { + return minScale; + } + + public void setMinScale(float minScale) { + this.minScale = minScale; + } + + public boolean isShowIndicator() { + return showIndicator; + } + + public void setShowIndicator(boolean showIndicator) { + this.showIndicator = showIndicator; + } + + public void setOnItemSelectListener(OnItemSelectListener onItemSelectListener) { + mOnItemSelectListener = onItemSelectListener; + } + + public interface OnItemSelectListener { + void onItemSelect(int position, TextView view); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/RoomNormalListAdapter.java b/app/src/main/java/com/chwl/app/avroom/adapter/RoomNormalListAdapter.java new file mode 100644 index 0000000..df304a2 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/RoomNormalListAdapter.java @@ -0,0 +1,105 @@ +package com.chwl.app.avroom.adapter; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.recyclerview.widget.RecyclerView; + +import com.chwl.app.R; +import com.chwl.app.common.widget.CircleImageView; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.user.UserModel; +import com.chwl.library.common.util.OtherExtKt; +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMember; + +import java.util.List; + + +/** + * Created by chenran on 2017/10/11. + */ + +public class RoomNormalListAdapter extends RecyclerView.Adapter implements View.OnClickListener{ + private Context context; + private List normalList; + private OnRoomNormalListOperationClickListener listOperationClickListener; + + public RoomNormalListAdapter(Context context) { + this.context = context; + } + + public void setNormalList(List normalList) { + this.normalList = normalList; + } + + public List getNormalList() { + return normalList; + } + + public void setListOperationClickListener(OnRoomNormalListOperationClickListener listOperationClickListener) { + this.listOperationClickListener = listOperationClickListener; + } + + @Override + public RoomNormalListHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_room_normal, parent, false); + return new RoomNormalListHolder(view); + } + + @Override + public void onBindViewHolder(RoomNormalListHolder holder, int position) { + ChatRoomMember chatRoomMember = normalList.get(position); + holder.nick.setText(chatRoomMember.getNick()); + holder.operationImg.setTag(chatRoomMember); + holder.operationImg.setOnClickListener(this); + ImageLoadUtils.loadAvatar(context, chatRoomMember.getAvatar(), holder.avatar); + + + if (UserModel.get().getCacheLoginUserInfo() != null && UserModel.get().getCacheLoginUserInfo().isSuperAdmin()) { + OtherExtKt.setVis(holder.operationImg, false, false); + } else { + OtherExtKt.setVis(holder.operationImg,true,false); + } + } + + @Override + public int getItemCount() { + if (normalList == null) { + return 0; + } else { + return normalList.size(); + } + } + + @Override + public void onClick(View v) { + if (v.getTag() != null && v.getTag() instanceof ChatRoomMember) { + ChatRoomMember chatRoomMember = (ChatRoomMember) v.getTag(); + if (listOperationClickListener != null) { + listOperationClickListener.onRemoveOperationClick(chatRoomMember); + } + } + } + + public class RoomNormalListHolder extends RecyclerView.ViewHolder { + private CircleImageView avatar; + private TextView nick; + private TextView erbanNo; + private TextView operationImg; + + public RoomNormalListHolder(View itemView) { + super(itemView); + avatar = (CircleImageView) itemView.findViewById(R.id.avatar); + nick = (TextView) itemView.findViewById(R.id.nick); + erbanNo = (TextView) itemView.findViewById(R.id.erban_no); + operationImg = (TextView) itemView.findViewById(R.id.remove_opration); + } + } + + public interface OnRoomNormalListOperationClickListener { + void onRemoveOperationClick(ChatRoomMember chatRoomMember); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/RoomRankFragmentPageAdapter.java b/app/src/main/java/com/chwl/app/avroom/adapter/RoomRankFragmentPageAdapter.java new file mode 100644 index 0000000..9d41f98 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/RoomRankFragmentPageAdapter.java @@ -0,0 +1,27 @@ +package com.chwl.app.avroom.adapter; + +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentPagerAdapter; + +import java.util.List; + +public class RoomRankFragmentPageAdapter extends FragmentPagerAdapter { + + private List fragmentList; + + public RoomRankFragmentPageAdapter(FragmentManager fm, List fragmentList) { + super(fm); + this.fragmentList = fragmentList; + } + + @Override + public Fragment getItem(int position) { + return fragmentList.get(position); + } + + @Override + public int getCount() { + return fragmentList.size(); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/RoomRankHalfHourListAdapter.java b/app/src/main/java/com/chwl/app/avroom/adapter/RoomRankHalfHourListAdapter.java new file mode 100644 index 0000000..dc03acc --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/RoomRankHalfHourListAdapter.java @@ -0,0 +1,63 @@ +package com.chwl.app.avroom.adapter; + +import android.content.Context; +import android.widget.TextView; + +import com.chad.library.adapter.base.BaseMultiItemQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.app.avroom.fragment.RoomRankDialogUtils; +import com.chwl.app.common.widget.CircleImageView; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.room.bean.RoomRankHalfHourRankInfo; +import com.chwl.core.room.bean.RoomRankMultiItem; + +import java.util.ArrayList; + +public class RoomRankHalfHourListAdapter extends BaseMultiItemQuickAdapter { + + public final static int TYPE_TIPS = 4; + + public RoomRankHalfHourListAdapter(Context context) { + super(new ArrayList<>()); + addItemType(RoomRankMultiItem.TYPE_LINEAR, R.layout.item_room_rank_layout); + addItemType(RoomRankMultiItem.TYPE_EMPTY, R.layout.item_empty_list); + addItemType(TYPE_TIPS, R.layout.item_rank_half_tips); + } + + @Override + protected void convert(BaseViewHolder baseViewHolder, RoomRankMultiItem roomConsumeInfo) { + if (roomConsumeInfo == null) { + return; + } + if (roomConsumeInfo.getItemType() == RoomRankMultiItem.TYPE_LINEAR) { + setLinearData(baseViewHolder, roomConsumeInfo); + } else if (roomConsumeInfo.getItemType() == RoomRankMultiItem.TYPE_EMPTY) { + + } + } + + private void setLinearData(BaseViewHolder baseViewHolder, RoomRankMultiItem roomConsumeInfo) { + if (roomConsumeInfo == null) { + return; + } + + RoomRankHalfHourRankInfo roomRankHalfHourRankInfo = (RoomRankHalfHourRankInfo) roomConsumeInfo.getData(); + if (roomRankHalfHourRankInfo == null) + return; + + // 值 + TextView valueTV = baseViewHolder.getView(R.id.tv_room_rank_value); + valueTV.setText(RoomRankDialogUtils.getRoomRankValueText(roomRankHalfHourRankInfo.getTotalNum())); + + int drawable = RoomRankDialogUtils.getNumberImage(roomRankHalfHourRankInfo.getSeqNo()); + if (drawable != 0) + baseViewHolder.setImageResource(R.id.iv_number, drawable); + // 标题 + baseViewHolder.setText(R.id.tv_room_rank_title, roomRankHalfHourRankInfo.getRoomTitle()); + // 头像 + CircleImageView avatarView = baseViewHolder.getView(R.id.iv_room_rank_avatar); + ImageLoadUtils.loadAvatar(roomRankHalfHourRankInfo.getAvatar(),avatarView); + baseViewHolder.setText(R.id.tv_room_rank_id, "ID:" + roomRankHalfHourRankInfo.getErbanNo()); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/RoomVPAdapter.java b/app/src/main/java/com/chwl/app/avroom/adapter/RoomVPAdapter.java new file mode 100644 index 0000000..0f81213 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/RoomVPAdapter.java @@ -0,0 +1,31 @@ +package com.chwl.app.avroom.adapter; + +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentPagerAdapter; + +import java.util.List; + +/** + * Created by MadisonRong on 25/04/2018. + */ + +public class RoomVPAdapter extends FragmentPagerAdapter { + + private List fragmentList; + + public RoomVPAdapter(FragmentManager fm, List fragmentList) { + super(fm,FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT); + this.fragmentList = fragmentList; + } + + @Override + public Fragment getItem(int position) { + return fragmentList.get(position); + } + + @Override + public int getCount() { + return fragmentList.size(); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/SendBroadcastAdapter.kt b/app/src/main/java/com/chwl/app/avroom/adapter/SendBroadcastAdapter.kt new file mode 100644 index 0000000..aa4e236 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/SendBroadcastAdapter.kt @@ -0,0 +1,14 @@ +package com.chwl.app.avroom.adapter + +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R + +class SendBroadcastAdapter : + BaseQuickAdapter(R.layout.item_send_broadcast) { + + override fun convert(helper: BaseViewHolder, item: String) { + helper.setText(R.id.tv_content, item) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/SingleAnchorMicroViewAdapter.kt b/app/src/main/java/com/chwl/app/avroom/adapter/SingleAnchorMicroViewAdapter.kt new file mode 100644 index 0000000..9a555fa --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/SingleAnchorMicroViewAdapter.kt @@ -0,0 +1,94 @@ +package com.chwl.app.avroom.adapter + +import android.annotation.SuppressLint +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.view.updateLayoutParams +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.opensource.svgaplayer.SVGAImageView +import com.chwl.app.R +import com.chwl.core.bean.RoomQueueInfo + +/** + * @author xiaoyu + * @date 2017/12/18 + */ +class SingleAnchorMicroViewAdapter(context: Context?) : BaseMicroViewAdapter(context) { + + /** + * Set LayoutManager and bind this to RecyclerView + */ + override fun bindToRecyclerView(recyclerView: RecyclerView) { + val layoutManager = + object : GridLayoutManager(context, 3) { + override fun canScrollHorizontally(): Boolean { + return false + } + } + layoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() { + override fun getSpanSize(position: Int): Int { + return if (position == 0) 3 else 1 + } + } + recyclerView.layoutManager = layoutManager + recyclerView.adapter = this + } + + override fun getItemCount() = 4 + + override fun microType() = MICRO_TYPE_SINGLE + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + return if (viewType == TYPE_BOSS) { + SingleAnchorBossMicroViewHolder( + LayoutInflater.from(parent.context) + .inflate(R.layout.item_micro_single_anchor_boss, parent, false) + ) + } else { + SingleAnchorMicroViewHolder( + LayoutInflater.from(parent.context) + .inflate(R.layout.item_micro_single_anchor, parent, false) + ) + } + } + + override fun getItemViewType(position: Int) = if (position == 0) TYPE_BOSS else TYPE_NORMAL + + private inner class SingleAnchorMicroViewHolder constructor(itemView: View) : + BasicMicroViewHolder(itemView) { + + @SuppressLint("SetTextI18n") + public override fun bind(info: RoomQueueInfo, position: Int) { + itemView.findViewById(R.id.micro_layout) + .updateLayoutParams { + horizontalBias = when (position) { + 0 -> 0.85f + 2 -> 0.15f + else -> 0.5f + } + } + super.bind(info, position) + } + + override fun setDefalutText(index: Int) { + tvNick.text = "" + } + } + + + inner class SingleAnchorBossMicroViewHolder internal constructor(itemView: View) : + BossMicroViewHolder(itemView) { + + public override fun bind(info: RoomQueueInfo, position: Int) { + itemView.findViewById(R.id.svga_head_wear)?.let { + it.visibility = View.VISIBLE + it.startAnimation() + } + super.bind(info, position) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/SingleRoomPKMicroViewAdapter.kt b/app/src/main/java/com/chwl/app/avroom/adapter/SingleRoomPKMicroViewAdapter.kt new file mode 100644 index 0000000..e91713b --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/SingleRoomPKMicroViewAdapter.kt @@ -0,0 +1,120 @@ +package com.chwl.app.avroom.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import androidx.core.view.isGone +import androidx.core.view.isVisible +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.chwl.app.R +import com.chwl.app.common.widget.CircleImageView +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.core.bean.RoomQueueInfo +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.praise.PraiseModel +import com.chwl.core.utils.extension.toast +import com.chwl.library.utils.ResUtil +import com.chwl.library.utils.config.BasicConfig + + +class SingleRoomPKMicroViewAdapter(context: Context?) : BaseMicroViewAdapter(context) { + + private var isAttention: Boolean = false + + + /** + * Set LayoutManager and bind this to RecyclerView + */ + override fun bindToRecyclerView(recyclerView: RecyclerView) { + val layoutManager = LinearLayoutManager(context) + recyclerView.layoutManager = layoutManager + recyclerView.adapter = this + } + + override fun getItemCount() = 1 + + override fun microType() = MICRO_TYPE_SINGLE + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + return SingleAnchorBossMicroViewHolder( + LayoutInflater.from(parent.context) + .inflate(R.layout.item_micro_single_room_pk_boss, parent, false) + ) + } + + inner class SingleAnchorBossMicroViewHolder internal constructor(itemView: View) : + GiftValueViewHolder(itemView) { + + private val tvLabelLeaveMode: TextView = itemView.findViewById(R.id.tv_label_leave_mode) + private val ivLeaveMode: CircleImageView = itemView.findViewById(R.id.iv_bg_leave_mode) + private val ivAttention: ImageView = itemView.findViewById(R.id.iv_attention) + private val ivPkResult: ImageView = itemView.findViewById(R.id.iv_pk_result) + + public override fun bind(info: RoomQueueInfo, position: Int) { + super.bind(info, position) + + // 新版房主位优先判断麦序是否有人,麦序没人再判断是否是离开模式(防止新版展示离开模式,实际麦位有人) + val chatRoomMember = info.mChatRoomMember + val roomInfo = AvRoomDataManager.get().mCurrentRoomInfo + if (chatRoomMember == null) { + if (roomInfo?.isLeaveMode == true || AvRoomDataManager.get().isSingleRoom) { + tvLabelLeaveMode.visibility = View.VISIBLE + ivLeaveMode.visibility = View.VISIBLE + ImageLoadUtils.loadDefaultImage( + BasicConfig.INSTANCE.appContext, + ivLeaveMode, + R.drawable.bg_leave_mode + ) + ivAvatar.visibility = View.VISIBLE + ivLockImage.visibility = View.INVISIBLE + ivUpImage.visibility = View.INVISIBLE + val avRoomDataManager = AvRoomDataManager.get() + ImageLoadUtils.loadAvatar( + BasicConfig.INSTANCE.appContext, + avRoomDataManager.avatar, + ivAvatar + ) + setSelectText(-1, avRoomDataManager.nick, avRoomDataManager.gender) + } else { + ivLeaveMode.visibility = View.GONE + tvLabelLeaveMode.visibility = View.GONE + } + } else { + ivLeaveMode.visibility = View.GONE + tvLabelLeaveMode.visibility = View.GONE + } + + val roomPkBean = AvRoomDataManager.get().roomPkLiveData.value + if (roomPkBean == null || roomPkBean.pkState == 1) { + ivPkResult.isVisible = false + } else if (roomPkBean.winUid == 0L) { + ivPkResult.isVisible = true + ivPkResult.setImageResource(R.drawable.single_room_pk_ic_result_deuce) + } else if (roomPkBean.winUid == roomPkBean.cUid) { + ivPkResult.isVisible = true + ivPkResult.setImageResource(R.drawable.single_room_pk_ic_result_win) + } else { + ivPkResult.isVisible = true + ivPkResult.setImageResource(R.drawable.single_room_pk_ic_result_failed) + } + + val roomUid = AvRoomDataManager.get().roomUid + ivAttention.isGone = PraiseModel.get().isPraised(roomUid) || AvRoomDataManager.get().isRoomOwner + ivAttention.setOnClickListener { + ivAttention.isVisible = false + PraiseModel.get().praise(roomUid, !PraiseModel.get().isPraised(roomUid)) + .doOnSuccess { ResUtil.getString(R.string.avroom_adapter_singleroompkmicroviewadapter_01).toast() } + .doOnError { + ivAttention.isVisible = true + it?.message.toast() + } + .subscribe() + } + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/adapter/UpMicAdapter.java b/app/src/main/java/com/chwl/app/avroom/adapter/UpMicAdapter.java new file mode 100644 index 0000000..86e1eed --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/adapter/UpMicAdapter.java @@ -0,0 +1,105 @@ +package com.chwl.app.avroom.adapter; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.widget.ImageView; +import android.widget.TextView; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.core.Constants; +import com.chwl.core.bean.RoomQueueInfo; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.library.utils.ResUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +import io.reactivex.Single; +import io.reactivex.functions.Consumer; + +/** + * Created by huangmeng1 on 2018/7/27. + * modify by lvzebiao on 2018/11/14. + */ + +public class UpMicAdapter extends BaseQuickAdapter { + + private Context context; + + private Consumer consumer; + + private long upUid; + + public UpMicAdapter(Context context, long upUid, Consumer consumer) { + super(R.layout.item_user_card_up_mic); + this.context = context; + this.consumer = consumer; + this.upUid = upUid; + List list = new ArrayList<>(); + int size; + size = AvRoomDataManager.get().getMicSize(); +// if (AvRoomDataManager.get().isCpRoom()) { +// size = 2; +// } else if (AvRoomDataManager.get().isSingleRoom()) { +// size = 4; +// } else if (AvRoomDataManager.get().isHomeParty()) { +// size = 9; +// }else if (AvRoomDataManager.get().isPartyRoom()) { +// size = 10; +// } else if (AvRoomDataManager.get().isRevelryRoom()) { +// size = 15; +// }else if (AvRoomDataManager.get().is19Room()) { +// size = 19; +// } else if (AvRoomDataManager.get().is20Room()) { +// size = 20; +// } else { +// size = 9; +// } + for (int i = 0; i < size; i++) { + list.add(""); + } + setNewData(list); + } + + @SuppressLint("SetTextI18n") + @Override + protected void convert(BaseViewHolder helper, String item) { + int position = helper.getAdapterPosition(); + RoomQueueInfo roomQueueInfo = AvRoomDataManager.get().getRoomQueueMemberInfoByMicPosition(position - 1); + if (roomQueueInfo == null) return; + + ImageView imageView = helper.getView(R.id.iv_mic); + //xxx 19麦房间时 老板麦位特殊特殊图标 待更换 + //麦上没人,且不是离开模式房主位,相亲模式的管理才能上房主位 + if (roomQueueInfo.mChatRoomMember == null + && (!AvRoomDataManager.get().isLeaveMode() || position != 0) + && (!AvRoomDataManager.get().isDatingMode() || AvRoomDataManager.get().isManager(String.valueOf(upUid)) || position != 0)) { + imageView.setImageResource((position == AvRoomDataManager.ITEM_POS_19_ROOM_BOSS && AvRoomDataManager.get().is19Room()) ? R.drawable.icon_room_up_micro_king : R.drawable.icon_up_mic_ture); + helper.itemView.setClickable(true); + helper.itemView.setOnClickListener(v -> Single.just(position).subscribe(consumer)); + } else { + imageView.setImageResource(R.drawable.icon_up_mic_false); + helper.itemView.setClickable(false); + } + + TextView textView = helper.getView(R.id.tv_pos); + if (position == 0) { + if (AvRoomDataManager.get().isHomeParty()) { + textView.setText(ResUtil.getString(R.string.avroom_adapter_upmicadapter_02)); + } else if (AvRoomDataManager.get().isDatingMode()) { + textView.setText(ResUtil.getString(R.string.avroom_adapter_upmicadapter_01)); + } else { + textView.setText(String.format(Locale.US,context.getResources().getString(R.string.which_mic_position), position+1)); + } + } else { + if (AvRoomDataManager.get().isDatingMode()) { + textView.setText(position + (Constants.maleIndex.contains(position - 1) ? ResUtil.getString(R.string.avroom_adapter_upmicadapter_03) : ResUtil.getString(R.string.avroom_adapter_upmicadapter_04))); + } else { + textView.setText(String.format(Locale.US,context.getResources().getString(R.string.which_mic_position), position+1)); + } + } + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPKBoardView.kt b/app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPKBoardView.kt new file mode 100644 index 0000000..a989a71 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPKBoardView.kt @@ -0,0 +1,200 @@ +package com.chwl.app.avroom.anotherroompk + +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.util.AttributeSet +import android.view.Gravity +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.FrameLayout +import android.widget.PopupWindow +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.view.isVisible +import androidx.core.view.marginBottom +import androidx.core.view.updateLayoutParams +import androidx.lifecycle.Observer +import com.netease.nim.uikit.common.util.sys.ScreenUtil +import com.netease.nim.uikit.common.util.sys.TimeUtil +import com.chwl.app.R +import com.chwl.app.avroom.activity.AVRoomActivity +import com.chwl.app.databinding.LayoutRoomPkBoardViewBinding +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.core.im.custom.bean.RoomPkBean +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.room.anotherroompk.ShowGiftDialogEvent +import com.chwl.core.room.anotherroompk.ShowUserInfoDialogEvent +import com.chwl.core.utils.CurrentTimeUtils +import com.chwl.core.utils.extension.subAndReplaceDot +import com.chwl.library.rxbus.RxBus +import com.chwl.library.utils.CommonUtils +import com.chwl.library.utils.ResUtil +import com.chwl.library.widget.drag.ViewDragLayout +import com.example.lib_utils.UiUtils +import io.reactivex.Observable +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import java.util.concurrent.TimeUnit + +class RoomPKBoardView @JvmOverloads constructor( + context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 +) : ViewDragLayout(context, attrs, defStyleAttr) { + + private val binding = LayoutRoomPkBoardViewBinding.inflate(LayoutInflater.from(context)) + private val observer = Observer { updateView(it) } + private var disposable: Disposable? = null + private lateinit var helpPopupWindow: PopupWindow + private var roomPkBean: RoomPkBean? = null + + init { + addView( + binding.root, + FrameLayout.LayoutParams( + context.resources.getDimensionPixelOffset(R.dimen.dp_309), + ViewGroup.LayoutParams.WRAP_CONTENT + ).apply { + this.gravity = Gravity.CENTER + this.setMargins(0, 0, 0, UiUtils.dip2px(50f)) + } + ) + //注意这里需要先改变Style,再订阅数据 + binding.viewRankListCharmLeft.showCharmStyle() + binding.viewRankListCharmRight.showCharmStyle() + AvRoomDataManager.get().roomPkLiveData.observeForever(observer) + binding.ivDetails.setOnClickListener { + if (CommonUtils.isFastDoubleClick(500)) return@setOnClickListener + binding.groupRank.isVisible = !binding.groupRank.isVisible + if (binding.groupRank.isVisible) { + binding.ivBg.setImageResource(R.drawable.room_pk_bg_full) + binding.ivBg.updateLayoutParams { + width = ViewGroup.LayoutParams.MATCH_PARENT + height = context.resources.getDimensionPixelOffset(R.dimen.dp_285) + } + } else { + binding.ivBg.setImageResource(R.drawable.room_pk_bg_small) + binding.ivBg.updateLayoutParams { + width = ViewGroup.LayoutParams.MATCH_PARENT + height = context.resources.getDimensionPixelOffset(R.dimen.dp_130) + } + } + binding.ivDetails.animate().rotationBy(180f).start() + } + binding.ivHelp.setOnClickListener { showHelpPopup() } + + binding.ivAvatarLeft.setOnClickListener { + roomPkBean?.let { + RxBus.get().post(ShowUserInfoDialogEvent(it.cUid.toString())) + } + } + + binding.ivAvatarRight.setOnClickListener { + roomPkBean?.let { + RxBus.get().post(ShowUserInfoDialogEvent(it.aUid.toString())) + } + } + + binding.tvGoAnotherRoom.setOnClickListener { + roomPkBean?.let { + AVRoomActivity.start(context, it.aUid) + } + } + + binding.tvSendGift.setOnClickListener { + RxBus.get().post(ShowGiftDialogEvent()) + } + + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + AvRoomDataManager.get().roomPkLiveData.removeObserver(observer) + disposable?.dispose() + } + + @SuppressLint("SetTextI18n") + private fun updateView(roomPkBean: RoomPkBean?) { + this.roomPkBean = roomPkBean + binding.tvRoomNameLeft.text = roomPkBean?.cTitle.subAndReplaceDot(7) + ImageLoadUtils.loadImage( + context, + roomPkBean?.cAvatar, + binding.ivAvatarLeft, + R.drawable.default_avatar + ) + binding.viewRankListCharmLeft.updateData(roomPkBean?.crRank) + binding.viewRankListContributeLeft.updateData(roomPkBean?.csRank) + + binding.tvRoomNameRight.text = roomPkBean?.aTitle.subAndReplaceDot(7) + ImageLoadUtils.loadImage( + context, + roomPkBean?.aAvatar, + binding.ivAvatarRight, + R.drawable.default_avatar + ) + binding.viewRankListCharmRight.updateData(roomPkBean?.arRank) + binding.viewRankListContributeRight.updateData(roomPkBean?.asRank) + binding.pbScore.progress = ((roomPkBean?.cPercent ?: 0.5f) * 100).toInt() + binding.pbScore.post { + val progress = binding.pbScore.width * (roomPkBean?.cPercent ?: 0.5f) + var bias = + (progress - binding.svgaHot.width / 2f) / (binding.pbScore.width - binding.svgaHot.width) + val layoutParams = binding.svgaHot.layoutParams as ConstraintLayout.LayoutParams + bias = 1f.coerceAtMost(bias) + bias = 0f.coerceAtLeast(bias) + layoutParams.horizontalBias = bias + binding.svgaHot.layoutParams = layoutParams + } + + binding.tvScoreLeft.text = "${roomPkBean?.cAmount ?: 0}" + binding.tvScoreRight.text = "${roomPkBean?.aAmount ?: 0}" + disposable?.dispose() + disposable = Observable.interval(1, TimeUnit.SECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { _ -> + roomPkBean?.endTime?.let { + val remainTime = (it - CurrentTimeUtils.getCurrentTime()).toInt() / 1000 + binding.tvTime.setTextColor(Color.parseColor(if (remainTime <= 30) "#FFF17D" else "#ffffff")) + if (remainTime > 0) { + binding.tvTime.text = TimeUtil.secToTime(remainTime) + } else { + binding.tvTime.text = + ResUtil.getString(R.string.layout_layout_room_pk_board_view_02) + } + } ?: let { + binding.tvTime.text = "00:00" + } + } + } + + private fun showHelpPopup() { + val contentView: View + if (!this::helpPopupWindow.isInitialized) { + contentView = + LayoutInflater.from(context).inflate(R.layout.layout_room_pk_help_view, null) + helpPopupWindow = + PopupWindow( + contentView, + resources.getDimensionPixelOffset(R.dimen.dp_209), + ViewGroup.LayoutParams.WRAP_CONTENT + ) + helpPopupWindow.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + helpPopupWindow.isOutsideTouchable = true + helpPopupWindow.isFocusable = true + } + + try { + helpPopupWindow.showAsDropDown( + binding.ivHelp, + 0, + ScreenUtil.dip2px(7f), + Gravity.END or Gravity.BOTTOM + ) + } catch (e: Exception) { + e.printStackTrace() + } + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPKCreateActivity.kt b/app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPKCreateActivity.kt new file mode 100644 index 0000000..8bf2c0a --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPKCreateActivity.kt @@ -0,0 +1,143 @@ +package com.chwl.app.avroom.anotherroompk + +import android.annotation.SuppressLint +import android.content.Context +import android.content.Intent +import android.text.Editable +import android.view.Gravity +import android.view.WindowManager +import androidx.core.view.isVisible +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.databinding.ActivityRoomPkCreateBinding +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.app.ui.widget.TextWatcherSimple +import com.chwl.core.auth.AuthModel +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.room.anotherroompk.RoomPKModel +import com.chwl.core.room.anotherroompk.SimpleRoomInfo +import com.chwl.core.utils.extension.ifNotNullOrEmpty +import com.chwl.core.utils.extension.subAndReplaceDot +import com.chwl.core.utils.extension.toIntOrDef +import com.chwl.core.utils.extension.toast +import com.chwl.library.utils.ResUtil + +class RoomPKCreateActivity : BaseViewBindingActivity() { + + companion object { + @JvmStatic + fun start(context: Context) { + val starter = Intent(context, RoomPKCreateActivity::class.java) + context.startActivity(starter) + } + } + + private var currSimpleRoomInfo: SimpleRoomInfo? = null + + private var pkTime: Int = 10 + + @SuppressLint("CheckResult") + override fun init() { + window.setLayout( + WindowManager.LayoutParams.MATCH_PARENT, + WindowManager.LayoutParams.WRAP_CONTENT, + ) + window.setGravity(Gravity.BOTTOM) + binding.ivHelp.setOnClickListener { + RoomPkRuleDialog.newInstance().show(this) + } + + binding.ivAddPkRoom.setOnClickListener { + RoomPKSearchActivity.start(this) + } + binding.ivDelPkRoom.setOnClickListener { + binding.ivAddPkRoom.isVisible = true + binding.llPkRoom.isVisible = false + currSimpleRoomInfo = null + checkCommitEnable() + } + + binding.rbMin10.setOnCheckedChangeListener { _, isChecked -> + if (isChecked) { + pkTime = 10 + binding.editTime.setText("") + checkCommitEnable() + } + } + binding.rbMin20.setOnCheckedChangeListener { _, isChecked -> + if (isChecked) { + pkTime = 20 + binding.editTime.setText("") + checkCommitEnable() + } + } + binding.rbMin30.setOnCheckedChangeListener { _, isChecked -> + if (isChecked) { + pkTime = 30 + binding.editTime.setText("") + checkCommitEnable() + } + } + + binding.editTime.addTextChangedListener(object : TextWatcherSimple() { + + override fun afterTextChanged(s: Editable?) { + s?.toString().ifNotNullOrEmpty { + pkTime = it.toIntOrDef(0) + if (pkTime != 0) { + binding.rg.clearCheck() + } + checkCommitEnable() + } + } + }) + + binding.tvOk.setOnClickListener { + if (pkTime < 5 || pkTime > 180) { + ResUtil.getString(R.string.avroom_anotherroompk_roompkcreateactivity_01).toast() + return@setOnClickListener + } + currSimpleRoomInfo?.let { + RoomPKModel.initiateRoomPK( + it.roomUid, + pkTime, + AvRoomDataManager.get().roomUid, + AuthModel.get().currentUid, + binding.editDesc.text?.toString() + ) + .compose(bindToLifecycle()) + .subscribe( + { + ResUtil.getString(R.string.avroom_anotherroompk_roompkcreateactivity_02).toast() + finish() + }, { throwable -> + dialogManager.showTipsDialog(throwable.message, null) + } + ) + } + + } + + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (resultCode == RESULT_OK && requestCode == RoomPKSearchActivity.REQUEST_CODE) { + (data?.getSerializableExtra(RoomPKSearchActivity.KEY_ROOM_INFO) as? SimpleRoomInfo)?.let { + currSimpleRoomInfo = it + binding.ivAddPkRoom.isVisible = false + binding.llPkRoom.isVisible = true + ImageLoadUtils.loadImage(this, it.avatar, binding.ivAvatar) + binding.tvRoomTitle.text = it.title.subAndReplaceDot(7) + binding.tvRoomId.text = "ID:${it.erbanNo}" + checkCommitEnable() + } + } + } + + private fun checkCommitEnable(): Boolean { + val isEnabled = currSimpleRoomInfo != null && pkTime != 0 + binding.tvOk.isEnabled = isEnabled + return isEnabled + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPKRankListView.kt b/app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPKRankListView.kt new file mode 100644 index 0000000..bd219d1 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPKRankListView.kt @@ -0,0 +1,63 @@ +package com.chwl.app.avroom.anotherroompk + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.widget.FrameLayout +import androidx.core.view.isGone +import androidx.core.view.isInvisible +import androidx.core.view.isVisible +import com.chwl.app.R +import com.chwl.app.databinding.LayoutRoomPkRankListViewBinding +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.core.im.custom.bean.RoomPkBean +import com.chwl.core.room.anotherroompk.ShowUserInfoDialogEvent +import com.chwl.library.rxbus.RxBus + +class RoomPKRankListView @JvmOverloads constructor( + context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 +) : FrameLayout(context, attrs, defStyleAttr) { + + private val binding = LayoutRoomPkRankListViewBinding.inflate(LayoutInflater.from(context)) + private val tvValues = arrayOf(binding.tvValue1, binding.tvValue2, binding.tvValue3) + private val ivAvatars = arrayOf(binding.ivAvatar1, binding.ivAvatar2, binding.ivAvatar3) + + init { + addView(binding.root) + ivAvatars.forEach { ivAvatar -> + ivAvatar.setOnClickListener { + ivAvatar.tag?.toString()?.let { + RxBus.get().post(ShowUserInfoDialogEvent(it)) + } + } + } + } + + fun showCharmStyle() { + binding.tvValue1.setBackgroundResource(R.drawable.bg_room_pk_charm) + binding.tvValue2.setBackgroundResource(R.drawable.bg_room_pk_charm) + binding.tvValue3.setBackgroundResource(R.drawable.bg_room_pk_charm) + binding.ivAvatarSeat1.setImageResource(R.drawable.room_pk_ic_seat_charm) + binding.ivAvatarSeat2.setImageResource(R.drawable.room_pk_ic_seat_charm) + binding.ivAvatarSeat3.setImageResource(R.drawable.room_pk_ic_seat_charm) + } + + fun updateData(data: List?) { + for (i in tvValues.indices) { + val rankBean = data?.getOrNull(i) + tvValues[i].text = rankBean?.amount ?: "0" + tvValues[i].isGone = "0" == tvValues[i].text + if (rankBean?.avatar.isNullOrEmpty()) { + ivAvatars[i].isInvisible = true + } else { + ivAvatars[i].isVisible = true + ImageLoadUtils.loadImage( + context, + rankBean?.avatar, + ivAvatars[i], R.drawable.default_avatar + ) + } + ivAvatars[i].tag = rankBean?.uid + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPKSearchActivity.kt b/app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPKSearchActivity.kt new file mode 100644 index 0000000..cb37d91 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPKSearchActivity.kt @@ -0,0 +1,105 @@ +package com.chwl.app.avroom.anotherroompk + +import android.annotation.SuppressLint +import android.app.Activity +import android.content.Intent +import android.view.Gravity +import android.view.WindowManager +import android.widget.CheckBox +import androidx.recyclerview.widget.LinearLayoutManager +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.common.EmptyViewHelper +import com.chwl.app.databinding.ActivityRoomPkSearchBinding +import com.chwl.app.ui.user.activity.UserInfoActivity +import com.chwl.app.ui.utils.RVDelegate +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.room.anotherroompk.RoomPKModel +import com.chwl.core.room.anotherroompk.SimpleRoomInfo +import com.chwl.core.utils.extension.toast +import com.chwl.library.utils.ResUtil + +class RoomPKSearchActivity : BaseViewBindingActivity() { + + companion object { + + const val REQUEST_CODE = 0xffaa + const val KEY_ROOM_INFO = "SimpleRoomInfo" + + @JvmStatic + fun start(context: Activity) { + val starter = Intent(context, RoomPKSearchActivity::class.java) + context.startActivityForResult(starter, REQUEST_CODE) + } + } + + private lateinit var rvDelegate: RVDelegate + private var pageNum = 1 + private val pageSize = 20 + private val roomPKSearchAdapter = RoomPKSearchAdapter() + private var searchKey: String? = null + private var currRoomInfo: SimpleRoomInfo? = null + override fun init() { + + window.setLayout( + WindowManager.LayoutParams.MATCH_PARENT, + WindowManager.LayoutParams.WRAP_CONTENT + ) + window.setGravity(Gravity.BOTTOM) + + rvDelegate = RVDelegate.Builder() + .setPageSize(pageSize) + .setEmptyView(EmptyViewHelper.createEmptyTextView(this, ResUtil.getString(R.string.avroom_anotherroompk_roompksearchactivity_01))) + .setLayoutManager(LinearLayoutManager(this)) + .setRecyclerView(binding.recyclerView) + .setAdapter(roomPKSearchAdapter) + .build() + + roomPKSearchAdapter.setOnLoadMoreListener({ loadData(false) }, binding.recyclerView) + + roomPKSearchAdapter.setOnItemChildClickListener { _, view, position -> + roomPKSearchAdapter.getItem(position)?.let { + when (view.id) { + R.id.iv_avatar -> UserInfoActivity.Companion.start(this, it.roomUid) + R.id.check_box -> { + val isChecked = (view as CheckBox).isChecked + roomPKSearchAdapter.data.forEach { roomInfo -> + roomInfo.checked = it.roomUid == roomInfo.roomUid && isChecked + } + binding.tvOk.isEnabled = isChecked + currRoomInfo = if (isChecked) it else null + roomPKSearchAdapter.notifyDataSetChanged() + } + } + } + } + + binding.ivBack.setOnClickListener { finish() } + binding.tvOk.setOnClickListener { + if (currRoomInfo == null) { + ResUtil.getString(R.string.avroom_anotherroompk_roompksearchactivity_02).toast() + return@setOnClickListener + } + setResult(RESULT_OK, Intent().putExtra(KEY_ROOM_INFO, currRoomInfo)) + finish() + } + + binding.ivSearch.setOnClickListener { + searchKey = binding.editSearch.text?.toString() + loadData(true) + } + loadData(true) + } + + @SuppressLint("CheckResult") + private fun loadData(isRefresh: Boolean) { + pageNum = if (isRefresh) 1 else pageNum + 1 + RoomPKModel.searchPermitRoom(searchKey, AvRoomDataManager.get().roomUid, pageNum, pageSize) + .compose(bindToLifecycle()) + .subscribe({ + rvDelegate.loadData(it, isRefresh) + }, { + rvDelegate.loadErr(isRefresh) + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPKSearchAdapter.kt b/app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPKSearchAdapter.kt new file mode 100644 index 0000000..2c98f77 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPKSearchAdapter.kt @@ -0,0 +1,20 @@ +package com.chwl.app.avroom.anotherroompk + +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.core.room.anotherroompk.SimpleRoomInfo +import com.chwl.core.utils.extension.subAndReplaceDot + +class RoomPKSearchAdapter : + BaseQuickAdapter(R.layout.item_room_pk_search) { + + override fun convert(helper: BaseViewHolder, item: SimpleRoomInfo) { + helper.setText(R.id.tv_room_title,item.title.subAndReplaceDot(7)) + .setText(R.id.tv_room_id,"ID:${item.erbanNo}") + .setChecked(R.id.check_box,item.checked) + ImageLoadUtils.loadImage(mContext,item.avatar,helper.getView(R.id.iv_avatar)) + helper.addOnClickListener(R.id.iv_avatar,R.id.check_box) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPkFinishDialog.kt b/app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPkFinishDialog.kt new file mode 100644 index 0000000..1c57895 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPkFinishDialog.kt @@ -0,0 +1,89 @@ +package com.chwl.app.avroom.anotherroompk + +import android.annotation.SuppressLint +import android.os.Bundle +import android.view.WindowManager +import com.chwl.app.R +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.databinding.DialogRoomPkFinishBinding +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.core.im.custom.bean.RoomPkBean +import com.chwl.core.utils.extension.subAndReplaceDot + +class RoomPkFinishDialog : BaseDialogFragment() { + + companion object { + @JvmStatic + fun newInstance(pkBean: RoomPkBean): RoomPkFinishDialog { + val args = Bundle() + args.putSerializable("RoomPkBean", pkBean) + val fragment = RoomPkFinishDialog() + fragment.arguments = args + return fragment + } + } + + override var width = WindowManager.LayoutParams.MATCH_PARENT + + private val roomPkBean: RoomPkBean by lazy { requireArguments().getSerializable("RoomPkBean") as RoomPkBean } + + @SuppressLint("CheckResult", "SetTextI18n") + override fun init() { + binding?.tvTitleRed?.text = roomPkBean.cTitle.subAndReplaceDot(7) + binding?.tvValueRed?.text = "${roomPkBean.cAmount}" + ImageLoadUtils.loadImage( + context, + roomPkBean.cAvatar, + binding?.ivAvatarRed, + R.drawable.default_avatar + ) + + binding?.tvTitleBlue?.text = roomPkBean.aTitle.subAndReplaceDot(7) + binding?.tvValueBlue?.text = "${roomPkBean.aAmount}" + ImageLoadUtils.loadImage( + context, + roomPkBean.aAvatar, + binding?.ivAvatarBlue, + R.drawable.default_avatar + ) + + roomPkBean.csRank.getOrNull(0)?.let { + binding?.tvNickContribute?.text = it.nick + binding?.tvValueContribute?.text = + context?.getString(R.string.layout_dialog_room_pk_finish_07, it.amount.toString()) + ?: "" + ImageLoadUtils.loadImage( + context, + it.avatar, + binding?.ivAvatarContribute, + R.drawable.default_avatar + ) + } + + roomPkBean.crRank.getOrNull(0)?.let { + binding?.tvNickCharm?.text = it.nick + binding?.tvValueCharm?.text = + context?.getString(R.string.layout_activity_jewel_09, it.amount?.toString()) ?: "" + ImageLoadUtils.loadImage( + context, + it.avatar, + binding?.ivAvatarCharm, + R.drawable.default_avatar + ) + } + + when (roomPkBean.winUid) { + 0L -> { + binding?.ivStatus?.setImageResource(R.drawable.room_pk_result_draw) + } + roomPkBean.cUid -> { + binding?.ivStatus?.setImageResource(R.drawable.room_pk_result_win) + } + else -> { + binding?.ivStatus?.setImageResource(R.drawable.room_pk_result_fail) + } + } + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPkForceFinishDialog.kt b/app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPkForceFinishDialog.kt new file mode 100644 index 0000000..f546e67 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPkForceFinishDialog.kt @@ -0,0 +1,54 @@ +package com.chwl.app.avroom.anotherroompk + +import android.annotation.SuppressLint +import android.os.Bundle +import android.view.WindowManager +import com.chwl.app.R +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.databinding.DialogRoomPkForceFinishBinding +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.core.im.custom.bean.RoomPkBean +import com.chwl.core.utils.extension.subAndReplaceDot + +class RoomPkForceFinishDialog : BaseDialogFragment() { + + companion object { + @JvmStatic + fun newInstance(pkBean: RoomPkBean): RoomPkForceFinishDialog { + val args = Bundle() + args.putSerializable("RoomPkBean", pkBean) + val fragment = RoomPkForceFinishDialog() + fragment.arguments = args + return fragment + } + } + + override var width = WindowManager.LayoutParams.MATCH_PARENT + + private val roomPkBean: RoomPkBean by lazy { requireArguments().getSerializable("RoomPkBean") as RoomPkBean } + + @SuppressLint("CheckResult", "SetTextI18n") + override fun init() { + binding?.ivClose?.setOnClickListener { dismissAllowingStateLoss() } + binding?.tvTitleRed?.text = roomPkBean.cTitle.subAndReplaceDot(7) + binding?.tvValueRed?.text = "${roomPkBean.cAmount}" + ImageLoadUtils.loadImage( + context, + roomPkBean.cAvatar, + binding?.ivAvatarRed, + R.drawable.default_avatar + ) + + binding?.tvTitleBlue?.text = roomPkBean.aTitle.subAndReplaceDot(7) + binding?.tvValueBlue?.text = "${roomPkBean.aAmount}" + + ImageLoadUtils.loadImage( + context, + roomPkBean.aAvatar, + binding?.ivAvatarBlue, + R.drawable.default_avatar + ) + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPkReceivedDialog.kt b/app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPkReceivedDialog.kt new file mode 100644 index 0000000..3964d87 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPkReceivedDialog.kt @@ -0,0 +1,84 @@ +package com.chwl.app.avroom.anotherroompk + +import android.annotation.SuppressLint +import android.os.Bundle +import androidx.core.view.isVisible +import com.chwl.app.R +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.databinding.DialogRoomPkReceivedBinding +import com.chwl.core.im.custom.bean.RoomPkBean +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.room.anotherroompk.RoomPKModel +import com.chwl.core.utils.extension.subAndReplaceDot +import com.chwl.core.utils.extension.toast +import io.reactivex.Observable +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import java.util.concurrent.TimeUnit + +class RoomPkReceivedDialog : BaseDialogFragment() { + + companion object { + + @JvmStatic + fun newInstance(pkBean: RoomPkBean): RoomPkReceivedDialog { + val args = Bundle() + args.putSerializable("RoomPkBean", pkBean) + val fragment = RoomPkReceivedDialog() + fragment.arguments = args + return fragment + } + } + + private val pkBean: RoomPkBean by lazy { requireArguments().getSerializable("RoomPkBean") as RoomPkBean } + + private var disposable: Disposable? =null + + @SuppressLint("CheckResult") + override fun init() { + binding?.tvNick?.text = pkBean.inviteRoomTitle + binding?.tvTime?.text = "${pkBean.pkDuration}${getString(R.string.layout_activity_room_pk_create_010)}" + val height: Int + if (pkBean.pkDesc.isNullOrEmpty()) { + binding?.groupDesc?.isVisible = false + height = resources.getDimensionPixelOffset(R.dimen.dp_192) + } else { + binding?.tvDesc?.text = pkBean.pkDesc + binding?.groupDesc?.isVisible = true + height = resources.getDimensionPixelOffset(R.dimen.dp_211) + } + binding?.layoutContent?.let { + it.layoutParams.height = height + it.requestLayout() + } + disposable = Observable.intervalRange(0, 10, 0, 1, TimeUnit.SECONDS) + .compose(bindToLifecycle()) + .observeOn(AndroidSchedulers.mainThread()) + .doOnComplete { dismissAllowingStateLoss() } + .subscribe { + binding?.tvCloseTime?.text = "${10 - it}" + } + + binding?.tvReceived?.setOnClickListener { + commit(true) + } + + binding?.tvRefuse?.setOnClickListener { + commit(false) + } + } + + @SuppressLint("CheckResult") + private fun commit(accept: Boolean) { + disposable?.dispose() + RoomPKModel.acceptRoomPK(accept, AvRoomDataManager.get().roomUid, pkBean.roundId) + .compose(bindToLifecycle()) + .subscribe({ + //"接受PK邀請成功".toast() + dismissAllowingStateLoss() + }, { + it.message.toast() + dismissAllowingStateLoss() + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPkRuleDialog.kt b/app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPkRuleDialog.kt new file mode 100644 index 0000000..0b67a80 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/anotherroompk/RoomPkRuleDialog.kt @@ -0,0 +1,19 @@ +package com.chwl.app.avroom.anotherroompk + +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.databinding.DialogRoomPkRuleBinding + +class RoomPkRuleDialog : BaseDialogFragment() { + + companion object { + + @JvmStatic + fun newInstance(): RoomPkRuleDialog { + return RoomPkRuleDialog() + } + } + + override fun init() { + binding?.ivClose?.setOnClickListener { dismissAllowingStateLoss() } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/bean/LuckyBagConfig.java b/app/src/main/java/com/chwl/app/avroom/bean/LuckyBagConfig.java new file mode 100644 index 0000000..97ed9a2 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/bean/LuckyBagConfig.java @@ -0,0 +1,13 @@ +package com.chwl.app.avroom.bean; + +import java.util.List; + +import lombok.Data; + +@Data +public class LuckyBagConfig { + public int expireSeconds; + public List goldItems; + public List numItems; + public List timeItems; +} diff --git a/app/src/main/java/com/chwl/app/avroom/bean/LuckyBagDetailEntity.java b/app/src/main/java/com/chwl/app/avroom/bean/LuckyBagDetailEntity.java new file mode 100644 index 0000000..04622e8 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/bean/LuckyBagDetailEntity.java @@ -0,0 +1,22 @@ +package com.chwl.app.avroom.bean; + +import lombok.Data; + +@Data +public class LuckyBagDetailEntity { + public String avatar; + public String nick; + public long createTime; + public String createTimeStr; + public int num = 1; + public int originalAmount; + public String type; + public String giftName; + + + + public @interface BiliType{ + public int SENT = 1; + public int RECEIVED = 2; + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/bean/LuckyBagEntity.java b/app/src/main/java/com/chwl/app/avroom/bean/LuckyBagEntity.java new file mode 100644 index 0000000..5a9fc40 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/bean/LuckyBagEntity.java @@ -0,0 +1,28 @@ +package com.chwl.app.avroom.bean; + +import static com.chwl.app.avroom.bean.LuckyBagEntity.Type.GIFT; + +import lombok.Data; + +@Data +public class LuckyBagEntity { + public long id; + public long roomUid; + public long userId; + public String avatar; + public String nick; + public int status; + public String type; + public long beginTime; // 倒计时结束时间, 表时可以开抢了, (东八区) + public int countDownSecond; // 倒计时多少秒 + public long countDownTime; //接收到倒计时秒数 记录下本地时间 + + public @interface Type{ + public String GIFT = "GIFT"; + public String DIAMOND = "DIAMOND"; + } + + public boolean isGift() { + return type.equals(GIFT); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/bean/LuckyBagGiftBody.java b/app/src/main/java/com/chwl/app/avroom/bean/LuckyBagGiftBody.java new file mode 100644 index 0000000..f14e968 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/bean/LuckyBagGiftBody.java @@ -0,0 +1,27 @@ +package com.chwl.app.avroom.bean; + +import static com.chwl.app.avroom.bean.LuckyBagEntity.Type.GIFT; + +import java.util.ArrayList; +import java.util.List; + +import lombok.Data; + +@Data +public class LuckyBagGiftBody { + + public long roomUid; + public long uid; + public int countDownSecond; + public String type = GIFT; +// public int num; + + public List giftItems; + + public void addLuckyBagGift(LuckyBagGiftItemBody index) { + if (giftItems == null) { + giftItems = new ArrayList<>(); + } + giftItems.add(index); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/bean/LuckyBagGiftItemBody.java b/app/src/main/java/com/chwl/app/avroom/bean/LuckyBagGiftItemBody.java new file mode 100644 index 0000000..9f29fad --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/bean/LuckyBagGiftItemBody.java @@ -0,0 +1,9 @@ +package com.chwl.app.avroom.bean; + +import lombok.Data; + +@Data +public class LuckyBagGiftItemBody { + public long giftId; + public int giftNum; +} diff --git a/app/src/main/java/com/chwl/app/avroom/bean/LuckyBagGoldBody.java b/app/src/main/java/com/chwl/app/avroom/bean/LuckyBagGoldBody.java new file mode 100644 index 0000000..68c2676 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/bean/LuckyBagGoldBody.java @@ -0,0 +1,18 @@ +package com.chwl.app.avroom.bean; + +import static com.chwl.app.avroom.bean.LuckyBagEntity.Type.DIAMOND; + +import lombok.Data; + +@Data +public class LuckyBagGoldBody { + + public long roomUid; + public long uid; + public String type = DIAMOND; + public int goldNum; + public int num; + public int countDownSecond; + + +} diff --git a/app/src/main/java/com/chwl/app/avroom/bean/LuckyBagOpenBiliEntity.java b/app/src/main/java/com/chwl/app/avroom/bean/LuckyBagOpenBiliEntity.java new file mode 100644 index 0000000..53bc146 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/bean/LuckyBagOpenBiliEntity.java @@ -0,0 +1,14 @@ +package com.chwl.app.avroom.bean; + +import java.util.List; + +import lombok.Data; + +@Data +public class LuckyBagOpenBiliEntity { + public int amount; + public long createTime; + public String createTimeStr; + public List redEnvelopeGiftItemVOs; + public LuckyBagOpenUserBean userVO; +} diff --git a/app/src/main/java/com/chwl/app/avroom/bean/LuckyBagOpenEntity.java b/app/src/main/java/com/chwl/app/avroom/bean/LuckyBagOpenEntity.java new file mode 100644 index 0000000..1b58c95 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/bean/LuckyBagOpenEntity.java @@ -0,0 +1,11 @@ +package com.chwl.app.avroom.bean; + +import java.util.List; + +import lombok.Data; + +@Data +public class LuckyBagOpenEntity { + public int currentUserAmount; + public List currentUserGifts; +} diff --git a/app/src/main/java/com/chwl/app/avroom/bean/LuckyBagOpenGiftBean.java b/app/src/main/java/com/chwl/app/avroom/bean/LuckyBagOpenGiftBean.java new file mode 100644 index 0000000..ba183f9 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/bean/LuckyBagOpenGiftBean.java @@ -0,0 +1,10 @@ +package com.chwl.app.avroom.bean; + +import lombok.Data; + +@Data +public class LuckyBagOpenGiftBean { + public String giftUrl; + public String giftName; + public int goldPrice; +} diff --git a/app/src/main/java/com/chwl/app/avroom/bean/LuckyBagOpenGiftEntity.java b/app/src/main/java/com/chwl/app/avroom/bean/LuckyBagOpenGiftEntity.java new file mode 100644 index 0000000..9c6657b --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/bean/LuckyBagOpenGiftEntity.java @@ -0,0 +1,9 @@ +package com.chwl.app.avroom.bean; + +import lombok.Data; + +@Data +public class LuckyBagOpenGiftEntity { + public int giftNum; + public LuckyBagOpenGiftBean giftVo; +} diff --git a/app/src/main/java/com/chwl/app/avroom/bean/LuckyBagOpenUserBean.java b/app/src/main/java/com/chwl/app/avroom/bean/LuckyBagOpenUserBean.java new file mode 100644 index 0000000..e389de6 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/bean/LuckyBagOpenUserBean.java @@ -0,0 +1,10 @@ +package com.chwl.app.avroom.bean; + +import lombok.Data; + +@Data +public class LuckyBagOpenUserBean { + public String avatar; + public String nick; + public long uid; +} diff --git a/app/src/main/java/com/chwl/app/avroom/bean/RoomAlbumPhotoInfo.kt b/app/src/main/java/com/chwl/app/avroom/bean/RoomAlbumPhotoInfo.kt new file mode 100644 index 0000000..9234872 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/bean/RoomAlbumPhotoInfo.kt @@ -0,0 +1,14 @@ +package com.chwl.app.avroom.bean + +data class RoomAlbumPhotoInfo( + val giftId: Int, + val giftNum: Int, + val giftUrl: String, + val id: Int, + val photoUrl: String, + val roomUid: Int, + val status: Int, + val totalGoldPrice: Int, + val type: Int, + val uid: Int +) \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/bean/RoomGameplayItem.kt b/app/src/main/java/com/chwl/app/avroom/bean/RoomGameplayItem.kt new file mode 100644 index 0000000..fb1610c --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/bean/RoomGameplayItem.kt @@ -0,0 +1,63 @@ +package com.chwl.app.avroom.bean + +import androidx.annotation.Keep +import com.chwl.app.avroom.dialog.RoomGameplayDialog +import com.chwl.core.room.bean.RoomIcon +import java.io.Serializable + +@Keep +interface RoomGameplayItem : Serializable { + + fun getName(): String? + + fun getIconUrl(): String? + + fun getIconRes(): Int? + + fun onItemClick(dialog: RoomGameplayDialog) + + @Keep + class RoomIconItem( + private val roomIcon: RoomIcon, + private val onClick: (RoomGameplayDialog, RoomIcon) -> Unit + ) : RoomGameplayItem { + override fun getName(): String? { + return roomIcon.name + } + + override fun getIconUrl(): String? { + return roomIcon.icon + } + + override fun getIconRes(): Int? { + return null + } + + override fun onItemClick(dialog: RoomGameplayDialog) { + onClick.invoke(dialog, roomIcon) + } + } + + @Keep + class CustomItem( + private val name: String, + private val iconRes: Int, + private val onClick: (RoomGameplayDialog, CustomItem) -> Unit + ) : RoomGameplayItem { + override fun getName(): String { + return name + } + + override fun getIconUrl(): String? { + return null + } + + override fun getIconRes(): Int { + return iconRes + } + + override fun onItemClick(dialog: RoomGameplayDialog) { + onClick.invoke(dialog, this) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/bean/RoomLuckyBagInfo.java b/app/src/main/java/com/chwl/app/avroom/bean/RoomLuckyBagInfo.java new file mode 100644 index 0000000..c28f9e5 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/bean/RoomLuckyBagInfo.java @@ -0,0 +1,13 @@ +package com.chwl.app.avroom.bean; + +import java.util.List; + +import lombok.Data; + +@Data +public class RoomLuckyBagInfo { + + public List redEnvelopeListVoList; + public LuckyBagConfig redEnvelopeV2Config; + +} diff --git a/app/src/main/java/com/chwl/app/avroom/bean/RoomPlayBean.kt b/app/src/main/java/com/chwl/app/avroom/bean/RoomPlayBean.kt new file mode 100644 index 0000000..cfac18a --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/bean/RoomPlayBean.kt @@ -0,0 +1,8 @@ +package com.chwl.app.avroom.bean + +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage + +data class RoomPlayBean( + val event: Int, + val chatRoomMessage: ChatRoomMessage +) \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/AttentionHintDialog.java b/app/src/main/java/com/chwl/app/avroom/dialog/AttentionHintDialog.java new file mode 100644 index 0000000..0e5d42a --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/AttentionHintDialog.java @@ -0,0 +1,61 @@ +package com.chwl.app.avroom.dialog; + +import android.content.Context; +import android.widget.ImageView; +import android.widget.TextView; + +import com.chwl.app.R; +import com.chwl.app.base.BaseBsDialog; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.praise.PraiseModel; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; + +import io.reactivex.disposables.Disposable; + +/** + * @author Memory + * @desc 房间关注提示 + * @date 2021/6/28 + */ + +public class AttentionHintDialog extends BaseBsDialog { + + private ImageView ivAvatar; + private TextView tvNickname; + private TextView tvAttention; + private Disposable disposable; + + public AttentionHintDialog(Context context) { + super(context); + } + + @Override + protected int getDialogLayout() { + return R.layout.dialog_attention_hint; + } + + @Override + protected void init() { + ivAvatar = findViewById(R.id.iv_avatar); + tvNickname = findViewById(R.id.tv_nickname); + tvAttention = findViewById(R.id.tv_attention); + ImageLoadUtils.loadAvatar(getContext(), AvRoomDataManager.get().avatar, ivAvatar); + tvNickname.setText(AvRoomDataManager.get().nick); + tvAttention.setOnClickListener(v -> + disposable = PraiseModel.get().praise(AvRoomDataManager.get().getRoomUid(), true) + .subscribe(s -> { + tvAttention.setText(ResUtil.getString(R.string.avroom_dialog_attentionhintdialog_01)); + tvAttention.setEnabled(false); + dismiss(); + }, throwable -> SingleToastUtil.showToast(throwable.getMessage()))); + findViewById(R.id.iv_close).setOnClickListener(v -> dismiss()); + } + + @Override + public void onDetachedFromWindow() { + super.onDetachedFromWindow(); + if (disposable != null) disposable.dispose(); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/BaseRoomNotifyDialog.kt b/app/src/main/java/com/chwl/app/avroom/dialog/BaseRoomNotifyDialog.kt new file mode 100644 index 0000000..a288742 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/BaseRoomNotifyDialog.kt @@ -0,0 +1,174 @@ +package com.chwl.app.avroom.dialog + +import android.app.Activity +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.os.Handler +import android.os.Looper +import android.view.Gravity +import android.view.LayoutInflater +import android.view.MotionEvent +import android.view.View +import android.view.ViewGroup +import android.view.Window +import android.view.WindowManager +import androidx.annotation.StyleRes +import androidx.viewbinding.ViewBinding +import com.chwl.app.R +import com.chwl.app.application.GlobalHandleManager +import com.chwl.app.avroom.widget.VDHLayout +import com.chwl.app.ui.widget.dialog.BaseDialog + +abstract class BaseRoomNotifyDialog(context: Context, theme: Int = 0) : BaseDialog(context, theme) { + + protected val handle = Handler(Looper.getMainLooper()) + protected lateinit var mBinding: VB + + abstract fun createBinding(inflater: LayoutInflater): VB + + abstract fun init() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + mBinding = createBinding(LayoutInflater.from(context)) + setContentView(mBinding.root) + setCancelable(true) + setCanceledOnTouchOutside(false) + window?.let { + initWindow(it) + } + + init() + + if (useAutoDismiss()) { + startAutoDismiss() + } + } + + protected open fun startAutoDismiss() { + handle.postDelayed({ + dismissDialog() + }, (getStaySecond()*1000).toLong()) + } + + override fun onDetachedFromWindow() { + handle.removeCallbacksAndMessages(null) + super.onDetachedFromWindow() + } + + protected open fun initWindow(window: Window) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + val windowParams = window.attributes + windowParams.width = WindowManager.LayoutParams.MATCH_PARENT + windowParams.height = WindowManager.LayoutParams.WRAP_CONTENT + windowParams.dimAmount = 0.0f + windowParams.gravity = getGravity() + windowParams.x = 0 + windowParams.y = getTopOffset() + window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND) + window.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL) + window.attributes = windowParams + window.setWindowAnimations(getAnimations()) + } + + protected open fun getGravity():Int{ + return Gravity.TOP + } + + + protected open fun getStaySecond():Float{ + return 5f + } + + protected open fun getTopOffset():Int{ + return 0 + } + + @StyleRes + protected open fun getAnimations():Int{ + return R.style.anim_left + } + + override fun setContentView(view: View) { + if (useSlipSlip()) { + val vdhLayout = VDHLayout(context, null) + vdhLayout.addView(view) + vdhLayout.setListener { dismissDialog() } + super.setContentView(vdhLayout) + return + } + super.setContentView(view) + } + + override fun setContentView(layoutResID: Int) { + if (useSlipSlip()) { + val vdhLayout = VDHLayout(context, null) + LayoutInflater.from(context).inflate(layoutResID, vdhLayout) + vdhLayout.setListener { dismissDialog() } + super.setContentView(vdhLayout) + return + } + super.setContentView(layoutResID) + } + + override fun setContentView(view: View, params: ViewGroup.LayoutParams?) { + if (useSlipSlip()) { + val vdhLayout = VDHLayout(context, null) + vdhLayout.addView(view) + vdhLayout.setListener { dismissDialog() } + super.setContentView(vdhLayout, params) + return + } + super.setContentView(view, params) + } + + /** + * 是否启动侧滑,左滑:删除,右滑:回到原位置 + */ + protected open fun useSlipSlip(): Boolean { + return true + } + protected open fun useAutoDismiss(): Boolean { + return true + } + + + var mCallBack : CallBack? = null + interface CallBack{ + fun onHide(); + } + + open fun dismissDialog() { + try { + dismiss() + } catch (e: Exception) { + } + mCallBack?.onHide() + } + + open fun clearDialog() { + try { + dismiss() + } catch (e: Exception) { + } + } + + open fun showDialog(){ + show() + } + + override fun onTouchEvent(ev: MotionEvent): Boolean { +// Log.d(TAG,"dialog onTouchEvent") + // 将未消费的事件传给 activity,使得 dialog 区域外可见的 activity 界面可以进行点击滑动等操作 + var event= MotionEvent.obtain(ev.downTime, ev.eventTime, ev.action, ev.rawX, ev.rawY, ev.pressure, ev.size, ev.metaState, ev.xPrecision, ev.yPrecision, ev.deviceId, ev.edgeFlags) + val activity = GlobalHandleManager.get().activity ?: return super.onTouchEvent(ev) + return passThrough(activity,event) + } + + private fun passThrough(activity: Activity, ev: MotionEvent): Boolean { + return activity?.dispatchTouchEvent(ev) ?: false + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/CreateGameRoomDialog.kt b/app/src/main/java/com/chwl/app/avroom/dialog/CreateGameRoomDialog.kt new file mode 100644 index 0000000..d644168 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/CreateGameRoomDialog.kt @@ -0,0 +1,62 @@ +package com.chwl.app.avroom.dialog + +import android.annotation.SuppressLint +import android.view.Gravity +import android.view.WindowManager +import androidx.recyclerview.widget.GridLayoutManager +import com.chwl.app.avroom.adapter.CreateRoomGameGuideAdapter +import com.chwl.app.base.BaseActivity +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.databinding.DialogCreateGameRoomBinding +import com.chwl.app.home.helper.OpenRoomHelper +import com.chwl.app.ui.utils.RVDelegate +import com.chwl.core.room.bean.RoomInfo +import com.chwl.core.room.game.bean.GameInfo +import com.chwl.core.room.game.GameModel + +class CreateGameRoomDialog : BaseDialogFragment() { + + private lateinit var rvDelegate: RVDelegate + private val gameAdapter = CreateRoomGameGuideAdapter() + + override var width = WindowManager.LayoutParams.MATCH_PARENT + override var gravity = Gravity.BOTTOM + + @SuppressLint("CheckResult") + override fun init() { + + binding?.rvGame?.itemAnimator = null + rvDelegate = RVDelegate.Builder() + .setAdapter(gameAdapter) + .setRecyclerView(binding?.rvGame) + .setLayoutManager(GridLayoutManager(context, 2)) + .build() + + gameAdapter.setOnItemClickListener { _, _, position -> + try { + dismissAllowingStateLoss() + OpenRoomHelper.openRoom( + requireActivity() as BaseActivity, RoomInfo.ROOMTYPE_GAME, + gameAdapter.data[position].mgId.toLong() + ) + }catch (e:Exception){ + + } + } + + binding?.ivClose?.setOnClickListener { + dismissAllowingStateLoss() + } + + GameModel.getGameList(null) + .compose(bindToLifecycle()) + .subscribe( + { + rvDelegate.setNewData(it) + }, { + rvDelegate.loadErr(true) + } + ) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/CreateRoomDialog.kt b/app/src/main/java/com/chwl/app/avroom/dialog/CreateRoomDialog.kt new file mode 100644 index 0000000..49d9655 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/CreateRoomDialog.kt @@ -0,0 +1,114 @@ +package com.chwl.app.avroom.dialog + +import android.annotation.SuppressLint +import android.view.Gravity +import android.view.WindowManager +import androidx.core.view.isInvisible +import androidx.core.view.isVisible +import androidx.recyclerview.widget.LinearLayoutManager +import com.chwl.app.R +import com.chwl.app.avroom.adapter.CreateRoomGameAdapter +import com.chwl.app.base.BaseActivity +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.databinding.DialogCreateRoomBinding +import com.chwl.app.home.helper.OpenRoomHelper +import com.chwl.app.ui.utils.RVDelegate +import com.chwl.core.room.bean.RoomInfo +import com.chwl.core.room.game.bean.GameInfo +import com.chwl.core.room.game.GameModel +import com.chwl.core.utils.extension.toast +import com.chwl.library.utils.ResUtil + +class CreateRoomDialog : BaseDialogFragment() { + + private lateinit var rvDelegate: RVDelegate + private val gameAdapter = CreateRoomGameAdapter() + private var selectIndex = -1 + + override var width = WindowManager.LayoutParams.MATCH_PARENT + override var gravity = Gravity.BOTTOM + + private var isHomeGame = false + + @SuppressLint("CheckResult") + override fun init() { + if(isHomeGame){ + binding?.tvPlayType?.isVisible = false + binding?.rgType?.isVisible = false + binding?.rvGame?.isVisible = true + } + binding?.rvGame?.itemAnimator = null + rvDelegate = RVDelegate.Builder() + .setAdapter(gameAdapter) + .setRecyclerView(binding?.rvGame) + .setLayoutManager(LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)) + .build() + + gameAdapter.setOnItemClickListener { _, _, position -> + if (selectIndex != -1) { + gameAdapter.data.getOrNull(selectIndex)?.isSelect = false + gameAdapter.notifyItemChanged(selectIndex) + } + selectIndex = position + gameAdapter.data.getOrNull(selectIndex)?.isSelect = true + gameAdapter.notifyItemChanged(selectIndex) + checkCreateEnable() + } + + binding?.rbGameRoom?.setOnCheckedChangeListener { _, isChecked -> + checkCreateEnable() + if (isChecked) { + binding?.rvGame?.isVisible = true + } + } + + binding?.rbPartyRoom?.setOnCheckedChangeListener { _, isChecked -> + checkCreateEnable() + if (isChecked) { + binding?.rvGame?.isInvisible = true + } + } + binding?.tvCreate?.setOnClickListener { + dismissAllowingStateLoss() + if (binding?.rbPartyRoom?.isChecked == true) { + OpenRoomHelper.openHomePartyRoom(requireActivity() as BaseActivity) + } else { + if (selectIndex != -1) { + OpenRoomHelper.openRoom( + requireActivity() as BaseActivity, RoomInfo.ROOMTYPE_GAME, + gameAdapter.data[selectIndex].mgId.toLong() + ) + } else { + ResUtil.getString(R.string.avroom_dialog_createroomdialog_01).toast() + } + } + } + + binding?.ivClose?.setOnClickListener { + dismissAllowingStateLoss() + } + + GameModel.getGameList(null) + .compose(bindToLifecycle()) + .subscribe( + { + rvDelegate.setNewData(it) + }, { + rvDelegate.loadErr(true) + } + ) + } + + fun setGameVisible(){ + this.isHomeGame = true + } + + private fun checkCreateEnable() { + if(isHomeGame){ + binding?.tvCreate?.isEnabled = selectIndex != -1 + }else { + binding?.tvCreate?.isEnabled = binding?.rbPartyRoom?.isChecked == true || + (binding?.rbGameRoom?.isChecked == true && selectIndex != -1) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/DatingVipRuleDialog.java b/app/src/main/java/com/chwl/app/avroom/dialog/DatingVipRuleDialog.java new file mode 100644 index 0000000..228db3d --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/DatingVipRuleDialog.java @@ -0,0 +1,35 @@ +package com.chwl.app.avroom.dialog; + +import android.content.Context; +import android.text.method.ScrollingMovementMethod; +import android.view.View; + +import com.chwl.app.R; +import com.chwl.app.databinding.DialogDatingVipRuleBinding; +import com.chwl.app.base.BaseBindingDialog; +import com.chwl.library.annatation.ActLayoutRes; + + +@ActLayoutRes(R.layout.dialog_dating_vip_rule) +public class DatingVipRuleDialog extends BaseBindingDialog implements View.OnClickListener { + + + public DatingVipRuleDialog(Context context) { + super(context, R.style.DialogFragment); + } + + public static DatingVipRuleDialog newInstance(Context context) { + return new DatingVipRuleDialog(context); + } + + @Override + protected void init() { + binding.setClick(this); + binding.tvRule.setMovementMethod(ScrollingMovementMethod.getInstance()); + } + + @Override + public void onClick(View v) { + closeDialog(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/ExitRoomPopupWindow.kt b/app/src/main/java/com/chwl/app/avroom/dialog/ExitRoomPopupWindow.kt new file mode 100644 index 0000000..b8411cc --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/ExitRoomPopupWindow.kt @@ -0,0 +1,170 @@ +package com.chwl.app.avroom.dialog + +import android.annotation.SuppressLint +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.view.LayoutInflater +import android.view.View +import android.view.WindowManager +import android.widget.PopupWindow +import android.widget.TextView +import androidx.core.view.isGone +import androidx.core.view.isVisible +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.netease.nim.uikit.common.util.sys.ScreenUtil +import com.chwl.app.R +import com.chwl.app.avroom.activity.AVRoomActivity +import com.chwl.app.avroom.adapter.ExitRoomAdapter +import com.chwl.app.avroom.presenter.HomePartyPresenter +import com.chwl.app.common.widget.dialog.DialogManager.LambdaOkDialogListener +import com.chwl.app.common.widget.dialog.DialogManager.OkCancelDialogListener +import com.chwl.app.ui.utils.RVDelegate +import com.chwl.core.home.bean.HomeRoomInfo +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.room.model.AvRoomModel +import com.chwl.library.annatation.ActLayoutRes +import com.chwl.library.utils.ResUtil +import com.example.lib_utils.UiUtils +import io.reactivex.disposables.Disposable + + +@ActLayoutRes(R.layout.dialog_exit_room) +class ExitRoomPopupWindow(val avRoomActivity: AVRoomActivity) : PopupWindow() { + + companion object { + + @JvmStatic + fun newInstance(avRoomActivity: AVRoomActivity): ExitRoomPopupWindow { + return ExitRoomPopupWindow(avRoomActivity) + } + + } + + private val recyclerView: RecyclerView + private val llEmpty: View + private val tvMiniRoom: TextView + private val tvExitRoom: TextView + + private var disposable: Disposable? = null + + private val exitRoomAdapter = ExitRoomAdapter() + private lateinit var rvDelegate: RVDelegate + + init { + contentView = LayoutInflater.from(avRoomActivity).inflate(R.layout.dialog_exit_room, null) + width = ScreenUtil.dip2px(250f) + height = WindowManager.LayoutParams.MATCH_PARENT + isFocusable = true + recyclerView = contentView.findViewById(R.id.recycler_view) + llEmpty = contentView.findViewById(R.id.ll_empty) + tvMiniRoom = contentView.findViewById(R.id.tv_mini_room) + tvExitRoom = contentView.findViewById(R.id.tv_exit_room) + initView() + isClippingEnabled = false + } + + private fun initView() { + if(UiUtils.isRtl(avRoomActivity)){ + animationStyle = R.style.style_anim_left_in_out + }else{ + animationStyle = R.style.style_anim_right_in_out + } + setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + + tvExitRoom.setOnClickListener { + handleExitRoom() + dismiss() + } + + tvMiniRoom.setOnClickListener { + if (AvRoomDataManager.get().isSelfGamePlaying) { + avRoomActivity.dialogManager.showOkCancelDialog( + ResUtil.getString(R.string.avroom_dialog_exitroompopupwindow_01), false + ) { + avRoomActivity.toBack() + dismiss() + } + return@setOnClickListener + } + avRoomActivity.onBackPressed() + dismiss() + } + + rvDelegate = RVDelegate.Builder() + .setLayoutManager(LinearLayoutManager(avRoomActivity)) + .setRecyclerView(recyclerView) + .setAdapter(exitRoomAdapter) + .build() + + exitRoomAdapter.setOnItemClickListener { _, _, position -> + exitRoomAdapter.getItem(position)?.let { + AVRoomActivity.start(avRoomActivity, it.uid) + dismiss() + } + } + + disposable = AvRoomModel.get() + .getRecommendRoomList(AvRoomDataManager.get().roomId.toString()) + .subscribe( + { + llEmpty.isVisible = it.isNullOrEmpty() + recyclerView.isGone = it.isNullOrEmpty() + rvDelegate.setNewData(it) + }, + { + llEmpty.isVisible = true + recyclerView.isVisible = true + } + ) + + setOnDismissListener { + disposable?.dispose() + } + + } + + private fun handleExitRoom() { + if (AvRoomDataManager.get().isSelfGamePlaying) { + avRoomActivity.dialogManager.showOkCancelDialog( + ResUtil.getString(R.string.avroom_dialog_exitroompopupwindow_02), false + ) { avRoomActivity.toBack() } + return + } + if (AvRoomDataManager.get().isOpenKTV && AvRoomDataManager.get().isOwnerOnMic) { + avRoomActivity.dialogManager.showOkCancelDialog( + ResUtil.getString(R.string.avroom_dialog_exitroompopupwindow_03), + false + ) { avRoomActivity.toBack() } + return + } + if ((AvRoomDataManager.get().isQueuingMicro || AvRoomDataManager.get().isOpenPKMode) + && AvRoomDataManager.get().myIsInQueue + ) { + avRoomActivity.dialogManager.showOkCancelDialog(ResUtil.getString(R.string.avroom_dialog_exitroompopupwindow_04), + false, + LambdaOkDialogListener { avRoomActivity.toBack() }) + return + } + if (AvRoomDataManager.get().haveStartDragon) { + avRoomActivity.dialogManager.showOkCancelDialog( + ResUtil.getString(R.string.avroom_dialog_exitroompopupwindow_05), + false, + object : OkCancelDialogListener { + override fun onCancel() {} + + @SuppressLint("CheckResult") + override fun onOk() { + avRoomActivity.giveUpDragonBar() + .subscribe { _: String? -> + HomePartyPresenter().cancelDragon() + avRoomActivity.toBack() + } + } + }) + } else { + avRoomActivity.toBack() + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/MicQueueDialog.java b/app/src/main/java/com/chwl/app/avroom/dialog/MicQueueDialog.java new file mode 100644 index 0000000..5ef987a --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/MicQueueDialog.java @@ -0,0 +1,609 @@ +package com.chwl.app.avroom.dialog; + +import android.content.Context; +import android.graphics.Color; +import android.os.Bundle; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.SpannableStringBuilder; +import android.text.style.ForegroundColorSpan; +import android.view.Gravity; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import com.chwl.app.R; +import com.chwl.app.avroom.adapter.MicQueueAdapter; +import com.chwl.app.home.helper.LoadPageDataHelper; +import com.chwl.app.ui.widget.dialog.BaseDialog; +import com.chwl.app.ui.widget.recyclerview.decoration.ColorDecoration; +import com.chwl.core.Constants; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.bean.RoomQueueInfo; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.core.room.giftvalue.helper.GiftValueMrg; +import com.chwl.core.room.model.HomePartyModel; +import com.chwl.core.room.model.MicQueueModel; +import com.chwl.core.room.queuing_mic.bean.GroupType; +import com.chwl.core.room.queuing_mic.bean.QueuingMicMemeberInfo; +import com.chwl.core.room.queuing_mic.bean.RespQueuingMicListInfo; +import com.chwl.core.user.bean.BaseInfo; +import com.chwl.core.utils.net.BeanObserver; +import com.chwl.library.common.util.Utils; +import com.chwl.library.net.rxnet.callback.CallBack; +import com.chwl.library.utils.CommonUtils; +import com.chwl.library.utils.JavaUtil; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMember; + +import java.util.ArrayList; +import java.util.List; + +import io.reactivex.Single; +import io.reactivex.SingleObserver; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.disposables.Disposable; + +/** + * @author jack + * @Description + * @Date 2018/12/14 + */ +public class MicQueueDialog extends BaseDialog implements + LoadPageDataHelper.LoadData>, View.OnClickListener { + + private TextView tvMicQueueTip; + private RecyclerView rvMicQueue; + private SwipeRefreshLayout srlRefreshContainer; + private TextView tvNoDataTip; + private LinearLayout llNoDataContainer; + private TextView tvApplyMicQueue; + private FrameLayout flQueueCount; + private View llJoinQueue; + private TextView tvJoinMale; + private TextView tvJoinFemale; + + private LoadPageDataHelper> loadPageDataHelper; + private boolean noMoreData = false; + private MicQueueAdapter adapter; + + private CompositeDisposable compositeDisposable = new CompositeDisposable(); + + private Context context; + + public MicQueueDialog(@NonNull Context context) { + super(context, R.style.bottom_dialog); + this.context = context; + loadPageDataHelper = new LoadPageDataHelper<>(this); + Window window = getWindow(); + if (window != null) { + WindowManager.LayoutParams lps = window.getAttributes(); + lps.width = WindowManager.LayoutParams.MATCH_PARENT; + lps.height = WindowManager.LayoutParams.WRAP_CONTENT; + lps.gravity = Gravity.BOTTOM; + window.setAttributes(lps); + } + } + + private List dataList = new ArrayList<>(); + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setCanceledOnTouchOutside(true); + setContentView(R.layout.dialog_mic_queue); + + findView(); + initListener(); + + srlRefreshContainer.setOnRefreshListener(this::refreshData); + + rvMicQueue.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false)); + rvMicQueue.addItemDecoration(new ColorDecoration(Color.TRANSPARENT, 0, Utils.dip2px(getContext(), 5), true)); + + adapter = new MicQueueAdapter(dataList); + adapter.setOnUpMicListener((member, itemPos) -> { + if (CommonUtils.isFastDoubleClick(1000)) { + toast(ResUtil.getString(R.string.avroom_dialog_micqueuedialog_01)); + return; + } + long targetUid = member.getUid(); + if (AvRoomDataManager.get().isOnMic(member.getUid())) { + toast(ResUtil.getString(R.string.avroom_dialog_micqueuedialog_02)); + return; + } + AvRoomDataManager.get().checkMemberInRoomById(targetUid) + .subscribe(new BeanObserver() { + @Override + public void onErrorMsg(String error) { + toast(error); + MicQueueModel.get().cancelApplyForQueuing(AvRoomDataManager.get().getRoomUid(), targetUid).subscribe(); + } + + @Override + public void onSuccess(ChatRoomMember mem) { + inviteToMic(member, itemPos); + } + }); + + }); + rvMicQueue.setAdapter(adapter); + + srlRefreshContainer.setRefreshing(true); + //加载更多 + rvMicQueue.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrollStateChanged(RecyclerView recyclerView, int newState) { + super.onScrollStateChanged(recyclerView, newState); + if (loadPageDataHelper.isLoading() || noMoreData) { + return; + } + if (adapter.getItemCount() <= 0) { + return; + } + if (newState == RecyclerView.SCROLL_STATE_IDLE) { + LinearLayoutManager manager = (LinearLayoutManager) rvMicQueue.getLayoutManager(); + int lastIndex = manager.findLastVisibleItemPosition(); + if (lastIndex == adapter.getItemCount() - 1) { + loadMoreData(); + } + } + } + }); + refreshData(); + } + + private void findView() { + tvMicQueueTip = findViewById(R.id.tv_mic_queue_tip); + rvMicQueue = findViewById(R.id.rv_mic_queue); + srlRefreshContainer = findViewById(R.id.srl_refresh_container); + tvNoDataTip = findViewById(R.id.tv_no_data_tip); + llNoDataContainer = findViewById(R.id.ll_no_data_container); + tvApplyMicQueue = findViewById(R.id.tv_apply_mic_queue); + flQueueCount = findViewById(R.id.fl_queue_count); + llJoinQueue = findViewById(R.id.ll_join_queue); + tvJoinMale = findViewById(R.id.tv_join_male); + tvJoinFemale = findViewById(R.id.tv_join_female); + } + + private void initListener() { + tvApplyMicQueue.setOnClickListener(this); + tvJoinMale.setOnClickListener(this); + tvJoinFemale.setOnClickListener(this); + } + + @Override + public void onClick(View view) { + if (queueMicListInfo == null) { + return; + } + + //报名排麦 + if (AvRoomDataManager.get().isManager()) { + if (actionListener != null) { + actionListener.onShareRoom(MicQueueDialog.this); + } + } else { + int groupType = 0; + if (view.getId() == R.id.tv_join_male) { + groupType = GroupType.MALE; + } else if (view.getId() == R.id.tv_join_female) { + groupType = GroupType.FEMALE; + } + if (actionListener != null) { + if (queueMicListInfo.getMyPos() < 0) { + if (!AvRoomDataManager.get().isQueuingMicro()) { + toast(ResUtil.getString(R.string.avroom_dialog_micqueuedialog_05)); + return; + } + actionListener.onApplyMicQueue(MicQueueDialog.this, groupType); + } else { + actionListener.onCancelMicQueue(MicQueueDialog.this); + } + } + } + } + + /** + * 抱TA上麦 + */ + private void inviteToMic(QueuingMicMemeberInfo member, int itemPos) { + int micPosition = -1; + for (int i = 0; i < AvRoomDataManager.get().mMicQueueMemberMap.size(); i++) { + int key = AvRoomDataManager.get().mMicQueueMemberMap.keyAt(i); + //-1这个位置是 房主,不让上去 + if (key == -1) continue; + //相亲模式只能抱上对应的坑位 + if (AvRoomDataManager.get().isDatingMode()) { + if (member.getGroupType() == GroupType.MALE && !Constants.maleIndex.contains(key)) + continue; + if (member.getGroupType() == GroupType.FEMALE && Constants.maleIndex.contains(key)) + continue; + } + //19麦的情况下 老板麦跳过 , 19麦房间的 boss ViewItemPos是7 , 云信上麦位是6 , 展示时是8号麦 + if (AvRoomDataManager.get().is19Room()) { + if (AvRoomDataManager.get().is19RoomBoosMicPos(key)) continue; + } + + RoomQueueInfo roomQueueInfo = AvRoomDataManager.get().mMicQueueMemberMap.get(key); + //排麦模式下,选择被锁的坑,即是排麦坑才能上 + if (roomQueueInfo != null + && roomQueueInfo.mRoomMicInfo != null + && roomQueueInfo.mRoomMicInfo.isMicLock() + && roomQueueInfo.mChatRoomMember == null) { + micPosition = key; + break; + } + } + //房主的坑位key是-1 ,剩下的 坑位 按房间类型填 + int maxMicPos = 8; + if (AvRoomDataManager.get().isPartyRoom()){ + maxMicPos = 10; + }else if (AvRoomDataManager.get().isRevelryRoom()){ + maxMicPos = 15; + }else if (AvRoomDataManager.get().is19Room()){ + maxMicPos = 19; + }else if (AvRoomDataManager.get().is20Room()){ + maxMicPos = 20; + } + if (micPosition != -1 && micPosition < maxMicPos) { + + //跳过 19 麦的 老板麦 + if (AvRoomDataManager.get().is19Room() && AvRoomDataManager.get().is19RoomBoosMicPos(micPosition)) return; + + if (itemPos < adapter.getItemCount()) { + dataList.remove(itemPos); + adapter.notifyDataSetChanged(); + } + reduceQueueInfo(); + if (dataList.size() == 0) { + showNoDataLayout(); + } else { + setTopLayout(); + } + HomePartyModel model = new HomePartyModel(); + long targetUid = member.getUid(); + if (AvRoomDataManager.get().isOwner(targetUid)) { + //如果是自己,就是自己上麦 + final int finalMicPos = micPosition; + model.upMicroPhone( + micPosition, + String.valueOf(targetUid), + String.valueOf(AvRoomDataManager.get().getRoomId()), + true, + new CallBack() { + @Override + public void onSuccess(String data) { + GiftValueMrg.get().requestUpMic(finalMicPos, String.valueOf(targetUid)); + } + + @Override + public void onFail(int code, String error) { + + } + }); + return; + } + //抱别人上麦 + model.inviteMicroPhone(new BaseInfo(targetUid, member.getNick(), member.getGroupType()), micPosition) + .subscribe(); + + } else { + toast(ResUtil.getString(R.string.avroom_dialog_micqueuedialog_03)); + } + } + + + /** + * 将队列减一 + */ + private void reduceQueueInfo() { + if (queueMicListInfo != null) { + int count = queueMicListInfo.getCount(); + count--; + if (count < 0) { + count = 0; + } + queueMicListInfo.setCount(count); + } + } + + @Override + protected void onStop() { + super.onStop(); + if (compositeDisposable != null) { + compositeDisposable.dispose(); + compositeDisposable = null; + } + } + + public void addDisposable(Disposable disposable) { + compositeDisposable.add(disposable); + } + + /** + * 刷新麦序 + */ + public void refreshData() { + if (loadPageDataHelper.isLoading()) { + srlRefreshContainer.setRefreshing(false); + return; + } + noMoreData = false; + loadPageDataHelper.refreshData().subscribe(new SingleObserver>() { + @Override + public void onSubscribe(Disposable d) { + compositeDisposable.add(d); + } + + @Override + public void onSuccess(List memberList) { + if (ListUtils.isListEmpty(memberList)) { + showNoDataLayout(); + noMoreData = true; + } else { + showHaveDataLayout(); + dataList = memberList; + adapter.setNewData(memberList); + } + srlRefreshContainer.setRefreshing(false); + } + + @Override + public void onError(Throwable e) { + srlRefreshContainer.setRefreshing(false); +// Toast.makeText(getContext(), e.getMessage(), Toast.LENGTH_SHORT).show(); + SingleToastUtil.showToastShort(e.getMessage()); + } + }); + } + + private void showHaveDataLayout() { + resetApplyButton(); + srlRefreshContainer.setVisibility(View.VISIBLE); + llNoDataContainer.setVisibility(View.GONE); + setTopLayout(); + llJoinQueue.setActivated(true); + setApplyButtonClickable(true); + if (AvRoomDataManager.get().isManager()) { + llJoinQueue.setVisibility(View.GONE); + } else { + if (queueMicListInfo != null) { + llJoinQueue.setVisibility(View.VISIBLE); + if (queueMicListInfo.getMyPos() < 0) { + //我不在队列 + //点击报名 + if (AvRoomDataManager.get().isOnMic(AuthModel.get().getCurrentUid())) { + llJoinQueue.setActivated(false); + setApplyButtonClickable(false); + } + tvApplyMicQueue.setText(context.getResources().getString(R.string.apply_mic_queue)); + } else { + //我在队列 + //取消报名 + llJoinQueue.setActivated(false); + tvApplyMicQueue.setText(context.getResources().getString(R.string.cancel_mic_queue)); + tvApplyMicQueue.setVisibility(View.VISIBLE); + tvJoinFemale.setVisibility(View.GONE); + tvJoinMale.setVisibility(View.GONE); + } + } + } + } + + private void showNoDataLayout() { + resetApplyButton(); + srlRefreshContainer.setVisibility(View.GONE); + llNoDataContainer.setVisibility(View.VISIBLE); + llJoinQueue.setVisibility(View.VISIBLE); + llJoinQueue.setActivated(true); + setApplyButtonClickable(true); + if (AvRoomDataManager.get().isManager()) { + flQueueCount.setVisibility(View.GONE); + //立即邀请 + tvApplyMicQueue.setText(R.string.invite_to_mic_queue); + tvNoDataTip.setText(getContext().getResources().getString(R.string.manager_no_mic_queue_tip)); + } else { + flQueueCount.setVisibility(View.VISIBLE); + tvMicQueueTip.setText(R.string.apply_mic_queue_tip); + //点击报名 + if (AvRoomDataManager.get().isOnMic(AuthModel.get().getCurrentUid())) { + llJoinQueue.setActivated(false); + setApplyButtonClickable(false); + } + tvApplyMicQueue.setText(R.string.apply_mic_queue); + + tvNoDataTip.setText(getContext().getResources().getString(R.string.no_mic_queue_tip)); + } + } + + //相亲模式下有两按钮,但是管理员依然只有一个 + private void resetApplyButton() { + if (AvRoomDataManager.get().isDatingMode() && !AvRoomDataManager.get().isManager()) { + tvApplyMicQueue.setVisibility(View.GONE); + tvJoinFemale.setVisibility(View.VISIBLE); + tvJoinMale.setVisibility(View.VISIBLE); + } else { + tvApplyMicQueue.setVisibility(View.VISIBLE); + tvJoinFemale.setVisibility(View.GONE); + tvJoinMale.setVisibility(View.GONE); + } + } + + private void setApplyButtonClickable(boolean clickable) { + tvApplyMicQueue.setClickable(clickable); + tvJoinFemale.setClickable(clickable); + tvJoinMale.setClickable(clickable); + } + + + private void loadMoreData() { + loadPageDataHelper.loadMoreData().subscribe(new SingleObserver>() { + @Override + public void onSubscribe(Disposable d) { + compositeDisposable.add(d); + } + + @Override + public void onSuccess(List userInfos) { + if (!ListUtils.isListEmpty(userInfos)) { + adapter.addData(userInfos); + } else { + noMoreData = true; + } + } + + @Override + public void onError(Throwable e) { + SingleToastUtil.showToastShort(e.getMessage()); + } + }); + + } + + private RespQueuingMicListInfo queueMicListInfo; + + @Override + public Single> loadData(int curPage) { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo != null) { + return MicQueueModel.get().loadMicQueueList(roomInfo.getUid(), curPage, Constants.PAGE_SIZE) + .flatMap(info -> { + queueMicListInfo = info; + AvRoomDataManager.get().myIsInQueue = info.getMyPos() >= 0; + List list = info.getQueue(); + if (list == null) { + list = new ArrayList<>(); + } + return Single.just(list); + }); + } else { + return Single.error(new Throwable(ResUtil.getString(R.string.avroom_dialog_micqueuedialog_04))); + } + } + + private SpannableStringBuilder createBuilder(String normalText, String spannableText) { + SpannableStringBuilder builder = new SpannableStringBuilder(); + builder.append(normalText); + SpannableString spannableString = new SpannableString(spannableText); + spannableString.setSpan( + new ForegroundColorSpan(getContext().getResources().getColor(R.color.appColor)), + 0, + spannableString.length(), + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + builder.append(spannableString); + return builder; + } + + public void updateQueueInfo(RespQueuingMicListInfo info) { + if (info == null) { + return; + } + queueMicListInfo = info; + AvRoomDataManager.get().myIsInQueue = info.getMyPos() >= 0; + List list = queueMicListInfo.getQueue(); + if (list == null) { + list = new ArrayList<>(); + } + dataList = list; + adapter.setNewData(dataList); + if (!ListUtils.isListEmpty(list)) { + showHaveDataLayout(); + } else { + showNoDataLayout(); + } + loadPageDataHelper.setCurPage(Constants.PAGE_START + 1); + } + + public void removeQueueMember(String account) { + long removeUid = JavaUtil.str2long(account); + int removeIndex = -1; + int myQueuePos = -1; + for (int i = 0; i < dataList.size(); i++) { + if (dataList.get(i).getUid() == removeUid) { + removeIndex = i; + } + if (dataList.get(i).getUid() == AuthModel.get().getCurrentUid()) { + myQueuePos = i; + } + } + if (removeIndex >= 0) { + //判断自己的位置是否需要减一 + if (AvRoomDataManager.get().myIsInQueue) { + if (myQueuePos >= 0 && myQueuePos > removeIndex) { + int newMyPos = queueMicListInfo.getMyPos() - 1; + if (newMyPos < 1) { + newMyPos = 1; + } + queueMicListInfo.setMyPos(newMyPos); + } + } + dataList.remove(removeIndex); + adapter.notifyDataSetChanged(); + } + queueMicListInfo.setQueue(dataList); + reduceQueueInfo(); + if (dataList.size() == 0) { + showNoDataLayout(); + return; + } + setTopLayout(); + } + + /** + * 顶部的布局 + */ + private void setTopLayout() { + if (AvRoomDataManager.get().isManager()) { + if (queueMicListInfo != null) { + tvMicQueueTip.setText( + createBuilder( + context.getResources().getString(R.string.curr_queue_member_count), + String.valueOf(queueMicListInfo.getCount()) + ) + ); + } + } else { + if (queueMicListInfo != null) { + if (queueMicListInfo.getMyPos() < 0) { + tvMicQueueTip.setText(R.string.please_to_apply_queue); + } else { + tvMicQueueTip.setText( + createBuilder( + context.getResources().getString(R.string.my_pos_in_queue), + String.valueOf(queueMicListInfo.getMyPos()) + ) + ); + } + } + } + } + + /********************************回调*******************************************/ + + private OnActionListener actionListener; + + public interface OnActionListener { + void onShareRoom(MicQueueDialog micQueueDialog); + + void onApplyMicQueue(MicQueueDialog micQueueDialog, int groupType); + + void onCancelMicQueue(MicQueueDialog micQueueDialog); + } + + public void setActionListener(OnActionListener actionListener) { + this.actionListener = actionListener; + } + +} diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/NewUserGiftDialog.kt b/app/src/main/java/com/chwl/app/avroom/dialog/NewUserGiftDialog.kt new file mode 100644 index 0000000..add6c02 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/NewUserGiftDialog.kt @@ -0,0 +1,19 @@ +package com.chwl.app.avroom.dialog + +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.databinding.DialogNewUserGiftBinding +import com.chwl.app.ui.utils.load +import com.chwl.core.gift.bean.GiftInfo + +class NewUserGiftDialog(val giftInfo: GiftInfo) : + BaseDialogFragment() { + + override fun init() { + binding?.ivClose?.setOnClickListener { + dismissAllowingStateLoss() + } + binding?.ivGift?.load(giftInfo.giftUrl) + binding?.tvGiftName?.text = "${giftInfo.giftName}*${giftInfo.count}" + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/PKMicQueueDialog.java b/app/src/main/java/com/chwl/app/avroom/dialog/PKMicQueueDialog.java new file mode 100644 index 0000000..358189d --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/PKMicQueueDialog.java @@ -0,0 +1,545 @@ +package com.chwl.app.avroom.dialog; + +import android.content.Context; +import android.graphics.Color; +import android.os.Bundle; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.SpannableStringBuilder; +import android.text.style.ForegroundColorSpan; +import android.view.Gravity; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMember; +import com.chwl.app.R; +import com.chwl.app.avroom.adapter.PKMicQueueAdapter; +import com.chwl.app.home.helper.LoadPageDataHelper; +import com.chwl.app.ui.widget.dialog.BaseDialog; +import com.chwl.app.ui.widget.dialog.CommonLoadingDialog; +import com.chwl.library.common.util.Utils; +import com.chwl.app.ui.widget.recyclerview.decoration.ColorDecoration; +import com.chwl.core.Constants; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.bean.RoomQueueInfo; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.core.room.pk.bean.PKMemberInfo; +import com.chwl.core.room.pk.bean.PKQueuingMicMemberInfo; +import com.chwl.core.room.pk.bean.PKRespQueuingMicListInfo; +import com.chwl.core.room.pk.bean.PKTeamInfo; +import com.chwl.core.room.pk.bean.RoomPKInvitedUpMicMember; +import com.chwl.core.room.pk.model.PkModel; +import com.chwl.core.utils.net.BeanObserver; +import com.chwl.library.utils.JavaUtil; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import io.reactivex.Single; +import io.reactivex.SingleObserver; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.disposables.Disposable; +import io.reactivex.functions.BiConsumer; + +/** + * @author jack + * @Description + * @Date 2019/1/2 + */ +public class PKMicQueueDialog extends BaseDialog implements + LoadPageDataHelper.LoadData> { + + private FrameLayout flQueueCount; + private TextView tvMicQueueTip; + private SwipeRefreshLayout srlRefreshContainer; + private RecyclerView rvMicQueue; + private LinearLayout llNoDataContainer; + private TextView tvNoDataTip; + private FrameLayout flBottomButton; + private LinearLayout llJoinQueue; + private TextView tvJoinRed; + private TextView tvJoinBlue; + private TextView tvExitQueue; + private TextView tvShareRoom; + + private PKMicQueueAdapter adapter; + private final LoadPageDataHelper> loadPageDataHelper; + private PKRespQueuingMicListInfo queueMicListInfo; + + private CompositeDisposable compositeDisposable = new CompositeDisposable(); + + private CommonLoadingDialog loadingDialog; + private String inviteAccount = ""; + + public PKMicQueueDialog(Context context) { + super(context, R.style.bottom_dialog); + loadPageDataHelper = new LoadPageDataHelper<>(this); + Window window = getWindow(); + if (window != null) { + WindowManager.LayoutParams lps = window.getAttributes(); + lps.width = WindowManager.LayoutParams.MATCH_PARENT; + lps.height = WindowManager.LayoutParams.WRAP_CONTENT; + lps.gravity = Gravity.BOTTOM; + window.setAttributes(lps); + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setCanceledOnTouchOutside(true); + setContentView(R.layout.dialog_pk_mic_queue); + + flQueueCount = findViewById(R.id.fl_queue_count); + tvMicQueueTip = findViewById(R.id.tv_mic_queue_tip); + srlRefreshContainer = findViewById(R.id.srl_refresh_container); + rvMicQueue = findViewById(R.id.rv_mic_queue); + llNoDataContainer = findViewById(R.id.ll_no_data_container); + tvNoDataTip = findViewById(R.id.tv_no_data_tip); + flBottomButton = findViewById(R.id.fl_bottom_button); + llJoinQueue = findViewById(R.id.ll_join_queue); + tvJoinRed = findViewById(R.id.tv_join_red); + tvJoinBlue = findViewById(R.id.tv_join_blue); + tvExitQueue = findViewById(R.id.tv_exit_queue); + tvShareRoom = findViewById(R.id.tv_share_room); + + + srlRefreshContainer.setOnRefreshListener(this::refreshData); + + rvMicQueue.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false)); + rvMicQueue.addItemDecoration(new ColorDecoration(Color.TRANSPARENT, 0, Utils.dip2px(getContext(), 5), true)); + + adapter = new PKMicQueueAdapter(null); + adapter.setEnableLoadMore(true); + adapter.setOnLoadMoreListener(this::loadMoreData, rvMicQueue); + adapter.setOnUpMicListener(new PKMicQueueAdapter.OnUpMicListener() { + @Override + public void onUpMic(PKQueuingMicMemberInfo member, final int itemPos) { + long targetUid = member.getUid(); + if (AvRoomDataManager.get().isOnMic(member.getUid())) { + toast(ResUtil.getString(R.string.avroom_dialog_pkmicqueuedialog_01)); + return; + } + + if (!isTeamMemberCountUnderLimit(member.getGroupType())) { + toast(ResUtil.getString(R.string.avroom_dialog_pkmicqueuedialog_02)); + return; + } + + loadingDialog = new CommonLoadingDialog(getContext(), ResUtil.getString(R.string.avroom_dialog_pkmicqueuedialog_03)).showDialog(); + inviteAccount = String.valueOf(member.getUid()); + AvRoomDataManager.get().checkMemberInRoomById(targetUid) + .subscribe(new BeanObserver() { + @Override + public void onErrorMsg(String error) { + toast(error); + loadingDialog.dismiss(); + } + + @Override + public void onSuccess(ChatRoomMember mem) { + inviteToMic(member, itemPos); + } + }); + + } + }); + rvMicQueue.setAdapter(adapter); + + tvExitQueue.setOnClickListener(v -> { + if (actionListener != null && queueMicListInfo != null && queueMicListInfo.getMyPos() >= 0) { + actionListener.onCancelMicQueue(PKMicQueueDialog.this); + } + }); + + tvJoinRed.setOnClickListener(v -> { + if (actionListener != null && queueMicListInfo != null && queueMicListInfo.getMyPos() < 0) { + actionListener.onApplyMicQueue(PKMicQueueDialog.this, PKTeamInfo.TEAM_RED); + } + }); + + tvJoinBlue.setOnClickListener(v -> { + if (actionListener != null && queueMicListInfo != null && queueMicListInfo.getMyPos() < 0) { + actionListener.onApplyMicQueue(PKMicQueueDialog.this, PKTeamInfo.TEAM_BLUE); + } + }); + + tvShareRoom.setOnClickListener(v -> { + if (actionListener != null) { + actionListener.onShareRoom(PKMicQueueDialog.this); + } + }); + + + srlRefreshContainer.setRefreshing(true); + refreshData(); + } + + private boolean isTeamMemberCountUnderLimit(int groupType) { + int teamSize = 0; + for (PKMemberInfo pkMemberInfo : PkModel.get().getPkMemberInfoList()) { + if (pkMemberInfo.getTeamId() == groupType) { + teamSize++; + } + } + return teamSize < PkModel.TEAM_MAX_SIZE; + } + + @Override + protected void onStop() { + super.onStop(); + if (compositeDisposable != null) { + compositeDisposable.dispose(); + compositeDisposable = null; + } + } + + public void addDisposable(Disposable disposable) { + compositeDisposable.add(disposable); + } + + @Override + public Single> loadData(int curPage) { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo != null) { + return PkModel.get().loadPKMicQueueList( + curPage, + Constants.PAGE_SIZE + ) + .flatMap(info -> { + queueMicListInfo = info; + AvRoomDataManager.get().myIsInQueue = info.getMyPos() >= 0; + List list = info.getQueue(); + if (list == null) { + list = new ArrayList<>(); + } + return Single.just(list); + }); + } else { + return Single.error(new Throwable(ResUtil.getString(R.string.avroom_dialog_pkmicqueuedialog_04))); + } + } + + public void refreshData() { + if (loadPageDataHelper.isLoading()) { + srlRefreshContainer.setRefreshing(false); + return; + } + loadPageDataHelper.refreshData().subscribe(new SingleObserver>() { + @Override + public void onSubscribe(Disposable d) { + compositeDisposable.add(d); + } + + @Override + public void onSuccess(List memberList) { + if (ListUtils.isListEmpty(memberList)) { + showNoDataLayout(); + } else { + showHaveDataLayout(); + adapter.setNewData(memberList); + } + srlRefreshContainer.setRefreshing(false); + } + + @Override + public void onError(Throwable e) { + srlRefreshContainer.setRefreshing(false); +// Toast.makeText(getContext(), e.getMessage(), Toast.LENGTH_SHORT).show(); + SingleToastUtil.showToastShort(e.getMessage()); + } + }); + } + + private void loadMoreData() { + loadPageDataHelper.loadMoreData().subscribe(new SingleObserver>() { + @Override + public void onSubscribe(Disposable d) { + compositeDisposable.add(d); + } + + @Override + public void onSuccess(List userInfos) { + adapter.loadMoreComplete(); + if (!ListUtils.isListEmpty(userInfos)) { + adapter.addData(userInfos); + } else { + adapter.loadMoreEnd(); + } + } + + @Override + public void onError(Throwable e) { + adapter.loadMoreComplete(); +// Toast.makeText(getContext(), e.getMessage(), Toast.LENGTH_SHORT).show(); + SingleToastUtil.showToastShort(e.getMessage()); + } + }); + } + + public void updateQueueInfo(PKRespQueuingMicListInfo info) { + if (info == null) { + return; + } + queueMicListInfo = info; + AvRoomDataManager.get().myIsInQueue = info.getMyPos() >= 0; + List list = queueMicListInfo.getQueue(); + if (list == null) { + list = new ArrayList<>(); + } + adapter.setNewData(list); + if (!ListUtils.isListEmpty(list)) { + showHaveDataLayout(); + } else { + showNoDataLayout(); + } + loadPageDataHelper.setCurPage(Constants.PAGE_START + 1); + } + + + /** + * 抱TA上麦 + */ + private void inviteToMic(PKQueuingMicMemberInfo member, int itemPos) { + int micPosition = -1; + for (int i = 0; i < AvRoomDataManager.get().mMicQueueMemberMap.size(); i++) { + int key = AvRoomDataManager.get().mMicQueueMemberMap.keyAt(i); + RoomQueueInfo roomQueueInfo = AvRoomDataManager.get().mMicQueueMemberMap.get(key); + //-1这个位置是 房主,不让上去 + //排麦模式下,选择被锁的坑,即是排麦坑才能上 + if (key != -1 && roomQueueInfo != null + && roomQueueInfo.mRoomMicInfo != null + && roomQueueInfo.mRoomMicInfo.isMicLock() + && roomQueueInfo.mChatRoomMember == null) { + micPosition = key; + break; + } + } + //房主的坑位key是-1 ,剩下的 8个坑的key从0 - 7 + if (micPosition != -1 && micPosition < 8) { + if (itemPos < adapter.getItemCount()) { + adapter.remove(itemPos); + adapter.notifyDataSetChanged(); + } + reduceQueueInfo(); + if (adapter.getData().size() == 0) { + showNoDataLayout(); + } else { + setTopLayout(); + } + + RoomPKInvitedUpMicMember upMicMember = new RoomPKInvitedUpMicMember(); + upMicMember.setUid(String.valueOf(member.getUid())); + upMicMember.setNick(member.getNick()); + upMicMember.setGroupType(member.getGroupType()); + upMicMember.setPosition(micPosition); + PkModel.get().inviteInTeam( + Collections.singletonList(upMicMember) + ) + .subscribe(new BiConsumer() { + @Override + public void accept(String s, Throwable throwable) throws Exception { + if (throwable != null) { +// Toast.makeText(getContext(), throwable.getMessage(), Toast.LENGTH_SHORT).show(); + SingleToastUtil.showToastShort(throwable.getMessage()); + loadingDialog.dismiss(); + } + } + }); + + } else { + toast(ResUtil.getString(R.string.avroom_dialog_pkmicqueuedialog_05)); + loadingDialog.dismiss(); + } + } + + /** + * 将队列减一 + */ + private void reduceQueueInfo() { + if (queueMicListInfo != null) { + int count = queueMicListInfo.getCount(); + count--; + if (count < 0) { + count = 0; + } + queueMicListInfo.setCount(count); + } + } + + + public void removeQueueMember(String account) { + long removeUid = JavaUtil.str2long(account); + int removeIndex = -1; + int myQueuePos = -1; + for (int i = 0; i < adapter.getData().size(); i++) { + if (adapter.getData().get(i).getUid() == removeUid) { + removeIndex = i; + } + if (adapter.getData().get(i).getUid() == AuthModel.get().getCurrentUid()) { + myQueuePos = i; + } + } + if (removeIndex >= 0) { + //判断自己的位置是否需要减一 + if (AvRoomDataManager.get().myIsInQueue) { + if (myQueuePos >= 0 && myQueuePos > removeIndex) { + int newMyPos = queueMicListInfo.getMyPos() - 1; + if (newMyPos < 1) { + newMyPos = 1; + } + queueMicListInfo.setMyPos(newMyPos); + } + } + adapter.getData().remove(removeIndex); + adapter.notifyDataSetChanged(); + } + queueMicListInfo.setQueue(adapter.getData()); + reduceQueueInfo(); + if (adapter.getData().size() == 0) { + showNoDataLayout(); + return; + } + setTopLayout(); + } + + private void showNoDataLayout() { + srlRefreshContainer.setVisibility(View.GONE); + llNoDataContainer.setVisibility(View.VISIBLE); + flBottomButton.setVisibility(View.VISIBLE); + llJoinQueue.setVisibility(View.VISIBLE); + if (AvRoomDataManager.get().isManager()) { + flQueueCount.setVisibility(View.GONE); + tvNoDataTip.setText(getContext().getResources().getString(R.string.manager_no_mic_queue_tip)); + llJoinQueue.setVisibility(View.GONE); + tvExitQueue.setVisibility(View.GONE); + tvShareRoom.setVisibility(View.VISIBLE); + } else { + tvExitQueue.setVisibility(View.GONE); + tvShareRoom.setVisibility(View.GONE); + flQueueCount.setVisibility(View.VISIBLE); + tvMicQueueTip.setText(R.string.apply_mic_queue_tip); + //点击报名 + if (AvRoomDataManager.get().isOnMic(AuthModel.get().getCurrentUid())) { + llJoinQueue.setVisibility(View.VISIBLE); + } else { + tvJoinRed.setBackgroundResource(R.drawable.shape_pk_join_red_team_btn); + tvJoinBlue.setBackgroundResource(R.drawable.shape_pk_join_blue_team_btn); + } + tvNoDataTip.setText(getContext().getResources().getString(R.string.no_mic_queue_tip)); + } + } + + + private void showHaveDataLayout() { + srlRefreshContainer.setVisibility(View.VISIBLE); + llNoDataContainer.setVisibility(View.GONE); + setTopLayout(); + llJoinQueue.setVisibility(View.VISIBLE); + if (AvRoomDataManager.get().isManager()) { + flBottomButton.setVisibility(View.GONE); + } else { + tvShareRoom.setVisibility(View.GONE); + if (queueMicListInfo != null) { + flBottomButton.setVisibility(View.VISIBLE); + if (queueMicListInfo.getMyPos() < 0) { + //我不在队列 + //点击报名 + if (AvRoomDataManager.get().isOnMic(AuthModel.get().getCurrentUid())) { + //如果我在麦上 设置不可点击 + llJoinQueue.setVisibility(View.VISIBLE); + tvExitQueue.setVisibility(View.GONE); + } else { + llJoinQueue.setVisibility(View.VISIBLE); + tvExitQueue.setVisibility(View.GONE); + } + } else { + //我在队列 + //取消报名 + llJoinQueue.setVisibility(View.GONE); + tvExitQueue.setVisibility(View.VISIBLE); + } + } + } + } + + /** + * 顶部的布局 + */ + private void setTopLayout() { + if (AvRoomDataManager.get().isManager()) { + if (queueMicListInfo != null) { + tvMicQueueTip.setText( + createBuilder( + getContext().getResources().getString(R.string.curr_queue_member_count), + String.valueOf(queueMicListInfo.getCount()) + ) + ); + } + } else { + if (queueMicListInfo != null) { + if (queueMicListInfo.getMyPos() < 0) { + tvMicQueueTip.setText(R.string.please_to_apply_queue); + } else { + tvMicQueueTip.setText( + createBuilder( + getContext().getResources().getString(R.string.my_pos_in_queue), + String.valueOf(queueMicListInfo.getMyPos()) + ) + ); + } + } + } + } + + private SpannableStringBuilder createBuilder(String normalText, String spannableText) { + SpannableStringBuilder builder = new SpannableStringBuilder(); + builder.append(normalText); + SpannableString spannableString = new SpannableString(spannableText); + spannableString.setSpan( + new ForegroundColorSpan(getContext().getResources().getColor(R.color.appColor)), + 0, + spannableString.length(), + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + builder.append(spannableString); + return builder; + } + + //人邀请上麦后回来 + public void onUpMicro(String account) { + if (inviteAccount.equals(account) && loadingDialog != null && loadingDialog.isShowing()) { + loadingDialog.dismiss(); + } + } + + + /********************************回调*******************************************/ + + private OnActionListener actionListener; + + public interface OnActionListener { + void onShareRoom(PKMicQueueDialog micQueueDialog); + + void onApplyMicQueue(PKMicQueueDialog micQueueDialog, int teamId); + + void onCancelMicQueue(PKMicQueueDialog micQueueDialog); + } + + public void setActionListener(OnActionListener actionListener) { + this.actionListener = actionListener; + } + +} diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/PKSelectPeopleDialog.java b/app/src/main/java/com/chwl/app/avroom/dialog/PKSelectPeopleDialog.java new file mode 100644 index 0000000..27285c7 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/PKSelectPeopleDialog.java @@ -0,0 +1,242 @@ +package com.chwl.app.avroom.dialog; + +import android.content.Context; +import android.graphics.Rect; +import android.os.Bundle; +import android.text.TextUtils; +import android.util.SparseArray; +import android.view.View; +import android.widget.TextView; + +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.netease.nim.uikit.support.glide.GlideApp; +import com.chwl.app.R; +import com.chwl.app.common.widget.CircleImageView; +import com.chwl.app.ui.widget.dialog.BaseDialog; +import com.chwl.library.common.util.Utils; +import com.chwl.core.bean.RoomQueueInfo; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.room.pk.bean.PKMemberInfo; +import com.chwl.core.room.pk.model.PkModel; +import com.chwl.core.room.queue.bean.MicMemberInfo; +import com.chwl.library.utils.ResUtil; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @author jack + * @Description + * @Date 2019/1/2 + */ +public class PKSelectPeopleDialog extends BaseDialog implements View.OnClickListener { + + + private RecyclerView rvList; + private TextView tvOk; + MicAdapter micAdapter; + List micEntityList = new ArrayList<>(); + private int teamId = -1; + + private List pkMemberInfoList = new ArrayList<>(); + + public PKSelectPeopleDialog(Context context, int teamId, List pkMemberInfoList) { + super(context, R.style.easy_dialog_style); + this.teamId = teamId; + this.pkMemberInfoList = pkMemberInfoList; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setCanceledOnTouchOutside(true); + setContentView(R.layout.dialog_pk_select_people); + + rvList = (RecyclerView) findViewById(R.id.rv_list); + rvList.setLayoutManager(new GridLayoutManager(getContext(), 4)); + rvList.addItemDecoration(new RecyclerView.ItemDecoration() { + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { + super.getItemOffsets(outRect, view, parent, state); + outRect.top = Utils.dip2px(getContext(), 8); + outRect.bottom = Utils.dip2px(getContext(), 8); + } + }); + for (int i = 0; i < 9; i++) { + micEntityList.add(new MicEntity()); + } + micAdapter = new MicAdapter(getContext(), micEntityList); + micAdapter.setSpanSizeLookup(new BaseQuickAdapter.SpanSizeLookup() { + @Override + public int getSpanSize(GridLayoutManager gridLayoutManager, int position) { + if (position == 0) { + return 4; + } + return 1; + } + }); + rvList.setAdapter(micAdapter); + tvOk = (TextView) findViewById(R.id.tv_ok); + tvOk.setOnClickListener(this); + + initData(); + } + + private void initData() { + SparseArray micQueue = AvRoomDataManager.get().mMicQueueMemberMap; + int[] keys = new int[micQueue.size()]; + for (int i = 0; i < micQueue.size(); i++) { + keys[i] = micQueue.keyAt(i); + } + Arrays.sort(keys); + for (int i = 0; i < micEntityList.size(); i++) { + if (i >= micQueue.size()) { + continue; + } + RoomQueueInfo roomQueueInfo = micQueue.get(keys[i]); + MicMemberInfo chatRoomMember = roomQueueInfo.mChatRoomMember; + if (chatRoomMember != null) { + micEntityList.get(i).avatar = chatRoomMember.getAvatar(); + micEntityList.get(i).nick = chatRoomMember.getNick(); + micEntityList.get(i).uid = chatRoomMember.getAccount(); + micEntityList.get(i).gender = chatRoomMember.getGender(); + micEntityList.get(i).isSelect = false; + micEntityList.get(i).unSelectable = false; + //已经加入队伍的显示已经选择 + if (isAddInTeam(teamId, chatRoomMember.getAccount())) { + micEntityList.get(i).isSelect = true; + } + //已经加其他入队伍的不显示选择 + if (isAddInTeam(-1, chatRoomMember.getAccount()) + && !isAddInTeam(teamId, chatRoomMember.getAccount())) { + micEntityList.get(i).unSelectable = true; + } + + } + } + micAdapter.notifyDataSetChanged(); + } + + /** + * @param teamId + * @param account + * @return + */ + private boolean isAddInTeam(int teamId, String account) { + for (PKMemberInfo createPKMember : pkMemberInfoList) { + if (teamId == -1) { + if (String.valueOf(createPKMember.getUserInfo().getUid()).equals(account)) { + return true; + } + } else { + if (createPKMember.getTeamId() == teamId + && String.valueOf(createPKMember.getUserInfo().getUid()).equals(account)) { + return true; + } + } + } + return false; + } + + + @Override + public void onClick(View v) { + int id = v.getId(); + if (id == tvOk.getId()) { + dismiss(); + if (onSelectPeopleListener != null) { + onSelectPeopleListener.onSelectPeople(micAdapter.getData()); + } + } + } + + + class MicAdapter extends BaseQuickAdapter { + + private Context context; + + public MicAdapter(Context context, @Nullable List data) { + super(R.layout.item_pk_select_people_rv, data); + this.context = context; + } + + @Override + protected void convert(BaseViewHolder helper, MicEntity item) { + + CircleImageView civAvatar = (CircleImageView) helper.getView(R.id.civ_avatar); + TextView tvSelectMark = (TextView) helper.getView(R.id.tv_select_mark); + TextView tvName = (TextView) helper.getView(R.id.tv_name); + + if (TextUtils.isEmpty(item.uid)) { + civAvatar.setImageResource(R.mipmap.bg_pk_select_people_seat); + tvName.setText(helper.getAdapterPosition() + ResUtil.getString(R.string.avroom_dialog_pkselectpeopledialog_01)); + tvSelectMark.setVisibility(View.GONE); + helper.itemView.setOnClickListener(null); + } else { + GlideApp.with(context) + .load(item.avatar) + .dontAnimate() + .placeholder(R.drawable.default_avatar) + .into(civAvatar); + tvName.setText(item.nick); + if (!item.unSelectable) { + tvSelectMark.setVisibility(View.VISIBLE); + tvSelectMark.setSelected(item.isSelect); + helper.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (!item.isSelect && !isSelectUnderLimit()) { + toast(ResUtil.getString(R.string.avroom_dialog_pkselectpeopledialog_02)); + return; + } + micEntityList.get(helper.getAdapterPosition()).isSelect + = !micEntityList.get(helper.getAdapterPosition()).isSelect; + notifyItemChanged(helper.getAdapterPosition()); + } + }); + } else { + tvSelectMark.setVisibility(View.GONE); + tvSelectMark.setSelected(false); + helper.itemView.setOnClickListener(null); + } + } + + } + } + + private boolean isSelectUnderLimit() { + int selectSize = 0; + for (MicEntity micEntity : micEntityList) { + if (micEntity.isSelect) { + selectSize++; + } + } + return selectSize < PkModel.TEAM_MAX_SIZE; + } + + private OnSelectPeopleListener onSelectPeopleListener; + + public interface OnSelectPeopleListener { + void onSelectPeople(List userInfoList); + } + + public void setOnSelectPeopleListener(OnSelectPeopleListener onSelectPeopleListener) { + this.onSelectPeopleListener = onSelectPeopleListener; + } + + public class MicEntity { + public boolean unSelectable = false; + public boolean isSelect = false; + public String uid; + public String avatar; + public String nick; + public int gender; + + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/PKTimePickerDialog.java b/app/src/main/java/com/chwl/app/avroom/dialog/PKTimePickerDialog.java new file mode 100644 index 0000000..f838a51 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/PKTimePickerDialog.java @@ -0,0 +1,171 @@ +package com.chwl.app.avroom.dialog; + +import android.content.Context; +import android.os.Bundle; +import android.view.Gravity; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.TextView; +import android.widget.Toast; + +import com.jzxiang.pickerview.adapters.AbstractWheelTextAdapter; +import com.jzxiang.pickerview.adapters.NumericWheelAdapter; +import com.jzxiang.pickerview.config.PickerConfig; +import com.jzxiang.pickerview.utils.PickerContants; +import com.jzxiang.pickerview.wheel.WheelView; +import com.orhanobut.logger.Logger; +import com.chwl.app.R; +import com.chwl.app.ui.widget.dialog.BaseDialog; +import com.chwl.library.utils.ResUtil; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * @author jack + * @Description + * @Date 2018/12/29 + */ +public class PKTimePickerDialog extends BaseDialog implements View.OnClickListener { + Context context; + + private TextView tvCancel; + private TextView tvOk; + private WheelView wvMinute; + private WheelView wvSecond; + + private NumericWheelAdapter minuteAdapter; + private SecondAdapter secondAdapter; + + private int selectMinute = 0; + private int selectSecond = 30; + + public PKTimePickerDialog(Context context) { + super(context, R.style.bottom_dialog); + this.context = context; + Window window = getWindow(); + if (window != null) { + WindowManager.LayoutParams lps = window.getAttributes(); + lps.width = WindowManager.LayoutParams.MATCH_PARENT; + lps.height = WindowManager.LayoutParams.WRAP_CONTENT; + lps.gravity = Gravity.BOTTOM; + window.setAttributes(lps); + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setCanceledOnTouchOutside(false); + setContentView(R.layout.dialog_pk_pick_time); + + tvCancel = (TextView) findViewById(R.id.tv_cancel); + tvOk = (TextView) findViewById(R.id.tv_ok); + wvMinute = (WheelView) findViewById(R.id.wv_minute); + wvSecond = (WheelView) findViewById(R.id.wv_second); + + tvCancel.setOnClickListener(this); + tvOk.setOnClickListener(this); + + PickerConfig pickerConfig = new PickerConfig(); + pickerConfig.mWheelTVNormalColor = getContext().getResources().getColor(R.color.color_999999); + pickerConfig.mWheelTVSelectorColor = getContext().getResources().getColor(R.color.black); + pickerConfig.mWheelTVSize = 16; + pickerConfig.cyclic = true; + pickerConfig.mThemeColor = getContext().getResources().getColor(R.color.color_FFFFFF); + + minuteAdapter = new NumericWheelAdapter(getContext(), 0, 30, PickerContants.FORMAT, ResUtil.getString(R.string.avroom_dialog_pktimepickerdialog_01)); + minuteAdapter.setConfig(pickerConfig); + wvMinute.setConfig(pickerConfig); + wvMinute.setViewAdapter(minuteAdapter); + wvMinute.setCurrentItem(selectMinute, false); + wvMinute.setCyclic(pickerConfig.cyclic); + wvMinute.addChangingListener((wheel, oldValue, newValue) -> { + selectMinute = newValue; + if (selectMinute == 0) { + secondAdapter.setSecondSelectData(Collections.singletonList(30)); + wvSecond.setCurrentItem(0, false); + selectSecond = 30; + } else if (selectMinute == 30) { + secondAdapter.setSecondSelectData(Collections.singletonList(0)); + wvSecond.setCurrentItem(0, false); + selectSecond = 0; + } else { + secondAdapter.setSecondSelectData(Arrays.asList(0, 30)); + wvSecond.setCurrentItem(0, false); + selectSecond = 0; + } + }); + + PickerConfig secConfig = new PickerConfig(); + secConfig.mWheelTVNormalColor = getContext().getResources().getColor(R.color.color_999999); + secConfig.mWheelTVSelectorColor = getContext().getResources().getColor(R.color.black); + secConfig.mWheelTVSize = 16; + secConfig.cyclic = false; + secConfig.mThemeColor = getContext().getResources().getColor(R.color.color_FFFFFF); + + secondAdapter = new SecondAdapter(getContext()); + secondAdapter.setSecondSelectData(Collections.singletonList(30)); + secondAdapter.setConfig(secConfig); + wvSecond.setConfig(secConfig); + wvSecond.setViewAdapter(secondAdapter); + wvSecond.setCurrentItem(0, false); + wvSecond.setCyclic(false); + wvSecond.addChangingListener((wheel, oldValue, newValue) -> { + selectSecond = secondAdapter.date.get(newValue); + }); + } + + + @Override + public void onClick(View v) { + int id = v.getId(); + if (id == tvCancel.getId()) { + dismiss(); + } else if (id == tvOk.getId()) { + dismiss(); + Logger.i(ResUtil.getString(R.string.avroom_dialog_pktimepickerdialog_02) + selectMinute + ResUtil.getString(R.string.avroom_dialog_pktimepickerdialog_03) + selectSecond + ResUtil.getString(R.string.avroom_dialog_pktimepickerdialog_04), Toast.LENGTH_SHORT); + if (null != onSelectTime) { + onSelectTime.selectTime((long) (selectMinute * 60 + selectSecond)); + } + } + } + + private OnSelectTime onSelectTime; + + public interface OnSelectTime { + void selectTime(long timeSecond); + } + + public void setOnSelectTime(OnSelectTime onSelectTime) { + this.onSelectTime = onSelectTime; + } + + private class SecondAdapter extends AbstractWheelTextAdapter { + + List date = new ArrayList<>(); + + protected SecondAdapter(Context context) { + super(context); + } + + @Override + protected CharSequence getItemText(int index) { + return String.format("%02d", date.get(index)) + ResUtil.getString(R.string.avroom_dialog_pktimepickerdialog_05); + } + + @Override + public int getItemsCount() { + return date.size(); + } + + public void setSecondSelectData(List date) { + this.date = date; + notifyDataChangedEvent(); + notifyDataInvalidatedEvent(); + } + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/RequestUpMicDialog.kt b/app/src/main/java/com/chwl/app/avroom/dialog/RequestUpMicDialog.kt new file mode 100644 index 0000000..2fa2d74 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/RequestUpMicDialog.kt @@ -0,0 +1,44 @@ +package com.chwl.app.avroom.dialog + +import android.content.Context +import android.view.View +import com.chwl.app.R +import com.chwl.app.databinding.DialogRequestUpmicBinding +import com.chwl.app.base.BaseBindingDialog +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.manager.IMNetEaseManager +import com.chwl.core.user.bean.BaseInfo +import com.chwl.core.user.bean.UserInfo +import com.chwl.library.annatation.ActLayoutRes + +@ActLayoutRes(R.layout.dialog_request_upmic) +class RequestUpMicDialog(context: Context) : + BaseBindingDialog(context, R.style.dialog), + View.OnClickListener { + private var userInfo: UserInfo? = null + override fun init() { + binding.click = this + } + + override fun onClick(v: View) { + when (v.id) { + R.id.btn_cancel -> { + closeDialog() + } + R.id.btn_ok -> { + userInfo?.let { + val baseInfo = BaseInfo(it.uid, it.nick) + val position = AvRoomDataManager.get().findFreePosition() + if ( position == Int.MIN_VALUE) return@let + IMNetEaseManager.get().inviteMicroPhoneBySdk(baseInfo, position ).subscribe() + } + closeDialog() + } + } + } + + fun setUser(userInfo: UserInfo) { + this.userInfo = userInfo + binding.user = userInfo + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/RoomBgPreviewDialog.kt b/app/src/main/java/com/chwl/app/avroom/dialog/RoomBgPreviewDialog.kt new file mode 100644 index 0000000..b4d0bfa --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/RoomBgPreviewDialog.kt @@ -0,0 +1,155 @@ +package com.chwl.app.avroom.dialog + +import android.view.Gravity +import android.view.WindowManager +import com.chwl.app.R +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.common.widget.dialog.DialogManager +import com.chwl.app.databinding.DialogRoomBgPreviewBinding +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.core.bean.response.ServiceResult +import com.chwl.core.file.FileModel +import com.chwl.core.gift.bean.RoomBgInfoItem +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.utils.net.RxHelper +import com.chwl.library.common.util.isVerify +import com.chwl.library.net.rxnet.RxNet +import com.example.lib_utils.ktx.getString +import com.google.gson.JsonElement +import com.hjq.toast.ToastUtils +import io.reactivex.Single +import retrofit2.http.POST +import retrofit2.http.Query +import java.io.File + +class RoomBgPreviewDialog : BaseDialogFragment() { + + + + override var width = WindowManager.LayoutParams.MATCH_PARENT + override var height = WindowManager.LayoutParams.MATCH_PARENT + override var dimAmount = 0.3f + override var gravity = Gravity.BOTTOM + + var isBuy = false + var mFile : File?=null + var mRoomBgInfoItem : RoomBgInfoItem?=null + var mDialog : DialogManager?=null + var mCallBack : CallBack?=null + + + override fun init() { + mDialog = DialogManager(requireActivity()) + binding.btnBack.setOnClickListener { + dismiss() + } + binding.close.setOnClickListener { + dismiss() + } + + mRoomBgInfoItem?.let { data-> + + binding.btnConfirm.setOnClickListener { + if (isBuy) { + buyBg() + } else { + mFile?.let { it1 -> upLoadImage(it1) } + } + } + + if (isBuy) { + binding.bg.loops + binding.bg.loadUrl(data.url) + binding.btnConfirm.text = R.string.buy.getString() + binding.hint.text = R.string.Purchases_hint.getString() + } else { + binding.btnConfirm.text = R.string.layout_activity_modify_pwd_07.getString() + binding.hint.text = R.string.Purchases_hint2.getString() + ImageLoadUtils.loadImage(context,mFile,binding.bg) + } + + binding.price.text = R.string.s_sDays.getString(data.goldPrice,(data.buyHour/24).toInt()) + } + + + } + + private fun buyBg() { + mRoomBgInfoItem?.let { data-> + postBuy(data.id) + .compose(bindToLifecycle()) + .doOnSuccess { + ToastUtils.show(R.string.doSuccess) + mCallBack?.onSuccess() + dismiss() + } + .doOnError { + it?.message?.let { msg-> + ToastUtils.show(msg) + } + dismiss() + } + .subscribe() + } + + } + + private fun upLoadImage(file: File) { + mDialog?.showProgressDialog(requireActivity()) + FileModel.get() + .uploadFile(file.path) + .compose(bindToLifecycle()) + .doOnSuccess { + if (it.isVerify()) { + postCustom(it) + .compose(bindToLifecycle()) + .doOnSuccess { + ToastUtils.show(R.string.doSuccess) + mCallBack?.onSuccess() + dismiss() + } + .doOnError { er-> + er?.message?.let { msg -> + ToastUtils.show(msg) + } + dismiss() + } + .subscribe() + } + mDialog?.dismissDialog() + } + .doOnError { + it?.message?.let { msg-> + ToastUtils.show(msg) + } + mDialog?.dismissDialog() + } + .subscribe() + } + + private fun postCustom(url: String): Single { + return api.postCustom(AvRoomDataManager.get().roomUid,url) + .compose(RxHelper.handleIgnoreData()) + .compose(RxHelper.handleSchedulers()) + } + + private fun postBuy(id: Long): Single { + return api.postBuy(AvRoomDataManager.get().roomUid,id) + .compose(RxHelper.handleIgnoreData()) + .compose(RxHelper.handleSchedulers()) + } + + private val api: Api = RxNet.create(Api::class.java); + interface Api { + @POST("/room/background/custom") + fun postCustom(@Query("roomUid") roomUid: Long,@Query("url") url: String): Single> + @POST("/room/background/buy") + fun postBuy(@Query("roomUid") roomUid: Long,@Query("id") id: Long): Single> + } + + public interface CallBack{ + fun onSuccess() + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/RoomBgSetDialog.kt b/app/src/main/java/com/chwl/app/avroom/dialog/RoomBgSetDialog.kt new file mode 100644 index 0000000..c38f22a --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/RoomBgSetDialog.kt @@ -0,0 +1,543 @@ +package com.chwl.app.avroom.dialog + +import android.app.Activity.RESULT_OK +import android.content.Intent +import android.graphics.Color +import android.view.Gravity +import android.view.WindowManager +import android.widget.TextView +import androidx.core.view.isVisible +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.chwl.app.R +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.base.PhotoPickActivity +import com.chwl.app.bindadapter.BaseBindingAdapter +import com.chwl.app.bindadapter.BaseBindingViewHolder +import com.chwl.app.common.EmptyViewHelper +import com.chwl.app.common.widget.dialog.DialogManager +import com.chwl.app.databinding.DialogRoomBgSetBinding +import com.chwl.app.databinding.ItemRoomBgSetBinding +import com.chwl.core.bean.response.ServiceResult +import com.chwl.core.gift.bean.RoomBgInfo +import com.chwl.core.gift.bean.RoomBgInfoItem +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.utils.myutil.MyUriUtils +import com.chwl.core.utils.net.RxHelper +import com.chwl.library.common.util.ClickUtils.click +import com.chwl.library.common.util.setVis +import com.chwl.library.net.rxnet.RxNet +import com.example.lib_utils.ktx.dp +import com.example.lib_utils.ktx.getColor +import com.example.lib_utils.ktx.getDimension +import com.example.lib_utils.ktx.getString +import com.google.gson.JsonElement +import com.hjq.toast.ToastUtils +import io.reactivex.Single +import retrofit2.http.GET +import retrofit2.http.POST +import retrofit2.http.Query +import java.io.File + +class RoomBgSetDialog : BaseDialogFragment() { + + override var width = WindowManager.LayoutParams.MATCH_PARENT + override var height = R.dimen.dp_323.getDimension().toInt() + override var dimAmount = 0f + override var gravity = Gravity.BOTTOM + + lateinit var mAdapter: RoomBgAdapter + + private var mDataFree = mutableListOf() + private var mDataPay = mutableListOf() + private var mDataCustom = mutableListOf() + + private var mCustomGoldPrice = 0 + private var mCustomHour = 0 + + private var mSelectType = RoomBgInfo.Type.T_FREE + + private val PICK_CODE = 1113 + + + override fun init() { + + mAdapter = RoomBgAdapter() + mAdapter.setNewData(mutableListOf()) + mAdapter.setEmptyView(EmptyViewHelper.createEmptyTextViewHeight(context, R.string.empty_data.getString())) + + binding.rvList.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false) + binding.rvList.adapter = mAdapter + + mAdapter.setOnItemChildClickListener { adapter, view, position -> + val data = mAdapter.data.getOrNull(position) + when (view.id) { + R.id.statusPlay, R.id.statusBuy -> { + data?.let { + if (it.type == RoomBgInfo.Type.T_CUSTOM) { + if (it.status != RoomBgInfo.Status.S_REJECT && it.status != RoomBgInfo.Status.S_REVIEW) { + showPreViewDialog(null, data, true) + } + } else { + showPreViewDialog(null, data, true) + } + } + } + + R.id.statusDel -> { + data?.let { + del(data) + } + } + + R.id.bg -> { + data?.let { + select(data) + } + } + + else -> {} + } + + } + + binding.btnFree.click { + setViewSelect(RoomBgInfo.Type.T_FREE) + } + binding.btnPay.click { + setViewSelect(RoomBgInfo.Type.T_PAY) + } + binding.btnCustom.click { + setViewSelect(RoomBgInfo.Type.T_CUSTOM) + } + + binding.btnCreate.click { + PhotoPickActivity.startImg(requireActivity(),PICK_CODE) + } + + binding.btnMore.click { + val dialogManager = DialogManager(context) + dialogManager.showOkCancelDialog(R.string.tip_tips.getString(),R.string.Purchases_hint_info.getString(),R.string.ok.getString(),null,true,null) + val window = dialogManager?.dialog?.window + val tip = window?.findViewById(R.id.message) + tip?.gravity = Gravity.START + } + + getData() + + } + + private fun getData() { + getBoomInfo(AvRoomDataManager.get().roomUid) + .compose(bindToLifecycle()) + .doOnSuccess { data -> + if (data != null) { + + mCustomHour = data.customHour + mCustomGoldPrice = data.customGoldPrice + + mDataFree.clear() + mDataPay.clear() + mDataCustom.clear() + + data.itemList.let { + val map = it.groupBy { it.type } + + if (map.containsKey(RoomBgInfo.Type.T_FREE)){ + mDataFree = map[RoomBgInfo.Type.T_FREE] as MutableList + } + + if (map.containsKey(RoomBgInfo.Type.T_PAY)) { + val newData = mutableListOf() + val pays = map[RoomBgInfo.Type.T_PAY] as MutableList + val groupBy = pays.groupBy { it.status } + + if (groupBy.containsKey(RoomBgInfo.Status.S_SUCCESS)) { + val paySuccess = groupBy[RoomBgInfo.Status.S_SUCCESS] as MutableList + paySuccess.sortByDescending { pay-> pay.remainHour } + newData.addAll(paySuccess) + } + + if (groupBy.containsKey(RoomBgInfo.Status.S_EXPIRED)) { + val paySuccess = groupBy[RoomBgInfo.Status.S_EXPIRED] as MutableList + newData.addAll(paySuccess) + } + + if (groupBy.containsKey(RoomBgInfo.Status.S_REVIEW)) { + val paySuccess = groupBy[RoomBgInfo.Status.S_REVIEW] as MutableList + newData.addAll(paySuccess) + } + + if (groupBy.containsKey(RoomBgInfo.Status.S_REJECT)) { + val paySuccess = groupBy[RoomBgInfo.Status.S_REJECT] as MutableList + newData.addAll(paySuccess) + } + + mDataPay = newData + } + + if (map.containsKey(RoomBgInfo.Type.T_CUSTOM)) { + + val newData = mutableListOf() + val customs = map[RoomBgInfo.Type.T_CUSTOM] as MutableList + val groupBy = customs.groupBy { it.status } + + if (groupBy.containsKey(RoomBgInfo.Status.S_SUCCESS)) { + val customsSuccess = groupBy[RoomBgInfo.Status.S_SUCCESS] as MutableList + customsSuccess.sortByDescending { customs-> customs.remainHour } + newData.addAll(customsSuccess) + } + + if (groupBy.containsKey(RoomBgInfo.Status.S_EXPIRED)) { + val customsSuccess = groupBy[RoomBgInfo.Status.S_EXPIRED] as MutableList + newData.addAll(customsSuccess) + } + + if (groupBy.containsKey(RoomBgInfo.Status.S_REVIEW)) { + val customsSuccess = groupBy[RoomBgInfo.Status.S_REVIEW] as MutableList + newData.addAll(customsSuccess) + } + + if (groupBy.containsKey(RoomBgInfo.Status.S_REJECT)) { + val customsSuccess = groupBy[RoomBgInfo.Status.S_REJECT] as MutableList + newData.addAll(customsSuccess) + } + + mDataCustom = newData + } + + + } + + setViewSelect(mSelectType) + } + + } + .doOnError { + it?.message?.let { msg -> + ToastUtils.show(msg) + } + } + .subscribe() + } + + private fun del(data: RoomBgInfoItem) { + if (data.type != RoomBgInfo.Type.T_CUSTOM) return + val dialog = DialogManager(requireActivity()) + dialog.showOkCancelDialog(R.string.community_photo_bigphotoactivity_08.getString(),object : DialogManager.AbsOkDialogListener() { + override fun onOk() { + postDel(data.id) + .compose(bindToLifecycle()) + .doOnSuccess { + ToastUtils.show(R.string.doSuccess) + getData() + } + .doOnError { + it?.message?.let { msg -> + ToastUtils.show(msg) + } + } + .subscribe() + } + }) + + } + + private fun select(data: RoomBgInfoItem) { + if (data.remainHour != -1 || data.type == RoomBgInfo.Type.T_FREE) { + if (data.status == RoomBgInfo.Status.S_SUCCESS) { + postSelect(data.id) + .compose(bindToLifecycle()) + .doOnSuccess { + ToastUtils.show(R.string.doSuccess) + dismiss() + } + .doOnError { + dismiss() + } + .subscribe() + } + } else { + if (data.status == RoomBgInfo.Status.S_REJECT || data.status == RoomBgInfo.Status.S_REVIEW) return // 拒審只能刪除 + showPreViewDialog(null, data, true) + } + } + + private fun setViewSelect(type: Int) { + binding.btnMore.setVis(false) + binding.btnCreate.setVis(false) + binding.btnFree.setTextColor(if (type == RoomBgInfo.Type.T_FREE) R.color.white.getColor() else R.color.white_tran_60.getColor()) + binding.btnPay.setTextColor(if (type == RoomBgInfo.Type.T_PAY) R.color.white.getColor() else R.color.white_tran_60.getColor()) + binding.btnCustom.setTextColor(if (type == RoomBgInfo.Type.T_CUSTOM) R.color.white.getColor() else R.color.white_tran_60.getColor()) + val text = mAdapter.emptyView?.findViewById(R.id.tv_hint) + text?.text = R.string.empty_data.getString() + mSelectType = type + when (type) { + RoomBgInfo.Type.T_FREE -> { + mAdapter.setNewData(mDataFree) + } + + RoomBgInfo.Type.T_PAY -> { + mAdapter.setNewData(mDataPay) + } + + RoomBgInfo.Type.T_CUSTOM -> { + mAdapter.setNewData(mDataCustom) + text?.text = R.string.empty_customize_bg.getString() + binding.btnMore.setVis(true) + binding.btnCreate.setVis(true) + } + } + } + + @Deprecated("Deprecated in Java") + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (resultCode == RESULT_OK) { + if (requestCode == PICK_CODE) { + val uri = data?.data + if (uri != null) { + if (MyUriUtils.isGif(requireActivity(), uri)) { + ToastUtils.show(R.string.error_file_type) + return + } + + val file = MyUriUtils.copyFile(requireActivity(), uri) + if (file != null) { + showPreViewDialog(file, RoomBgInfoItem().apply { + goldPrice = mCustomGoldPrice + buyHour = mCustomHour + }, false) + } else { + ToastUtils.show(R.string.exception_try_again) + } + } + } + } + } + + private fun showPreViewDialog(file: File?, data:RoomBgInfoItem, buy: Boolean) { + context?.let { + RoomBgPreviewDialog().apply { + mFile = file + mRoomBgInfoItem = data + isBuy = buy + mCallBack = object : RoomBgPreviewDialog.CallBack { + override fun onSuccess() { + getData() + } + } + }.show(it) + } + + } + + + class RoomBgAdapter() : BaseBindingAdapter() { + + + override fun convert( + helper: BaseBindingViewHolder, + data: RoomBgInfoItem + ) { + + val binding = helper.binding + defViewStatus(binding) + + data?.let { data -> + + binding.bg.loadUrl(data.url ?: "") + binding.select.setVis(data.isCur) + + + binding.statusPlay.setVis(data.url?.endsWith(".svga") == true) + binding.statusGif.setVis(data.url?.endsWith(".svga") == true) + + if (data.type == RoomBgInfo.Type.T_FREE) { + + val bindingAdapterPosition = helper.bindingAdapterPosition + if (bindingAdapterPosition == 0) { + binding.statusLimit.text = R.string.Original.getString() + binding.statusLimit.changeSoildColor(R.color.black_transparent_50.getColor()) + } + binding.statusLimit.setVis(bindingAdapterPosition == 0) + + + + } else if (data.type == RoomBgInfo.Type.T_PAY) { + + //有时长显示 左上角剩余时间 + binding.statusLimit.setVis(data.remainHour != -1) + binding.statusLimit.text = getTimeText(data.remainHour) + binding.statusLimit.changeSoildColor(R.color.black_transparent_50.getColor()) + + + + + + binding.price.text = getPriceText(data.goldPrice,data.buyHour) + binding.price.setVis(true) + + binding.statusBuy.setVis(true) + if (data.remainHour != -1) { //有剩余时长是 renew + binding.statusBuy.text = R.string.Renew.getString() + binding.statusBuy.setTextColor(R.color.white.getColor()) + binding.statusBuy.setGradientDrawable( + Color.parseColor("#373639"), + -1, + Color.parseColor("#373639"), + -1, + -1f + ) + binding.statusBuy.changeStrikeColor(R.color.white.getColor(), 1.dp) + } else { // 没有是buy + binding.statusBuy.text = R.string.buy.getString() + binding.statusBuy.setTextColor(R.color.white.getColor()) + binding.statusBuy.setGradientDrawable( + Color.parseColor("#E29030"), + -1, + Color.parseColor("#FCC074"), + -1, + -1f + ) + binding.statusBuy.changeStrikeColor(R.color.transparent.getColor(), 0) + } + + } else if (data.type == RoomBgInfo.Type.T_CUSTOM) { + + + binding.statusLimit.setVis(true) + if (data.status == RoomBgInfo.Status.S_EXPIRED) { //过期 就展示 左上角 过期图标 + binding.statusLimit.text = R.string.Expired.getString() + binding.statusLimit.changeSoildColor(R.color.color_696969.getColor()) + } else { + if (data.remainHour != -1) { //非过期,有时长就展示 没有就隐藏 + binding.statusLimit.text = getTimeText(data.remainHour) + binding.statusLimit.changeSoildColor(R.color.black_transparent_50.getColor()) + } else { + binding.statusLimit.setVis(false) + } + } + + binding.statusDel.setVis(data.status != RoomBgInfo.Status.S_REVIEW) + + binding.price.text = getPriceText(data.goldPrice,data.buyHour) + binding.price.setVis(true) + + binding.statusBuy.setVis(true) + if (data.status == RoomBgInfo.Status.S_REVIEW) { // 审核中 + binding.statusBuy.text = R.string.in_review.getString() + binding.statusBuy.setTextColor(R.color.color_ff9741.getColor()) + binding.statusBuy.setGradientDrawable( + Color.parseColor("#00000000"), + -1, + Color.parseColor("#00000000"), + -1, + -1f + ) + binding.statusBuy.changeStrikeColor(R.color.color_ff9741.getColor(), 1.dp) + } else if (data.status == RoomBgInfo.Status.S_EXPIRED || data.status == RoomBgInfo.Status.S_SUCCESS) { //过期和通过审核 显示 renew + binding.statusBuy.text = R.string.Renew.getString() + binding.statusBuy.setTextColor(R.color.white.getColor()) + binding.statusBuy.setGradientDrawable( + Color.parseColor("#00000000"), + -1, + Color.parseColor("#00000000"), + -1, + -1f + ) + binding.statusBuy.changeStrikeColor(R.color.white.getColor(), 1.dp) + } else if (data.status == RoomBgInfo.Status.S_REJECT) { //不过审 + binding.statusBuy.text = R.string.Reject.getString() + binding.statusBuy.setTextColor(R.color.color_ff5656.getColor()) + binding.statusBuy.setGradientDrawable( + Color.parseColor("#00000000"), + -1, + Color.parseColor("#00000000"), + -1, + -1f + ) + binding.statusBuy.changeStrikeColor(R.color.color_ff5656.getColor(), 1.dp) + } + + } + + + } + + helper.addOnClickListener(R.id.statusPlay) + helper.addOnClickListener(R.id.statusBuy) + helper.addOnClickListener(R.id.statusDel) + helper.addOnClickListener(R.id.bg) + } + + private fun defViewStatus(binding: ItemRoomBgSetBinding) { + binding.statusLimit.isVisible = false + binding.statusGif.isVisible = false + binding.statusPlay.isVisible = false + binding.statusDel.isVisible = false + binding.price.isVisible = false + binding.statusBuy.isVisible = false + } + + private fun getTimeText( hour:Int): String { + var text = "" + if (hour >= 24) { + text = R.string.sDays.getString((hour / 24).toInt()) + } else { + text = R.string.unDay.getString() + } + return text + } + + + private fun getPriceText( price :Int,hour:Int): String { + return R.string.s_sDays.getString(price,(hour / 24).toInt()) + } + + + } + + + private fun getBoomInfo(roomUid: Long): Single { + return api.getBoomInfo(roomUid) + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()) + } + + private fun postDel(id: Long): Single { + return api.postDel(AvRoomDataManager.get().roomUid, id) + .compose(RxHelper.handleIgnoreData()) + .compose(RxHelper.handleSchedulers()) + } + + private fun postSelect(id: Long): Single { + return api.postSelect(AvRoomDataManager.get().roomUid, id) + .compose(RxHelper.handleIgnoreData()) + .compose(RxHelper.handleSchedulers()) + } + + + private val api: Api = RxNet.create(Api::class.java); + + interface Api { + @GET("/room/background/list") + fun getBoomInfo(@Query("roomUid") roomUid: Long): Single> + + @POST("/room/background/del") + fun postDel( + @Query("roomUid") roomUid: Long, + @Query("id") id: Long + ): Single> + + @POST("/room/background/select") + fun postSelect( + @Query("roomUid") roomUid: Long, + @Query("id") id: Long + ): Single> + } + + + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/RoomBoomInfoDialog.kt b/app/src/main/java/com/chwl/app/avroom/dialog/RoomBoomInfoDialog.kt new file mode 100644 index 0000000..9f639f1 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/RoomBoomInfoDialog.kt @@ -0,0 +1,201 @@ +package com.chwl.app.avroom.dialog + +import android.graphics.Color +import android.view.Gravity +import android.view.View +import android.view.WindowManager +import android.widget.ImageView +import com.chwl.app.R +import com.chwl.app.application.GlobalHandleManager +import com.chwl.app.avroom.widget.GalleryLayoutManager.LayoutParams +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.databinding.DialogRoomBoomInfoBinding +import com.chwl.app.databinding.ItemRoomBoomInfoLevelBinding +import com.chwl.app.ui.utils.loadAnim2 +import com.chwl.app.ui.utils.loadImage +import com.chwl.app.ui.webview.CommonWebViewActivity +import com.chwl.app.ui.webview.DialogWebViewActivity +import com.chwl.core.UriProvider +import com.chwl.core.auth.AuthModel +import com.chwl.core.bean.response.ServiceResult +import com.chwl.core.gift.bean.BoomInfo +import com.chwl.core.user.UserModel +import com.chwl.core.utils.net.RxHelper +import com.chwl.library.common.util.isVerify +import com.chwl.library.common.util.setRL +import com.chwl.library.common.util.setViewWH +import com.chwl.library.common.util.setVis +import com.chwl.library.net.rxnet.RxNet +import com.example.lib_utils.ktx.dp +import com.example.lib_utils.ktx.getString +import com.tencent.qgame.animplayer.AnimView +import io.reactivex.Single +import retrofit2.http.GET +import retrofit2.http.Query + +class RoomBoomInfoDialog : BaseDialogFragment() { + + + override var width = WindowManager.LayoutParams.MATCH_PARENT + override var height = 658.dp + override var dimAmount = 0f + override var gravity = Gravity.BOTTOM + + public var roomUid = -1L + public var mCallBack :CallBack? = null + private var indexLevel = 0; + + + override fun init() { + if (roomUid > 0) { + getBoomInfo(roomUid) + .compose(bindToLifecycle()) + .doOnSuccess { + setView(it) + } + .doOnError { + + } + .subscribe() + } + + binding.btn2.setOnClickListener { + mCallBack?.onClick(0,0) + } + + binding.more2.setOnClickListener { + val activity = GlobalHandleManager.get().activity ?: return@setOnClickListener + DialogWebViewActivity.start(activity, UriProvider.getBoomRule(UserModel.get().partitionId), true) + } + binding.more3.setOnClickListener { + val activity = GlobalHandleManager.get().activity ?: return@setOnClickListener + DialogWebViewActivity.start(activity, UriProvider.getBoomRule(UserModel.get().partitionId), true) + } + + binding.levelLayoutBg.setRL() + + } + + private fun setView(boomInfos: List) { + val sortedByDescending = boomInfos.sortedByDescending { it.level } + sortedByDescending.forEachIndexed{ index, boomInfo -> + val levelView = ItemRoomBoomInfoLevelBinding.inflate(layoutInflater, binding.levelLayout, true) + levelView.root.setBackgroundResource(R.color.transparent) + levelView.levelText.text="LV.${boomInfo.level}" + levelView.levelIcon.loadImage(boomInfo.pic) + levelView.root.tag = boomInfo + levelView.root.setOnClickListener { + val tag = it.tag + if (tag != null && tag is BoomInfo){ + if (indexLevel != tag.level) { + indexLevel = tag.level + setInfo(tag) + for (i in 0 until binding.levelLayout.childCount) { + val view = binding.levelLayout.getChildAt(i) + view.setBackgroundResource(R.color.transparent) + } + it.setBackgroundColor(Color.parseColor("#9739ff")) + } + } + } + + if (boomInfo.currLevel) { + levelView.root.setBackgroundColor(Color.parseColor("#9739ff")) + indexLevel = boomInfo.level + setInfo(boomInfo) + mCallBack?.onCurrBoomInfo(boomInfo) + } + } + + } + + private fun setInfo(indexData: BoomInfo?) { + indexData?.let { + reSetView() + if (it.rank && it.roomBoomRankVos.isVerify()) { + binding.avatarLayout.setVis(true) + binding.rewardLayout.visibility = View.INVISIBLE + it.roomBoomRankVos.forEach { rank-> + if (rank.position == 1) { + binding.avatar1.loadImage(rank.avatar) + binding.nick1.text = rank.nick + }else if (rank.position == 2) { + binding.avatar2.loadImage(rank.avatar) + binding.nick2.text = rank.nick + }else if (rank.position == 3) { + binding.avatar3.loadImage(rank.avatar) + binding.nick3.text = rank.nick + } + } + + } else if (it.roomBoomLevelAwardVos.isVerify()){ + binding.rewardLayout.setVis(true) + binding.avatarLayout.visibility = View.INVISIBLE + it.roomBoomLevelAwardVos.forEachIndexed { index, boomInfoAward -> + val childAt = binding.rewardList.getChildAt(index) + if (childAt != null && childAt is ImageView && boomInfoAward.awardPic.isVerify()) { + childAt.loadImage(boomInfoAward.awardPic) + } + } + } + + setPro(indexData.speed,indexData.level) + + + binding.recordAnimLayout.removeAllViews() + val animView = AnimView(binding.recordAnimLayout.context) + binding.recordAnimLayout.addView(animView) + val layoutParams = animView.layoutParams + layoutParams.width = LayoutParams.MATCH_PARENT + layoutParams.height = LayoutParams.MATCH_PARENT + animView.layoutParams = layoutParams + animView.setLoop(Int.MAX_VALUE) + animView.loadAnim2(it.vapUrl) + + if (UserModel.get().isArUser) { + binding.avatarTime.text = R.string.roomBoomInfoRankHint2.getString() + } else { + binding.avatarTime.text = R.string.roomBoomInfoRankHint.getString() + } + + } + } + + private fun reSetView() { + binding.avatar1.setImageResource(R.drawable.default_avatar) + binding.avatar2.setImageResource(R.drawable.default_avatar) + binding.avatar3.setImageResource(R.drawable.default_avatar) + binding.nick1.text = "" + binding.nick2.text = "" + binding.nick3.text = "" + } + + + fun setPro(speed: Int, level: Int) { + if (level != indexLevel) return + binding.proMax.post{ + val max = binding.proMax.height + binding.pro.setViewWH(height = (max * (speed.toFloat() / 100)).toInt(), isDP = false) + binding.proVal.text = speed.toString() + } + } + + private fun getBoomInfo(roomUid: Long): Single> { + return api.getBoomInfo(roomUid) + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()) + } + + + + private val api: Api = RxNet.create(Api::class.java); + interface Api { + @GET("/room/boom/level/info") + fun getBoomInfo(@Query("roomUid") roomUid: Long): Single>> + } + + public interface CallBack{ + fun onCurrBoomInfo(boomInfo: BoomInfo) + fun onClick(type: Int,data:Any) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/RoomBoomRewardDialog.kt b/app/src/main/java/com/chwl/app/avroom/dialog/RoomBoomRewardDialog.kt new file mode 100644 index 0000000..5b3a5de --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/RoomBoomRewardDialog.kt @@ -0,0 +1,89 @@ +package com.chwl.app.avroom.dialog + +import android.content.Context +import android.view.Gravity +import android.view.LayoutInflater +import android.view.View +import com.chwl.app.R +import com.chwl.app.bindadapter.BaseAdapter +import com.chwl.app.bindadapter.BindingViewHolder +import com.chwl.app.databinding.RoomBoomRewardBinding +import com.chwl.app.databinding.RoomBoomRewardItemBinding +import com.chwl.app.ui.utils.loadImage +import com.chwl.core.auth.AuthModel +import com.chwl.core.gift.bean.BoomMsgAwardBean +import com.chwl.library.common.util.isVerify +import com.chwl.library.common.util.setViewWH +import com.chwl.library.common.util.setVis +import com.example.lib_utils.ktx.getString + +class RoomBoomRewardDialog(private val context: Context) : + BaseRoomNotifyDialog(context) { + + var list : List?=null + + + var mAdapter = object : BaseAdapter(R.layout.room_boom_reward_item, 1) { + override fun convert(helper: BindingViewHolder, item: BoomMsgAwardBean?) { + val binding = RoomBoomRewardItemBinding.bind(helper.itemView) + binding.boomItem.loadImage(item?.awardPic) + } + } + + + override fun createBinding(inflater: LayoutInflater): RoomBoomRewardBinding { + return RoomBoomRewardBinding.inflate(inflater) + } + + + override fun init() { + + mBinding.confirm.setOnClickListener { + dismiss() + } + + if (list.isVerify()) { + val filterList = list!!.filter { it.uid == AuthModel.get().currentUid } + if (filterList.isVerify()) { + setOnReceive(filterList) + } else { + setUnReceive() + } + } else { + setUnReceive() + } + } + + override fun useAutoDismiss() = false + override fun useSlipSlip() = false + override fun getGravity(): Int { + return Gravity.CENTER + } + + override fun getAnimations(): Int { + return -1 + } + + // 没有中奖的UI + private fun setUnReceive() { + mBinding.bg.setViewWH(height = 200) + mBinding.title.visibility = View.INVISIBLE +// mBinding.confirm.text = "" + mBinding.hint.text = R.string.roomBoomAwardHintEmpty.getString() + mBinding.rvList.setVis(false) + } + + //中奖UI + private fun setOnReceive(filterList: List) { + mBinding.bg.setViewWH(height = 395) + mBinding.title.setVis(true) +// mBinding.confirm.text = "" + mBinding.hint.text = R.string.roomBoomAwardHint.getString() + mBinding.rvList.setVis(true) + + mBinding.rvList.adapter = mAdapter + mAdapter.setNewData(filterList) + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/RoomGameListDialog.kt b/app/src/main/java/com/chwl/app/avroom/dialog/RoomGameListDialog.kt new file mode 100644 index 0000000..8a62ef7 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/RoomGameListDialog.kt @@ -0,0 +1,419 @@ +package com.chwl.app.avroom.dialog + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.view.isVisible +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleEventObserver +import androidx.lifecycle.LifecycleObserver +import androidx.lifecycle.LifecycleOwner +import androidx.recyclerview.widget.RecyclerView +import com.chwl.app.R +import com.chwl.app.avroom.adapter.RoomGameListAdapter +import com.chwl.app.base.BaseActivity +import com.chwl.app.common.widget.dialog.DialogManager +import com.chwl.app.databinding.RoomGameplayDialogBinding +import com.chwl.app.home.helper.OpenRoomHelper +import com.chwl.app.treasure_box.widget.GoldBoxHelper +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.room.bean.RoomIcon +import com.chwl.core.room.bean.RoomInfo +import com.chwl.core.room.bean.RoomModeType +import com.chwl.core.room.core.RoomDataService +import com.chwl.core.room.game.GameModel.getGameList +import com.chwl.core.room.game.bean.BaiShunGameConfig +import com.chwl.core.room.game.bean.GameInfo +import com.chwl.core.room.model.AvRoomModel +import com.chwl.core.support.room.AudioRoomContext +import com.chwl.core.utils.LogUtils +import com.chwl.library.utils.JavaUtil +import com.chwl.library.utils.ResUtil +import com.chwl.library.utils.SingleToastUtil +import com.example.lib_utils.ktx.asLifecycle +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import com.google.gson.Gson +import io.reactivex.disposables.CompositeDisposable + +class RoomGameListDialog : + BottomSheetDialogFragment(), LifecycleObserver { + private var binding: RoomGameplayDialogBinding? = null + private var compositeDisposable: CompositeDisposable? = null + private val adapter = RoomGameListAdapter() + private var dialogManager: DialogManager? = null + private lateinit var recycleView: RecyclerView + + var game_list = "game_list#" + var gameplay_list = "gameplay_list#" + var code = 0 + + private var mStatus = -1 + private var mGameData = arrayListOf() + var listener: GameplayDialogListener? = null + override fun getTheme(): Int { + return R.style.ErbanBottomSheetDialogDimFalse + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = RoomGameplayDialogBinding.inflate(LayoutInflater.from(context)) + return binding?.root + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + return super.onCreateDialog(savedInstanceState).apply { + this.setCanceledOnTouchOutside(true) + } + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + initView() + val recyclerView: RecyclerView = view.findViewById(R.id.recyclerView) + recycleView = recyclerView + switchStatus(0) + requestData() + } + + override fun onAttach(context: Context) { + super.onAttach(context) + val lifecycleObserver = object : LifecycleEventObserver { + override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) { + if (event == Lifecycle.Event.ON_DESTROY) { + context.asLifecycle()?.removeObserver(this) + try { + this@RoomGameListDialog.dismissAllowingStateLoss() + } catch (e: Exception) { + } + } + } + } + context.asLifecycle()?.addObserver(lifecycleObserver) + } + + private fun initView() { + adapter.setOnItemClickListener { _, view, position -> + val item = adapter.data.getOrNull(position) + if (item != null) { + switchGame(item) + } + } + binding?.recyclerView?.adapter = adapter + } + + private fun updateDialogHeight(count: Int) { + if (count > 10) { + val layoutParams = recycleView.layoutParams + layoutParams.height = 600 + recycleView.layoutParams = layoutParams + } + } + + private fun requestData() { + game_list = "game_list#$code" + gameplay_list = "gameplay_list#$code" + val dataService = AudioRoomContext.get()?.findAbility(RoomDataService::class.java.simpleName) + +// val gameList = dataService?.getData(game_list) as? List +// val gameplayList = dataService?.getData(gameplay_list) as? List +// +// LogUtils.d("gameListData-- code1=$game_list size=${gameList?.size} code2=$gameplay_list size=${gameplayList?.size}") +// +// if (gameList.isVerify() || gameplayList.isVerify()){ +// mGameData.clear() +// +// if (gameList.isVerify()) mGameData.addAll(0,gameList!!) +// if (gameplayList.isVerify()) mGameData.addAll(roomIconToGameInfo(gameplayList!!)) +// +// updateDialogHeight(mGameData.size) +// loadData(mGameData) +// return +// } + + val getGameList = getGameList(AvRoomDataManager.get().roomUid) + .doOnError { + SingleToastUtil.showToast(it.message) + if (mStatus != 1)switchStatus(-2) + } + .subscribe { it: List -> + LogUtils.d(" gamegame getGameList GameInfo = $it") + + mGameData.addAll(0,it) + + dataService?.putData(game_list, it) + updateDialogHeight(mGameData.size) + loadData(mGameData) + } + + val roomGamePlayList = AvRoomModel.get().roomGamePlayList + .doOnError { + SingleToastUtil.showToast(it.message) + if (mStatus != 1)switchStatus(-2) + } + .subscribe { it: List -> + LogUtils.d(" gamegame roomGamePlayList RoomIcon = $it") + + val roomIconToGameInfo = roomIconToGameInfo(it) + mGameData.addAll(roomIconToGameInfo) + + dataService?.putData(gameplay_list, it) + updateDialogHeight(mGameData.size) + loadData(mGameData) + } + + getCompositeDisposable().add(getGameList) + getCompositeDisposable().add(roomGamePlayList) + + } + + private fun roomIconToGameInfo(list : List): ArrayList { + val newData = arrayListOf() + list.forEachIndexed { index, roomIcon -> +// if (roomIcon.isBaiShunGame()) { +// newData.add(GameInfo(name = roomIcon.name?:"", pic = roomIcon.icon?:"" , pic2 = roomIcon.icon?:"", skipContent = roomIcon.skipContent?:"", ruleValue = roomIcon.ruleValue?:"",code = roomIcon.code)) +// }else if(roomIcon.isFindLove()){ +// newData.add(GameInfo(name = roomIcon.name?:"", pic = roomIcon.icon?:"" , pic2 = roomIcon.icon?:"", skipContent = roomIcon.skipContent?:"", ruleValue = roomIcon.ruleValue?:"", code = roomIcon.code)) +// }else if(roomIcon.isLeadercc()){ +// newData.add(GameInfo(name = roomIcon.name?:"", pic = roomIcon.icon?:"" , pic2 = roomIcon.icon?:"", skipContent = roomIcon.skipContent?:"", ruleValue = roomIcon.ruleValue?:"", code = roomIcon.code)) +// } + val gameInfo = GameInfo().apply { + name = roomIcon.name ?: "" + pic = roomIcon.icon ?: "" + pic2 = roomIcon.icon ?: "" + skipContent = roomIcon.skipContent ?: "" + ruleValue = roomIcon.ruleValue ?: "" + code = roomIcon.code ?: "" + showType = roomIcon.showType ?: 0 + } + newData.add(gameInfo) + } + return newData + } + + private fun loadData(list: List?) { + if (list.isNullOrEmpty()) { + switchStatus(-1) + } else { + adapter.setNewData(list) + switchStatus(1) + } + } + + private fun switchStatus(status: Int) { + mStatus = status + when (status) { + // loading + 0 -> { + binding?.recyclerView?.isVisible = false + binding?.layoutStatus?.isVisible = true + binding?.groupStatusLoading?.isVisible = true + binding?.groupStatusText?.isVisible = false + } + + // 有数据 + 1 -> { + binding?.recyclerView?.isVisible = true + binding?.layoutStatus?.isVisible = false + } + + // 空数据 + -1 -> { + binding?.recyclerView?.isVisible = false + binding?.layoutStatus?.isVisible = true + binding?.groupStatusLoading?.isVisible = false + binding?.groupStatusText?.isVisible = true + binding?.tvStatus?.setText(R.string.avroom_presenter_roomnewbiehellowwordpresenter_01) + } + + // 失败 + else -> { + binding?.recyclerView?.isVisible = false + binding?.layoutStatus?.isVisible = true + binding?.groupStatusLoading?.isVisible = false + binding?.groupStatusText?.isVisible = true + binding?.tvStatus?.setText(R.string.request_failed_again_later) + } + } + } + + private fun switchGame(gameInfo: GameInfo) { + if (AvRoomDataManager.get().isGamePlaying) { + SingleToastUtil.showToast(ResUtil.getString(R.string.room_switch_game_failed_in_game)) + return + } + //xxx 开启小游戏时的模式限制 +// if (!isShowChangeGame()) { +// SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_fragment_homepartyfragment_04)) +// return +// } + + if (dialogManager == null) { + dialogManager = DialogManager(context) + } + + + if (gameInfo.isLuckyBag()) { + listener?.onShowLuckyBag() + dismissAllowingStateLoss() + } else { + dialogManager?.showOkCancelDialog( + getString(R.string.room_switch_game_tips) + ) { + + //xxx 游戏弹窗列表 点击事件 ,code 优先判断 + if (gameInfo.isFindLove()) { + jumpFindLove() + }else if (gameInfo.isJoyPlay()) { + jumpJoyPlay(gameInfo) + }else if (gameInfo.isLeadercc()) { + jumpLeaderccGame(gameInfo) + } else if (gameInfo.mgId?.isNotEmpty() == true) { + if (gameInfo.isStandardRoom()) { + OpenRoomHelper.updateRoomInfo( + activity as BaseActivity, + AvRoomDataManager.get().mCurrentRoomInfo, + RoomInfo.ROOMTYPE_HOME_PARTY, + 0, + false + ) + } else { + OpenRoomHelper.updateRoomInfo( + activity as BaseActivity, + AvRoomDataManager.get().mCurrentRoomInfo, + RoomInfo.ROOMTYPE_GAME, + JavaUtil.str2long(gameInfo.mgId), + false + ) + } + }else { + jumpBaiShunGame(gameInfo) + } + + dismissAllowingStateLoss() + } + } + + } + + private fun jumpLeaderccGame(data: GameInfo) { + try { + val url = data.skipContent + val ruleValue = Gson().fromJson( + data.ruleValue, + RoomIcon.RuleValueBean::class.java + ) + val config = Gson().fromJson( + ruleValue.RESERVE, + BaiShunGameConfig::class.java + ) + + if (config != null && url != null) { + config.reloadDynamicParams() + config.showType = data.showType + listener?.onShowLeaderccGame(url, config) + } else { + SingleToastUtil.showToast(R.string.manager_trtc_trtcengineadapter_042) + } + + } catch (e: Exception) { + e.printStackTrace() + } + } + private fun jumpJoyPlay(data: GameInfo) { + try { + val url = data.skipContent + val ruleValue = Gson().fromJson( + data.ruleValue, + RoomIcon.RuleValueBean::class.java + ) + val config = Gson().fromJson( + ruleValue.RESERVE, + BaiShunGameConfig::class.java + ) + + if (config != null && url != null) { + config.reloadDynamicParams() + config.showType = data.showType + listener?.onShowJoyPlayGame(url, config) + } else { + SingleToastUtil.showToast(R.string.manager_trtc_trtcengineadapter_042) + } + + } catch (e: Exception) { + e.printStackTrace() + } + } + + private fun jumpBaiShunGame(data: GameInfo) { + try { + val url = data.skipContent + val ruleValue = Gson().fromJson( + data.ruleValue, + RoomIcon.RuleValueBean::class.java + ) + val config = Gson().fromJson( + ruleValue.RESERVE, + BaiShunGameConfig::class.java + ) + + if (config != null && url != null) { + config.reloadDynamicParams() + listener?.onShowBaiShunGame(url, config) + } else { + SingleToastUtil.showToast(R.string.manager_trtc_trtcengineadapter_042) + } + + } catch (e: Exception) { + e.printStackTrace() + } + } + + private fun jumpFindLove() { + context?.let { + GoldBoxHelper.handleBoxClick(it) + } + } + + override fun onDestroy() { + super.onDestroy() + onUnbindContext() + dialogManager?.dismissDialog() + dialogManager = null + } + + private fun getCompositeDisposable(): CompositeDisposable { + var disposable = compositeDisposable + if (disposable == null) { + disposable = CompositeDisposable() + compositeDisposable = disposable + } + return disposable + } + + private fun onUnbindContext() { + compositeDisposable?.dispose() + compositeDisposable = null + } + + //这里的2和4是服务端定义的错误状态 关闭排麦模式和关闭PK模式! + private fun isShowChangeGame(): Boolean { + //xxx 游戏模式限制判断 + val currentRoomInfo = AvRoomDataManager.get().mCurrentRoomInfo + return currentRoomInfo != null + && currentRoomInfo.type != RoomInfo.ROOM_TYPE_SINGLE + && (currentRoomInfo.roomModeType == RoomModeType.NORMAL_MODE || currentRoomInfo.roomModeType == 2 || currentRoomInfo.roomModeType == 4) + } + + interface GameplayDialogListener { + fun onShowBaiShunGame(url: String, config: BaiShunGameConfig) + fun onShowLeaderccGame(url: String, config: BaiShunGameConfig) + fun onShowJoyPlayGame(url: String, config: BaiShunGameConfig) + fun onShowLuckyBag() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/RoomGameplayDialog.kt b/app/src/main/java/com/chwl/app/avroom/dialog/RoomGameplayDialog.kt new file mode 100644 index 0000000..ecdef02 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/RoomGameplayDialog.kt @@ -0,0 +1,420 @@ +package com.chwl.app.avroom.dialog + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.view.isVisible +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleEventObserver +import androidx.lifecycle.LifecycleOwner +import androidx.recyclerview.widget.RecyclerView +import com.chwl.app.R +import com.chwl.app.avroom.activity.CreatePKActivity +import com.chwl.app.avroom.adapter.RoomGameplayAdapter +import com.chwl.app.avroom.anotherroompk.RoomPKCreateActivity +import com.chwl.app.avroom.bean.RoomGameplayItem +import com.chwl.app.avroom.singleroompk.SingleRoomPKCreateActivity +import com.chwl.app.databinding.RoomGameplayDialogBinding +import com.chwl.app.treasure_box.widget.GoldBoxHelper +import com.chwl.app.ui.webview.CommonWebViewActivity +import com.chwl.app.ui.webview.room_banner.RoomWebDialogActivity +import com.chwl.app.utils.CommonJumpHelper +import com.chwl.core.auth.AuthModel +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.room.anotherroompk.SingleRoomPKModel +import com.chwl.core.room.bean.RoomIcon +import com.chwl.core.room.bean.RoomInfo +import com.chwl.core.room.core.RoomDataService +import com.chwl.core.room.game.bean.BaiShunGameConfig +import com.chwl.core.room.model.AvRoomModel +import com.chwl.core.super_admin.util.SuperAdminUtil +import com.chwl.core.support.room.AudioRoomContext +import com.chwl.core.utils.CurrentTimeUtils +import com.chwl.library.utils.ResUtil +import com.chwl.library.utils.SingleToastUtil +import com.example.lib_utils.ktx.asLifecycle +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import com.google.gson.Gson +import io.reactivex.disposables.CompositeDisposable + +class RoomGameplayDialog : BottomSheetDialogFragment() { + + var isOnlyPK = false + private lateinit var recycleView: RecyclerView + + private var binding: RoomGameplayDialogBinding? = null + private var compositeDisposable: CompositeDisposable? = null + private val adapter = RoomGameplayAdapter() + + var listener: RoomGameplayDialog.GameplayDialogListener? = null + + override fun getTheme(): Int { + return R.style.ErbanBottomSheetDialogDimFalse + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = RoomGameplayDialogBinding.inflate(LayoutInflater.from(context)) + return binding?.root + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + return super.onCreateDialog(savedInstanceState).apply { + this.setCanceledOnTouchOutside(true) + } + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + initView() + + val recyclerView: RecyclerView = view.findViewById(R.id.recyclerView) + recycleView = recyclerView + + switchStatus(0) + requestData() + } + + private fun initView() { + adapter.setOnItemClickListener { _, view, position -> + adapter.getItem(position)?.onItemClick(this) + } + binding?.recyclerView?.adapter = adapter + } + + override fun onAttach(context: Context) { + super.onAttach(context) + val lifecycleObserver = object : LifecycleEventObserver { + override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) { + if (event == Lifecycle.Event.ON_DESTROY) { + context.asLifecycle()?.removeObserver(this) + try { + this@RoomGameplayDialog.dismissAllowingStateLoss() + } catch (e: Exception) { + } + } + } + } + context.asLifecycle()?.addObserver(lifecycleObserver) + } + + private fun requestData() { + if (isOnlyPK) { + loadSuccess(arrayListOf()) + } else { + val dataService = + AudioRoomContext.get() + ?.findAbility(RoomDataService::class.java.simpleName) + val cacheKey = "gameplay_list#${parentFragment.hashCode()}" + val list = dataService?.getData(cacheKey) as? List + + if (!list.isNullOrEmpty()) { + updateDialogHeight(list.size) + loadSuccess(list) + return + } + val disposable = AvRoomModel.get().roomGamePlayList + .doOnError { + loadFail(it) + } + .subscribe { it: List -> + dataService?.putData(cacheKey, it) + updateDialogHeight(it.size) + loadSuccess(it) + } + getCompositeDisposable().add(disposable) + } + } + + private fun updateDialogHeight(count: Int) { + if (count > 10) { + val layoutParams = recycleView.layoutParams + layoutParams.height = 600 + recycleView.layoutParams = layoutParams + } + } + + private fun loadSuccess(list: List?) { + var finalList = mutableListOf() + if (isOnlyPK) { + finalList = getLocalList() + } + list?.let { + finalList.addAll(list.map { + RoomGameplayItem.RoomIconItem(it) { dialog, item -> + jump(item) + } + }) + } + if (finalList.isEmpty()) { + switchStatus(-1) + } else { + adapter.setNewData(finalList) + switchStatus(1) + } + } + + private fun loadFail(throwable: Throwable) { + SingleToastUtil.showToast(throwable.message) + val finalList = getLocalList() + if (finalList.isEmpty()) { + switchStatus(-2) + } else { + adapter.setNewData(finalList) + switchStatus(1) + } + } + + private fun switchStatus(status: Int) { + when (status) { + // loading + 0 -> { + binding?.recyclerView?.isVisible = false + binding?.layoutStatus?.isVisible = true + binding?.groupStatusLoading?.isVisible = true + binding?.groupStatusText?.isVisible = false + } + + // 有数据 + 1 -> { + binding?.recyclerView?.isVisible = true + binding?.layoutStatus?.isVisible = false + } + + // 空数据 + -1 -> { + binding?.recyclerView?.isVisible = false + binding?.layoutStatus?.isVisible = true + binding?.groupStatusLoading?.isVisible = false + binding?.groupStatusText?.isVisible = true + binding?.tvStatus?.setText(R.string.avroom_presenter_roomnewbiehellowwordpresenter_01) + } + + // 失败 + else -> { + binding?.recyclerView?.isVisible = false + binding?.layoutStatus?.isVisible = true + binding?.groupStatusLoading?.isVisible = false + binding?.groupStatusText?.isVisible = true + binding?.tvStatus?.setText(R.string.request_failed_again_later) + } + } + } + + private fun jump(data: RoomIcon) { + dismissAllowingStateLoss() + if (data.isFindLove()) { + GoldBoxHelper.handleBoxClick(context) + } else if (data.isBaiShunGame()) { + jumpBaiShunGame(data) + } else { + val url = data.skipContent + if (data.skipType == 3 && !url.isNullOrEmpty()) { + if (data.showType == 2) { + RoomWebDialogActivity.start(context, url, false) + } else { + CommonWebViewActivity.start(context, url) + } + } else { + CommonJumpHelper.bannerJump(context, data) + } + } + } + + override fun onDestroy() { + super.onDestroy() + onUnbindContext() + } + + private fun getCompositeDisposable(): CompositeDisposable { + var disposable = compositeDisposable + if (disposable == null) { + disposable = CompositeDisposable() + compositeDisposable = disposable + } + return disposable + } + + private fun onUnbindContext() { + compositeDisposable?.dispose() + compositeDisposable = null + } + + private fun jumpBaiShunGame(data: RoomIcon) { + try { + val url = data.skipContent + val ruleValue = Gson().fromJson( + data.ruleValue, + RoomIcon.RuleValueBean::class.java + ) + val config = Gson().fromJson( + ruleValue.RESERVE, + BaiShunGameConfig::class.java + ) + if (config != null && url != null) { + config.reloadDynamicParams() + listener?.onShowBaiShunGame(url, config) +// BaiShunGameWebActivity.start(requireContext(), url, config) + } else { + SingleToastUtil.showToast(R.string.manager_trtc_trtcengineadapter_042) + } + } catch (e: Exception) { + e.printStackTrace() + } + } + + private fun getLocalList(): MutableList { + val list = ArrayList() + getPkItem()?.let { + list.add(it) + } + getRoomPkItem()?.let { + list.add(it) + } +// getSingleRoomPkItem()?.let { +// list.add(it) +// } + return list + } + + private fun getPkItem(): RoomGameplayItem? { + val context = context ?: return null + if (SuperAdminUtil.isSuperAdmin()) { + return null + } + if (AvRoomDataManager.get().roomType != RoomInfo.ROOMTYPE_HOME_PARTY && AvRoomDataManager.get().roomType != RoomInfo.ROOMTYPE_PARTY && AvRoomDataManager.get().roomType != RoomInfo.ROOMTYPE_REVELRY) { + return null + } + val roomInfo = AvRoomDataManager.get().mCurrentRoomInfo + if (roomInfo == null) { + return null + } + if (AvRoomDataManager.get().isManager && !AvRoomDataManager.get().isCpRoom) { + val str = + if (AvRoomDataManager.get().isOpenPKMode) context.resources.getString(R.string.room_was_in_PK) else context.resources.getString( + R.string.room_PK_mode + ) + val icon = + if (AvRoomDataManager.get().isOpenPKMode) R.drawable.room_gameplay_ic_team_pk else R.drawable.room_gameplay_ic_team_pk + return RoomGameplayItem.CustomItem(str, icon) { dialog, item -> + if (AvRoomDataManager.get().isDatingMode) { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_01)) + return@CustomItem + } + if (AvRoomDataManager.get().isOpenAnotherPKMode) { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_02)) + return@CustomItem + } + dialog.dismissAllowingStateLoss() + CreatePKActivity.start(context) + } + } + return null + } + + private fun getRoomPkItem(): RoomGameplayItem? { + val context = context ?: return null + if (SuperAdminUtil.isSuperAdmin()) { + return null + } + if (AvRoomDataManager.get().roomType != RoomInfo.ROOMTYPE_HOME_PARTY && AvRoomDataManager.get().roomType != RoomInfo.ROOMTYPE_PARTY && AvRoomDataManager.get().roomType != RoomInfo.ROOMTYPE_REVELRY) { + return null + } + val roomInfo = AvRoomDataManager.get().mCurrentRoomInfo + if (roomInfo == null) { + return null + } + if ((AvRoomDataManager.get().isRoomOwner || AvRoomDataManager.get().isSuperAdmin) && + !AvRoomDataManager.get().isCpRoom + ) { + val str = + if (AvRoomDataManager.get().isOpenAnotherPKMode) ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_03) else ResUtil.getString( + R.string.avroom_dialog_roomoperationdialog_04 + ) + val icon = + if (AvRoomDataManager.get().isOpenAnotherPKMode) R.drawable.room_gameplay_ic_room_pk else R.drawable.room_gameplay_ic_room_pk + return RoomGameplayItem.CustomItem(str, icon) { dialog, item -> + if (AvRoomDataManager.get().isDatingMode) { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_05)) + return@CustomItem + } + if (AvRoomDataManager.get().isOpenPKMode) { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_06)) + return@CustomItem + } + if (AvRoomDataManager.get().isOpenAnotherPKMode) { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_07)) + return@CustomItem + } + dismissAllowingStateLoss() + RoomPKCreateActivity.start(context) + } + } + return null + } + + private fun getSingleRoomPkItem(): RoomGameplayItem? { + val context = context ?: return null + if (SuperAdminUtil.isSuperAdmin()) { + return null + } + if (AvRoomDataManager.get().isOpenGame) { + return null + } + if (!AvRoomDataManager.get().isSingleRoom) { + return null + } + val pkBean = AvRoomDataManager.get().roomPkLiveData.value + if (AvRoomDataManager.get().isRoomOwner && !AvRoomDataManager.get().isCpRoom) { + var str = + if (AvRoomDataManager.get().isOpenAnotherPKMode) ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_08) else ResUtil.getString( + R.string.avroom_dialog_roomoperationdialog_09 + ) + if (pkBean != null) { + if (pkBean.pkState == 2 && + (pkBean.winUid == 0L || pkBean.winUid == AuthModel.get().currentUid || pkBean.penaltyEndTime < CurrentTimeUtils.getCurrentTime()) + ) { + str = ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_010) + } + } + val icon = + if (AvRoomDataManager.get().isOpenAnotherPKMode) R.drawable.ic_room_opt_single_pk_open else R.drawable.ic_room_opt_single_pk_in + val finalStr = str + return RoomGameplayItem.CustomItem(str, icon) { dialog, item -> + if (pkBean != null && ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_011) == finalStr) { + SingleRoomPKModel.endSingleRoomPk(pkBean.roundId) + .doOnSuccess { s: String? -> + SingleToastUtil.showToast( + ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_012) + ) + } + .doOnError { throwable: Throwable -> + SingleToastUtil.showToast( + throwable.message + ) + } + .subscribe() + dismissAllowingStateLoss() + return@CustomItem + } + if (AvRoomDataManager.get().isOpenAnotherPKMode) { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_013)) + return@CustomItem + } + dismissAllowingStateLoss() + SingleRoomPKCreateActivity.start(context) + } + } + return null + } + + interface GameplayDialogListener { + fun onShowBaiShunGame(url: String, config: BaiShunGameConfig) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/RoomLuckyBagBiliDialog.kt b/app/src/main/java/com/chwl/app/avroom/dialog/RoomLuckyBagBiliDialog.kt new file mode 100644 index 0000000..df8af90 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/RoomLuckyBagBiliDialog.kt @@ -0,0 +1,215 @@ +package com.chwl.app.avroom.dialog + +import android.content.DialogInterface +import android.view.Gravity +import android.view.WindowManager +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.chwl.app.R +import com.chwl.app.avroom.bean.LuckyBagDetailEntity +import com.chwl.app.avroom.bean.LuckyBagDetailEntity.BiliType.RECEIVED +import com.chwl.app.avroom.bean.LuckyBagDetailEntity.BiliType.SENT +import com.chwl.app.avroom.bean.LuckyBagEntity +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.bindadapter.BaseBindingAdapter +import com.chwl.app.common.EmptyViewHelper +import com.chwl.app.databinding.DialogRoomLuckyBagBiliBinding +import com.chwl.app.databinding.ItemRoomLuckyBagBiliBinding +import com.chwl.app.ui.utils.loadAvatar +import com.chwl.core.bean.response.ServiceResult +import com.chwl.core.user.UserModel +import com.chwl.core.utils.net.RxHelper +import com.chwl.library.common.util.ClickUtils.click +import com.chwl.library.common.util.doToast +import com.chwl.library.common.util.isVerify +import com.chwl.library.common.util.toColor +import com.chwl.library.common.util.toDP +import com.chwl.library.net.rxnet.RxNet +import com.chwl.library.widget.text.DrawableTextView +import com.example.lib_utils.ktx.getColor +import com.example.lib_utils.ktx.getDrawable +import com.example.lib_utils.ktx.getString +import io.reactivex.Single +import retrofit2.http.GET +import retrofit2.http.Query + +class RoomLuckyBagBiliDialog : BaseDialogFragment() { + + + override var width = WindowManager.LayoutParams.MATCH_PARENT + override var height = 485.toDP() + override var dimAmount = 0f + override var gravity = Gravity.BOTTOM + + private lateinit var mAdapter : RoomLuckyBagBiliAdapter + + private var mSentPageNum = 1 + private var mReceivedPageNum = 1 + private var mType = RECEIVED + + private var mSentData = mutableListOf() + private var mReceivedData = mutableListOf() + + override fun init() { + mAdapter = RoomLuckyBagBiliAdapter() + mAdapter.emptyView = EmptyViewHelper.createEmptyView(context,R.drawable.ic_lucky_bag_empty,"") + binding.srlLayout.setEnableLoadMore(false) + binding.srlLayout.setOnLoadMoreListener { + loadData() + } + binding.rvList.adapter = mAdapter + binding.rvList.layoutManager = LinearLayoutManager(context,RecyclerView.VERTICAL,false) + + UserModel.get().cacheLoginUserInfo?.let { + binding.avatar.loadAvatar(it.avatar) + binding.nick.text = it.nick + } + + + binding.btnBack.click { + dismiss() + } + + binding.btnReceived.click { + changeBtn(binding.btnReceived,true) + changeBtn(binding.btnSent,false) + mType = RECEIVED + mAdapter.isReceived = true + mAdapter.setNewData(mReceivedData) + checkData(mReceivedData) + } + + binding.btnSent.click { + changeBtn(binding.btnSent,true) + changeBtn(binding.btnReceived,false) + mType = SENT + mAdapter.isReceived = false + mAdapter.setNewData(mSentData) + checkData(mSentData) + } + + binding.btnReceived.performClick() + + + } + + private fun checkData(data: MutableList) { + if (!data.isVerify()) { + loadData() + } + } + + private fun loadData() { + val pageNum = if (mType == RECEIVED) mReceivedPageNum else mSentPageNum + getDetails(mType, pageNum, 20) + .compose(bindToLifecycle()) + .doOnSuccess { + if (pageNum == 1) { + if (mType == RECEIVED) { + mReceivedData.clear() + mReceivedData = it.toMutableList() + mAdapter.setNewData(mReceivedData) + } else { + mSentData.clear() + mSentData = it.toMutableList() + mAdapter.setNewData(mSentData) + } + } else { +// if (mType == RECEIVED) { +// mReceivedData.addAll(it) +// } else { +// mSentData.addAll(it) +// } + mAdapter.addData(it) + } + + if (it.size == 20) { + if (mType == RECEIVED) { + mReceivedPageNum++ + } else { + mSentPageNum++ + } + } + binding.srlLayout.setEnableLoadMore(it.size == 20) + binding.srlLayout.finishLoadMore() + } + .doOnError { + it?.message?.doToast() + binding.srlLayout.finishLoadMore() + }.subscribe() + } + + override fun onDismiss(dialog: DialogInterface) { + mActionCallBack?.onAction(0,0) + super.onDismiss(dialog) + } + + + private fun changeBtn(text: DrawableTextView, select: Boolean) { + if (select) { + text.changeGradientColor("#FF9F00".toColor(), -1, "#FFF437".toColor()) + text.setTextColor(R.color.color_292601.getColor()) + } else { + text.changeGradientColor("#00FF9F00".toColor(),-1,"#00FFF437".toColor()) + text.setTextColor(R.color.color_FFEA5C.getColor()) + } + } + + + + class RoomLuckyBagBiliAdapter : BaseBindingAdapter() { + + var isReceived = true + + override fun onBindView( + viewBinding: ItemRoomLuckyBagBiliBinding, + data: LuckyBagDetailEntity, + pos: Int + ) { + if (data.type == LuckyBagEntity.Type.GIFT) { + if (isReceived) { + viewBinding.item.text = "${data.giftName}*${data.num}" + } else { + viewBinding.item.text = "${R.string.gift_action.getString()}*${data.num}" + } + viewBinding.item.setDrawableEmpty(null,null,null,null) + } else { + viewBinding.item.text = data.originalAmount?.toString()?:"" + viewBinding.item.setDrawableEmpty(null,null,R.drawable.ic_coin_84.getDrawable(),null) + } + + viewBinding.time.text = data.createTimeStr?:"" + + if (isReceived) { + viewBinding.nick.text = data.nick?:"" + } else { + viewBinding.nick.text = if (data.type == LuckyBagEntity.Type.GIFT) R.string._ver_24_Gift_Lucky_Bag.getString() else R.string._ver_24_Coin_Lucky_Bag.getString() + } + + } + } + + + private fun getDetails(type: Int, page: Int, pageSize: Int): Single> { + return api.getDetails(type, page, pageSize) + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()) + } + + + private val api: Api = RxNet.create(Api::class.java); + + interface Api { + @GET("/new-red-envelope/detail") + fun getDetails( + @Query("type") type: Int, + @Query("pageNo") page: Int, + @Query("pageSize") pageSize: Int, + ): Single>> + + + } + + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/RoomLuckyBagDialog.kt b/app/src/main/java/com/chwl/app/avroom/dialog/RoomLuckyBagDialog.kt new file mode 100644 index 0000000..532f856 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/RoomLuckyBagDialog.kt @@ -0,0 +1,870 @@ +package com.chwl.app.avroom.dialog + +import android.view.Gravity +import android.view.MotionEvent +import android.view.View +import android.view.WindowManager +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chwl.app.R +import com.chwl.app.avroom.bean.LuckyBagGiftBody +import com.chwl.app.avroom.bean.LuckyBagGiftItemBody +import com.chwl.app.avroom.bean.LuckyBagGoldBody +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.bindadapter.BaseBindingAdapter +import com.chwl.app.bindadapter.BaseBindingViewHolder +import com.chwl.app.databinding.DialogRoomLuckyBagBinding +import com.chwl.app.databinding.ItemRoomLuckyBagGiftBinding +import com.chwl.app.databinding.ItemRoomLuckyBagGoldBinding +import com.chwl.app.databinding.ItemRoomLuckyBagTimeBinding +import com.chwl.app.ui.pay.ChargeActivity +import com.chwl.app.ui.utils.loadAvatar +import com.chwl.app.ui.utils.loadImage +import com.chwl.app.ui.webview.DialogWebViewActivity +import com.chwl.app.utils.KeyBoardUtils +import com.chwl.app.utils.RoomHelperManager +import com.chwl.core.UriProvider +import com.chwl.core.auth.AuthModel +import com.chwl.core.bean.response.ServiceResult +import com.chwl.core.gift.GiftModel +import com.chwl.core.gift.bean.GiftType +import com.chwl.core.gift.bean.LuckyBagGift +import com.chwl.core.gift.bean.LuckyBagGold +import com.chwl.core.gift.bean.LuckyBagNumber +import com.chwl.core.gift.bean.LuckyBagNumber.Type +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.pay.PayModel +import com.chwl.core.user.UserModel +import com.chwl.core.utils.net.RxHelper +import com.chwl.core.widget.layoutmanager.pagergridlayoutmanager.PagerGridLayoutManager +import com.chwl.library.common.util.ClickUtils.click +import com.chwl.library.common.util.doToast +import com.chwl.library.common.util.isVerify +import com.chwl.library.common.util.postSafe +import com.chwl.library.common.util.setAutoSizeModel +import com.chwl.library.common.util.setMargin +import com.chwl.library.common.util.setRL +import com.chwl.library.common.util.setVis +import com.chwl.library.common.util.toColor +import com.chwl.library.common.util.toDP +import com.chwl.library.net.rxnet.RxNet +import com.example.lib_utils.ktx.getColor +import com.example.lib_utils.ktx.getString +import com.example.lib_utils.ktx.setPadding2 +import com.example.lib_utils.spannable.SpannableTextBuilder +import com.google.gson.JsonElement +import com.netease.nim.uikit.common.util.sys.ScreenUtil +import com.youth.banner.config.IndicatorConfig +import io.reactivex.Single +import retrofit2.http.Body +import retrofit2.http.POST + +class RoomLuckyBagDialog : BaseDialogFragment() { + + + override var width = WindowManager.LayoutParams.MATCH_PARENT + override var height = WindowManager.LayoutParams.WRAP_CONTENT + override var dimAmount = 0f + override var gravity = Gravity.BOTTOM + + + private lateinit var mGiftAdapter : GiftAdapter + private lateinit var mGiftTimeAdapter : NumberItemAdapter + private lateinit var mGoldAdapter : GoldAdapter + private lateinit var mGoldNumAdapter : NumberItemAdapter + private lateinit var mGoldTimeAdapter : NumberItemAdapter + + private var mPageManager : PagerGridLayoutManager?=null + + private var mGiftData = mutableListOf() + private var mGiftDataSelect = mutableListOf() + private var mGiftDataSelectPos = HashMap() + + private var mIsGift = true + private var mIsGiftReview = false + + private var mGiftSelect = -1 + private var mGiftTimeSelect = -1 + + private var mGoldSelect = -1 + private var mGoldNumSelect = -1 + private var mGoldTimeSelect = -1 + + + + override fun init() { + + binding.redBagDesc.text = R.string._ver_24_sendHint.getString(0,0) + binding.giftIndicator.setRL() + + mGiftAdapter = GiftAdapter() + mGiftAdapter.onItemChildClickListener = object : BaseQuickAdapter.OnItemChildClickListener { + override fun onItemChildClick( + adapter: BaseQuickAdapter<*, *>?, + view: View?, + position: Int + ) { + view?.let { + when (it.id) { + + R.id.etNum -> { + mGiftSelect = position + showInputLayout() + } + + R.id.up -> { + if (mIsGiftReview) { + if (position.isVerify(mGiftDataSelect)) { + val data = mGiftDataSelect[position] + data.count = data.count.plus(1).coerceAtMost(99) + mGiftAdapter.notifyItemChanged(position,1) + mGiftDataSelectPos.forEach { (t, u) -> + if (u.giftId == data.giftId) { + u.count = data.count + mGiftData.getOrNull(t)?.count = data.count + } + } + } + + }else{ + if (position.isVerify(mGiftData)) { + val data = mGiftData[position] + data.count = data.count.plus(1).coerceAtMost(99) + mGiftAdapter.notifyItemChanged(position,1) + mGiftDataSelectPos[position] = data + } + } + showGiftCoin() + } + + R.id.down -> { + if (mIsGiftReview) { + if (position.isVerify(mGiftDataSelect)) { + val data = mGiftDataSelect[position] + data.count = data.count.minus(1).coerceAtLeast(0) + mGiftAdapter.notifyItemChanged(position,1) + + mGiftDataSelectPos.forEach { (t, u) -> + if (u.giftId == data.giftId) { + u.count = data.count + mGiftData.getOrNull(t)?.count = data.count + } + } + + } + } else { + if (position.isVerify(mGiftData)) { + val data = mGiftData[position] + data.count = data.count.minus(1).coerceAtLeast(0) + mGiftAdapter.notifyItemChanged(position,1) + + if (data.count <= 0) { + mGiftDataSelectPos.remove(position) + } + } + } + showGiftCoin() + } + + else -> {} + } + } + } + } + mPageManager = PagerGridLayoutManager(2,4,PagerGridLayoutManager.HORIZONTAL,false).apply { + setPagerChangedListener(object : PagerGridLayoutManager.PagerChangedListener { + + override fun onPagerCountChanged(pagerCount: Int) { + binding.giftIndicator.initView(IndicatorConfig().apply { + radius = 50.toDP() + selectedColor = R.color.color_FFEA5C.getColor() + normalColor = R.color.black_transparent_30.getColor() + selectedWidth = 5.toDP() + normalWidth = 5.toDP() + indicatorSpace = 3.toDP() + gravity = IndicatorConfig.Direction.CENTER + isAttachToBanner = false + currentPosition = 0 + indicatorSize = pagerCount + }) + } + + override fun onPagerIndexSelected(prePagerIndex: Int, currentPagerIndex: Int) { + binding.giftIndicator.onPageSelected(currentPagerIndex) + } + }) + } + binding.rvListGiftType.layoutManager = mPageManager + binding.rvListGiftType.adapter = mGiftAdapter + + mGiftTimeAdapter = NumberItemAdapter() + mGiftTimeAdapter.onItemClickListener = object : BaseQuickAdapter.OnItemClickListener { + override fun onItemClick(adapter: BaseQuickAdapter<*, *>?, view: View?, position: Int) { + mGiftTimeAdapter.select(position) + mGiftTimeSelect = mGiftTimeAdapter?.data?.getOrNull(position)?.number?:0 + } + } + binding.rvListGiftTime.layoutManager = GridLayoutManager(context,4,RecyclerView.VERTICAL,false) + binding.rvListGiftTime.adapter = mGiftTimeAdapter + + + + + //--金币礼包 + mGoldAdapter = GoldAdapter() + mGoldAdapter.onItemClickListener = object : BaseQuickAdapter.OnItemClickListener { + override fun onItemClick(adapter: BaseQuickAdapter<*, *>?, view: View?, position: Int) { + mGoldAdapter.select(position) + mGoldSelect = mGoldAdapter?.data?.getOrNull(position)?.number?:0 + showGoldCoin() + } + } + binding.rvListGoldType.layoutManager = GridLayoutManager(context,4,RecyclerView.VERTICAL,false) + binding.rvListGoldType.adapter = mGoldAdapter + + + + mGoldNumAdapter = NumberItemAdapter() + mGoldNumAdapter.onItemClickListener = object : BaseQuickAdapter.OnItemClickListener { + override fun onItemClick(adapter: BaseQuickAdapter<*, *>?, view: View?, position: Int) { + mGoldNumAdapter.select(position) + mGoldNumSelect = mGoldNumAdapter?.data?.getOrNull(position)?.number?:0 + showGoldCoin() + } + } + binding.rvListGoldNum.layoutManager = GridLayoutManager(context,4,RecyclerView.VERTICAL,false) + binding.rvListGoldNum.adapter = mGoldNumAdapter + + mGoldTimeAdapter = NumberItemAdapter() + mGoldTimeAdapter.onItemClickListener = object : BaseQuickAdapter.OnItemClickListener { + override fun onItemClick(adapter: BaseQuickAdapter<*, *>?, view: View?, position: Int) { + mGoldTimeAdapter.select(position) + mGoldTimeSelect = mGoldTimeAdapter?.data?.getOrNull(position)?.number?:0 + } + } + binding.rvListGoldTime.layoutManager = GridLayoutManager(context,4,RecyclerView.VERTICAL,false) + binding.rvListGoldTime.adapter = mGoldTimeAdapter + + + + + val giftInfoList = GiftModel.get().getGiftInfoList(GiftType.GIFT_TYPE_NORMAL) + giftInfoList.forEach { + mGiftData.add(LuckyBagGift().apply { + giftId = it.giftId.toLong() + giftName = it.giftName + giftPrice = it.goldPrice + giftPic = it.giftUrl + }) + } + giftInfoList.isVerify(0){ + it.isSelected = true + mGiftSelect = 0 + } + + + RoomHelperManager.mLuckyBagConfig?.let { config -> + val goldData = arrayListOf() + val goldNumData = arrayListOf() + val goldTimeData = arrayListOf() + val giftTimeData = arrayListOf() + + + config.goldItems.forEach { + goldData.add(LuckyBagGold().apply { + number = it + }) + } + + config.numItems.forEach { + goldNumData.add(LuckyBagNumber().apply { + type = Type.num + number = it + }) + } + + config.timeItems.forEach { + goldTimeData.add(LuckyBagNumber().apply { + type = Type.time + number = it + }) + giftTimeData.add(LuckyBagNumber().apply { + type = Type.time + number = it + }) + } + + + mGoldAdapter.setNewData(goldData) + mGoldNumAdapter.setNewData(goldNumData) + mGoldTimeAdapter.setNewData(goldTimeData) + + mGiftTimeAdapter.setNewData(giftTimeData) + + goldData.isVerify(0){ + it.isSelect = true + mGoldSelect = it.number + } + goldNumData.isVerify(0){ + it.isSelect = true + mGoldNumSelect= it.number + } + goldTimeData.isVerify(0){ + it.isSelect = true + mGoldTimeSelect = it.number + } + giftTimeData.isVerify(0){ + it.isSelect = true + mGiftTimeSelect = it.number + } + + + } + + + binding.bgGiftBag.click { + tabChange(true) + } + binding.bgGoldBag.click { + tabChange(false) + } + + binding.notifyView.avatar.loadAvatar(UserModel.get().cacheLoginUserInfo?.avatar) + binding.notifyView.nick.text = UserModel.get().cacheLoginUserInfo?.nick + binding.notifyView.desc.text = if (mIsGift) R.string._ver_24_lucky_bag_room_notify_gift.getString() else R.string._ver_24_lucky_bag_room_notify_coin.getString() + + binding.btnConfirm.click { + if (isSenting) return@click + if (checkSendData()) { + if (mIsGift) { + if (!mIsGiftReview) { + showGiftReview() + } else { + doSendGiftBag() + } + } else { + doSendGoldBag() + } + } else { + R.string._ver_24_sentLuckyBagNoSelect.doToast() + } + } + + binding.btnModify.click { + showGiftSelectView() + } + + binding.btnBill.click { + val root = binding.root + root.setVis(false) + val biliDialog = RoomLuckyBagBiliDialog() + biliDialog.mActionCallBack = object : Action { + override fun onAction(type: Int, data: Any?) { + if (isViewLoaded && isAdded) { + root.setVis(true) + } + } + } + biliDialog.show(context) + } + + binding.btnMore.click { + DialogWebViewActivity.start(binding.btnMore.context,UriProvider.getLuckyBagRule(),false,(ScreenUtil.screenHeight * 0.4).toInt()) + } + + binding.inputLayout.setOnTouchListener { _: View?, _: MotionEvent? -> + binding.inputEdit.clearFocus() + binding.inputLayout.visibility = View.GONE + KeyBoardUtils.hideKeyBoard(activity, binding.inputEdit) + + if (mIsGiftReview) { + if (mGiftSelect.isVerify(mGiftDataSelect)) { + val data = mGiftDataSelect[mGiftSelect] + data.isSelect = false + mGiftAdapter.notifyItemChanged(mGiftSelect,1) + } + }else{ + if (mGiftSelect.isVerify(mGiftData)) { + val data = mGiftData[mGiftSelect] + data.isSelect = false + mGiftAdapter.notifyItemChanged(mGiftSelect,1) + } + } + + mGiftSelect = -1 + false + } + + binding.inputSend.click { + var count = 0 + val text = binding.inputEdit.text.toString() + if (text.isVerify()) { + count = text.toInt() + } + + if (mIsGiftReview) { + + if (mGiftSelect.isVerify(mGiftDataSelect)) { + val data = mGiftDataSelect[mGiftSelect] + data.count = count + data.isSelect = false + mGiftAdapter.notifyItemChanged(mGiftSelect,1) + + mGiftDataSelectPos.forEach { (t, u) -> + if (u.giftId == data.giftId) { + u.count = data.count + mGiftData.getOrNull(t)?.count = data.count + } + } + } + + }else{ + if (mGiftSelect.isVerify(mGiftData)) { + val data = mGiftData[mGiftSelect] + data.count = count + data.isSelect = false + mGiftAdapter.notifyItemChanged(mGiftSelect,1) + + if (count > 0) { + mGiftDataSelectPos[mGiftSelect] = data + } else { + mGiftDataSelectPos.remove(mGiftSelect) + } + } + } + + + + + binding.inputEdit.clearFocus() + binding.inputLayout.visibility = View.GONE + KeyBoardUtils.hideKeyBoard(activity, binding.inputEdit) + mGiftSelect = -1 + + showGiftCoin() + } + + binding.userGold.text = (PayModel.get().currentWalletInfo?.diamondNum ?: 0.0).toInt().toString() + binding.userGold.click { + ChargeActivity.start(context) + } + + binding.btnGoldBag.setAutoSizeModel() + binding.btnGiftBag.setAutoSizeModel() + + + tabChange(true) + } + + private fun tabChange(isGift:Boolean) { + if (isGift) { + binding.bgGiftBag.setBackgroundResource(R.drawable.ic_lucky_bag_tab_bg_left_s) + binding.bgGoldBag.setBackgroundResource(R.drawable.ic_lucky_bag_tab_bg_right_n) + binding.notifyView.rootBg.setBackgroundResource(R.drawable.ic_lucky_bag_room_notify_gift_bg) + binding.giftBagLayout.setVis(true,true) + binding.goldBagLayout.setVis(false, true) + mIsGift = true + changeViewStatus() + showGiftCoin() + } else { + binding.bgGiftBag.setBackgroundResource(R.drawable.ic_lucky_bag_tab_bg_left_n) + binding.bgGoldBag.setBackgroundResource(R.drawable.ic_lucky_bag_tab_bg_right_s) + binding.notifyView.rootBg.setBackgroundResource(R.drawable.ic_lucky_bag_room_notify_gold_bg) + binding.goldBagLayout.setVis(true,true) + binding.giftBagLayout.setVis(false,true) + mIsGift = false + changeViewStatus() + showGoldCoin() + } + + binding.btnConfirm.text = if (mIsGift) R.string._ver_24_Send_Gift_Lucky_Bag.getString() else R.string._ver_24_Send_Coin_Lucky_Bag.getString() + + binding.btnGoldBag.paint.isFakeBoldText = !isGift + binding.btnGiftBag.paint.isFakeBoldText = isGift + + + } + + private fun changeViewStatus() { + if (mIsGift && !mIsGiftReview) { + showGiftSelectView() + }else if (mIsGift && mIsGiftReview) { + showGiftReview() + } else { + showGoldSelectView() + } + } + + private fun showGiftSelectView() { + binding.giftBagLayout.setVis(true) + binding.goldBagLayout.setVis(false) + binding.groupGiftSelect.setVis(true) + binding.groupReViewGift.setVis(false) + + binding.flListGiftTypeLayout.setMargin(top = 37, bottom = 90) +// binding.flListGiftTypeLayout.setViewWH(height = 350) + + binding.bottomSpace.setVis(true) + binding.userGold.setVis(true) + + binding.redBagDesc.setPadding2(bottom = 0.toDP()) + + mGiftAdapter.setNewData(mGiftData) + binding.rvListGiftType.postSafe { + mPageManager?.scrollToPagerIndex(0) + } + + mGiftDataSelect.clear() + val iterator = mGiftDataSelectPos.iterator() + while (iterator.hasNext()) { + val next = iterator.next().value + if (next.count <= 0) { + iterator.remove() + } + } + mIsGiftReview = false + + } + + private fun showGiftReview() { + binding.giftBagLayout.setVis(true) + binding.goldBagLayout.setVis(false) + binding.groupReViewGift.setVis(true) + binding.groupGiftSelect.setVis(false) + + binding.flListGiftTypeLayout.setMargin(top = 37, bottom = 90) +// binding.flListGiftTypeLayout.setViewWH(height = 300) + + binding.bottomSpace.setVis(false) + binding.userGold.setVis(false) + + binding.redBagDesc.setPadding2(bottom = 0.toDP()) + + mGiftDataSelect.clear() + val iterator = mGiftDataSelectPos.iterator() + while (iterator.hasNext()) { + val next = iterator.next().value + if (next.count > 0) { + mGiftDataSelect.add(next) + } else { + iterator.remove() + } + } + + mGiftAdapter.setNewData(mGiftDataSelect) + binding.rvListGiftType.postSafe { + mPageManager?.scrollToPagerIndex(0) + } + mIsGiftReview = true + } + + private fun showGoldSelectView() { + binding.goldBagLayout.setVis(true) + binding.giftBagLayout.setVis(false) + + binding.bottomSpace.setVis(true) + binding.userGold.setVis(true) + + binding.redBagDesc.setPadding2(bottom = 20.toDP()) + } + + private fun showInputLayout() { + binding.inputLayout.postDelayed({ + binding.inputLayout.visibility = View.VISIBLE + binding.inputEdit.isFocusableInTouchMode = true + binding.inputEdit.requestFocus() + + if (mGiftSelect.isVerify(mGiftData)) { + val data = mGiftData[mGiftSelect] + binding.inputEdit.setText(data.count.toString()) + binding.inputEdit.setSelection(binding.inputEdit.text.length) + data.isSelect = true + mGiftAdapter.notifyItemChanged(mGiftSelect,1) + } + + KeyBoardUtils.showKeyBoard(context, binding.inputEdit) + }, 200) + } + + private fun showGiftCoin() { + var giftCount = 0 + var giftCoin = 0 + mGiftDataSelectPos.forEach { (t, u) -> + if (u.count > 0) { + giftCount += u.count + giftCoin += u.count * u.giftPrice + } + } + + val redBagDesc = R.string._ver_24_sendHint.getString(giftCount, giftCoin) + SpannableTextBuilder(binding.redBagDesc).appendText(redBagDesc) + .addTextStyleList(arrayListOf( + SpannableTextBuilder.TextStyleBean().apply { + text = giftCount.toString() + textColor = R.color.white.getColor() + }, + SpannableTextBuilder.TextStyleBean().apply { + text = giftCoin.toString() + textColor = R.color.white.getColor() + } + )) + .apply() + + val time = mGiftTimeSelect / 60 + val reviewTime = R.string._ver_24_reviewTime.getString(time) + SpannableTextBuilder(binding.reviewTime).appendText(reviewTime) + .addTextStyleList(arrayListOf( + SpannableTextBuilder.TextStyleBean().apply { + text = time.toString() + textColor = R.color.white.getColor() + } + )) + .apply() + + } + + private fun showGoldCoin() { + val coin = mGoldSelect + val redBagDesc = R.string._ver_24_Total_spend_s_coins.getString(coin) + SpannableTextBuilder(binding.redBagDesc).appendText(redBagDesc) + .addTextStyleList(arrayListOf( + SpannableTextBuilder.TextStyleBean().apply { + text = coin.toString() + textColor = R.color.white.getColor() + } + )) + .apply() + } + + private fun checkSendData() : Boolean{ + if (mIsGift) { + if (!mGiftDataSelectPos.isVerify()) { + + return false + } + if (mGiftTimeSelect == -1) { + + return false + } + } else { + if (mGoldSelect == -1) { + + return false + } + if (mGoldNumSelect == -1) { + + return false + } + if (mGoldTimeSelect == -1) { + + return false + } + + } + return true + } + + + var isSenting = false + private fun doSendGiftBag() { + isSenting = true + val items = mutableListOf() + mGiftDataSelectPos.keys.forEach{ key-> + if ((mGiftDataSelectPos[key]?.count ?: 0) > 0) { + items.add(LuckyBagGiftItemBody().apply { + giftId = mGiftDataSelectPos[key]?.giftId ?: -1 + giftNum = mGiftDataSelectPos[key]?.count ?: -1 + }) + } + } + + if (!items.isVerify()) { + R.string._ver_24_sentLuckyBagNoSelect.doToast() + isSenting = false + return + } + + sentGiftBag(LuckyBagGiftBody().apply { + roomUid = AvRoomDataManager.get().roomUid + uid = AuthModel.get().currentUid + countDownSecond = mGiftTimeSelect + giftItems = items + }).compose(bindToLifecycle()) + .doOnSuccess { + PayModel.get().refreshWalletInfo(true) + isSenting = false + dismiss() + } + .doOnError { + isSenting = false + it?.message?.doToast() + }.subscribe() + } + + private fun doSendGoldBag() { + isSenting = true + sentGoldBag(LuckyBagGoldBody().apply { + roomUid = AvRoomDataManager.get().roomUid + uid = AuthModel.get().currentUid + goldNum = mGoldSelect + num = mGoldNumSelect + countDownSecond = mGoldTimeSelect + }).compose(bindToLifecycle()) + .doOnSuccess { + PayModel.get().refreshWalletInfo(true) + isSenting = false + dismiss() + } + .doOnError { + isSenting = false + it?.message?.doToast() + }.subscribe() + } + + + private class GiftAdapter : BaseBindingAdapter() { + + + override fun convert( + helper: BaseBindingViewHolder, + item: LuckyBagGift + ) { + helper?.binding?.let { + it.gift.loadImage(item.giftPic) + it.giftName.text = item.giftName + it.gold.text = item.giftPrice.toString() + it.etNum.setText(item.count.toString()) + it.giftCount.text = item.count.toString() + + it.etNum.setTextColor(if (item.isSelect) R.color.color_FFEA5C.getColor() else R.color.white.getColor()) + + helper.addOnClickListener(R.id.up) + helper.addOnClickListener(R.id.down) + helper.addOnClickListener(R.id.etNum) + +// if (item.isReView) { +// it.selectViews.setVis(false) +// it.giftCount.setVis(true) +// } else { +// it.selectViews.setVis(true) +// it.giftCount.setVis(false) +// } + } + } + + override fun onBindViewByPayloads( + viewBinding: ItemRoomLuckyBagGiftBinding, + data: LuckyBagGift, + pos: Int, + payloads: MutableList + ) { + viewBinding.etNum.setText(data.count.toString()) + viewBinding.etNum.setTextColor(if (data.isSelect) R.color.color_FFEA5C.getColor() else R.color.white.getColor()) + } + } + + private class NumberItemAdapter : BaseBindingAdapter() { + + public fun select(pos:Int) { + data?.forEachIndexed { index, luckyBagGold -> + luckyBagGold.isSelect = index == pos + } + notifyDataSetChanged() + } + + override fun convert( + helper: BaseBindingViewHolder, + item: LuckyBagNumber + ) { + helper?.binding?.let { + + if (item.type == LuckyBagNumber.Type.time) { + it.number.text = "${(item.number/60)}${R.string._ver_24_Mins_s.getString()}" + } else { + it.number.text = item.number.toString() + } + + if (item.isSelect()) { + it.number.changeGradientColor("#ff9f00".toColor(),-1,"#fff437".toColor()) + it.number.changeStrikeColor("#00ffd168".toColor()) + it.number.setTextColor(R.color.color_292601.getColor()) + } else { + it.number.changeGradientColor("#610015".toColor(),-1,"#97000c".toColor()) + it.number.changeStrikeColor("#ffd168".toColor()) + it.number.setTextColor(R.color.color_FFEA5C.getColor()) + } + } + } + } + + private class GoldAdapter : BaseBindingAdapter(){ + + public fun select(pos:Int) { + data?.forEachIndexed { index, luckyBagGold -> + luckyBagGold.isSelect = index == pos + } + notifyDataSetChanged() + } + + private var imageRes = arrayOf( + R.drawable.ic_lucky_bag_gold_1, + R.drawable.ic_lucky_bag_gold_2, + R.drawable.ic_lucky_bag_gold_3, + R.drawable.ic_lucky_bag_gold_4, + ) + override fun convert( + helper: BaseBindingViewHolder, + item: LuckyBagGold + ) { + helper?.binding?.let { + + it.gold.text = item.number.toString() + imageRes?.getOrNull(helper.bindingAdapterPosition)?.let { res-> + it.goldPic.setImageResource(res) + } + + if (item.isSelect()) { + it.goldBg.changeGradientColor("#ff9f00".toColor(),-1,"#fff437".toColor()) + it.goldBg.changeStrikeColor("#00ffd168".toColor()) + it.gold.setTextColor(R.color.color_292601.getColor()) + + } else { + it.goldBg.changeGradientColor("#610015".toColor(),-1,"#97000c".toColor()) + it.goldBg.changeStrikeColor("#ffd168".toColor()) + it.gold.setTextColor(R.color.color_FFEA5C.getColor()) + + } + + } + } + + } + + + + private fun sentGiftBag(body: LuckyBagGiftBody?): Single { + return api.sentGiftBag(body) + .compose(RxHelper.handleIgnoreData()) + .compose(RxHelper.handleSchedulers()) + } + + private fun sentGoldBag(body: LuckyBagGoldBody?): Single { + return api.sentGoldBag(body) + .compose(RxHelper.handleIgnoreData()) + .compose(RxHelper.handleSchedulers()) + } + + private val api: Api = RxNet.create(Api::class.java) + private interface Api { + /** + * 发包 + */ + @POST("/new-red-envelope") + fun sentGiftBag(@Body body: LuckyBagGiftBody?): Single?> + @POST("/new-red-envelope") + fun sentGoldBag(@Body body: LuckyBagGoldBody?): Single?> + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/RoomLuckyBagOpenDialog.kt b/app/src/main/java/com/chwl/app/avroom/dialog/RoomLuckyBagOpenDialog.kt new file mode 100644 index 0000000..268d1f0 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/RoomLuckyBagOpenDialog.kt @@ -0,0 +1,379 @@ +package com.chwl.app.avroom.dialog + +import android.content.DialogInterface +import android.view.Gravity +import android.view.View +import android.view.WindowManager +import androidx.lifecycle.lifecycleScope +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.chwl.app.R +import com.chwl.app.avroom.bean.LuckyBagEntity +import com.chwl.app.avroom.bean.LuckyBagOpenBiliEntity +import com.chwl.app.avroom.bean.LuckyBagOpenEntity +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.bindadapter.BaseBindingAdapter +import com.chwl.app.databinding.DialogRoomLuckyBagOpenBinding +import com.chwl.app.databinding.ItemRoomLuckyBagViewOthersBinding +import com.chwl.app.ui.utils.loadAvatar +import com.chwl.app.ui.utils.loadImage +import com.chwl.app.utils.RoomHelperManager +import com.chwl.core.auth.AuthModel +import com.chwl.core.bean.response.ServiceResult +import com.chwl.core.gift.bean.LuckyBagViewOthers +import com.chwl.core.pay.PayModel +import com.chwl.core.utils.net.RxHelper +import com.chwl.library.common.util.ClickUtils.click +import com.chwl.library.common.util.doLog +import com.chwl.library.common.util.doToast +import com.chwl.library.common.util.isVerify +import com.chwl.library.common.util.postSafe +import com.chwl.library.common.util.setMargin +import com.chwl.library.common.util.setViewWH +import com.chwl.library.common.util.setVis +import com.chwl.library.common.util.toDP +import com.chwl.library.net.rxnet.RxNet +import com.example.lib_utils.ktx.getDrawable +import com.example.lib_utils.ktx.getString +import com.tencent.qgame.animplayer.AnimConfig +import com.tencent.qgame.animplayer.inter.IAnimListener +import com.tencent.qgame.animplayer.util.ScaleType +import io.reactivex.Single +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import retrofit2.http.GET +import retrofit2.http.POST +import retrofit2.http.Query + +class RoomLuckyBagOpenDialog : BaseDialogFragment() { + + + override var width = 300.toDP() + override var height = WindowManager.LayoutParams.WRAP_CONTENT + override var dimAmount = 0f + override var gravity = Gravity.CENTER + + private var mAdapter : ViewOtherAdapter ? = null + + var isGift = true + private var isOpen = false + private var mTimeJop : Job?=null + + var mData : LuckyBagEntity? = null + + + override fun init() { + + + mAdapter = ViewOtherAdapter() + binding.rvListViewOthers.adapter = mAdapter + binding.rvListViewOthers.layoutManager = LinearLayoutManager(context,RecyclerView.VERTICAL,false) + + + binding.viewOthers.click { + viewOthers() + } + + binding.confirm.click { + if (isOpen) { + doOpenBag() + } else { + dismiss() + } + } + + binding.bagAnim.setLoop(1) + binding.bagAnim.setScaleType(ScaleType.FIT_XY) + + mData?.let { + isGift = it.isGift + + if (isGift) { + binding.bagImg.setImageResource(R.drawable.ic_lucky_bag_btn_gift_pic_2) + binding.title.text = R.string._ver_24_luckBagOpenGiftTitle.getString(it.nick) + } else { + binding.bagImg.setImageResource(R.drawable.ic_lucky_bag_btn_gold_pic_2) + binding.title.text = R.string._ver_24_luckBagOpenCoinTitle.getString(it.nick) + } + binding.bg.setBackgroundResource(R.drawable.ic_lucky_bag_open_bg) + binding.avatar.loadAvatar(it.avatar) + + val timeDown = RoomHelperManager.getTimeDown(it.countDownTime,it.countDownSecond) + if (timeDown == 0L) { + // 倒计时结束 可开 + ready() + } else { + timeDown(timeDown) + } + } + + + } + + private fun doOpenBag() { + mData?.let { data -> + postLuckyBagOpen(data.id) + .compose(bindToLifecycle()) + .doOnSuccess { + if (this@RoomLuckyBagOpenDialog.isAdded) { + if (it.currentUserGifts.isVerify() || it.currentUserAmount > 0){ + mActionCallBack?.onAction(1,mData) + playAnim(it) + }else { + showEmpty() + } + } + }.doOnError { + it?.message?.doToast() + }.subscribe() + } + } + + + + private fun timeDown(timeDown: Long) { + def() + + binding.bagImg.setVis(true) + binding.comingHint.setVis(true) + + + binding.comingHint.text = R.string._ver_24_luckBagOpenHint.getString() + startTimeDown(timeDown) + } + + + private fun startTimeDown(timeDown:Long) { + mTimeJop?.cancel() + mTimeJop = lifecycleScope.launch { + for (time in timeDown downTo 0) { + delay(1000L) + binding.time.postSafe{ + val timeString = RoomHelperManager.getTimeString(time) + binding.time.text = timeString + binding.time.setVis(time != 0L,true) + "倒计时 i=$time timeString=$timeString".doLog() + } + } + mTimeJop?.cancel() + mTimeJop = null + ready() + } + mTimeJop?.start() + } + + + private fun ready() { + binding.root.postSafe{ + def() + binding.bagImg.setVis(true) + + binding.confirm.text = R.string._ver_24_Click_Open.getString() + + isOpen = true + } + } + + + private fun open(entity: LuckyBagOpenEntity) { + def() + binding.viewOthers.setVis(true) + if (isGift) { + + binding.giftName.setVis(true) + binding.giftNum.setVis(true) + binding.giftImg.setVis(true) + binding.giftCoin.setVis(true) + binding.giftHint.setVis(true) + + entity.currentUserGifts.isVerify(0){ + binding.giftName.text = it?.giftVo?.giftName?:"" + binding.giftCoin.text = ((it?.giftVo?.goldPrice?:0) * (it?.giftNum?:0)).toString() + binding.giftNum.text = "x"+(it?.giftNum?.toString()?:"0") + binding.giftImg.loadImage(it?.giftVo?.giftUrl?:"") + } + + } else { + binding.gold.setVis(true) + binding.goldHint.setVis(true) + binding.gold.text = entity?.currentUserAmount?.toString()?:"0" + PayModel.get().refreshWalletInfo(true) + } + } + + + private fun showEmpty() { + def() + binding.viewOthers.setVis(true) + binding.bagImg.setVis(true) + binding.comingHint.setVis(true) + + binding.comingHint.text = R.string._ver_24_luckBagOpen_Empty.getString() + binding.bagImg.setImageResource(R.drawable.ic_lucky_bag_empty) + mActionCallBack?.onAction(1,mData) + } + + + private fun viewOthers() { + def() + binding.viewOthersHint.setVis(true) + binding.rvListViewOthers.setVis(true) + + binding.bg.setViewWH(height = 414) + binding.confirm.setMargin(bottom = 10) + binding.bg.setBackgroundResource(R.drawable.ic_lucky_bag_open_bili_bg) + + + mData?.let { data-> + getViewOthers(data.id) + .compose(bindToLifecycle()) + .doOnSuccess { + val viewOthers = mutableListOf() + it.forEach { vo-> + viewOthers.add(LuckyBagViewOthers().apply { + uid = vo?.userVO?.uid?:0L + avatar = vo?.userVO?.avatar?:"" + nick = vo?.userVO?.nick?:"" + time = vo?.createTime?:0L + timeStr = vo?.createTimeStr?:"" + giftName = vo?.redEnvelopeGiftItemVOs?.getOrNull(0)?.giftVo?.giftName?:"" + giftNum = vo?.redEnvelopeGiftItemVOs?.getOrNull(0)?.giftNum?:0 + goldNum = vo?.amount?:0 + }) + } + mAdapter?.setNewData(viewOthers) + } + .doOnError { + it?.message?.doToast() + } + .subscribe() + } + + } + + private fun def() { + isOpen = false + binding.viewOthers.visibility = View.INVISIBLE + binding.time.visibility = View.INVISIBLE + + binding.giftName.visibility = View.INVISIBLE + binding.giftNum.visibility = View.INVISIBLE + binding.giftImg.visibility = View.INVISIBLE + binding.giftHint.visibility = View.INVISIBLE + binding.giftCoin.visibility = View.INVISIBLE + + binding.gold.visibility = View.INVISIBLE + binding.goldHint.visibility = View.INVISIBLE + + binding.bagImg.visibility = View.INVISIBLE + binding.comingHint.visibility = View.INVISIBLE + + binding.rvListViewOthers.visibility = View.INVISIBLE + binding.viewOthersHint.visibility = View.INVISIBLE + + binding.bg.setViewWH(height = 326) + binding.confirm.text = R.string.ok.getString() + binding.confirm.setMargin(bottom = 20) + } + + private fun playAnim(luckyBagOpenEntity: LuckyBagOpenEntity) { + context?.let { + binding.bagAnim.setVis(true) + binding.bagAnim.setAnimListener(object : IAnimListener { + override fun onFailed(errorType: Int, errorMsg: String?) { + if (this@RoomLuckyBagOpenDialog.isAdded) { + _binding?.bagAnim.postSafe { + _binding?.bagAnim?.setVis(false) + open(luckyBagOpenEntity) + } + } + + + } + override fun onVideoComplete() { + if (this@RoomLuckyBagOpenDialog.isAdded) { + _binding?.bagAnim.postSafe { + _binding?.bagAnim?.setVis(false) + open(luckyBagOpenEntity) + } + } + + } + override fun onVideoDestroy() {} + override fun onVideoRender(frameIndex: Int, config: AnimConfig?) {} + override fun onVideoStart() { + if (this@RoomLuckyBagOpenDialog.isAdded) { + _binding?.bagImg.postSafe { + _binding?.bagImg?.setVis(isVis = false, isInVis = true) + } + } + + } + }) + val url = if (isGift) "mp4/lucky_bag_gift_open.mp4" else "mp4/lucky_bag_gold_open.mp4" + binding.bagAnim.startPlay(it.assets,url) + } + } + + override fun onDismiss(dialog: DialogInterface) { + super.onDismiss(dialog) + mTimeJop?.cancel() + } + + + private class ViewOtherAdapter : BaseBindingAdapter() { + + override fun onBindView( + viewBinding: ItemRoomLuckyBagViewOthersBinding, + data: LuckyBagViewOthers, + pos: Int + ) { + + viewBinding.time.text = data.timeStr + viewBinding.name.text = data.nick + viewBinding.me.setVis(data.uid == AuthModel.get().currentUid) + viewBinding.avatar.loadAvatar(data?.avatar?:"") + + if (data.giftNum > 0) { + viewBinding.giftInfo.text = "${data.giftName}x${data.giftNum}" + viewBinding.giftInfo.setDrawableEmpty(null,null,null,null) + } else { + viewBinding.giftInfo.text = data.goldNum.toString() + viewBinding.giftInfo.setDrawableEmpty(null,null,R.drawable.ic_coin_84.getDrawable(),null) + } + } + } + + + + private fun getViewOthers(redEnvelopeId: Long): Single> { + return api.getViewOthers(redEnvelopeId) + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()) + } + + + private fun postLuckyBagOpen(redEnvelopeId: Long): Single { + return api.postLuckyBagOpen(redEnvelopeId) + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()) + } + + + private val api: Api = RxNet.create(Api::class.java); + + interface Api { + @GET("/new-red-envelope/get") + fun getViewOthers(@Query("redEnvelopeId") redEnvelopeId: Long): Single>> + + + @POST("/new-red-envelope/open") + fun postLuckyBagOpen( + @Query("redEnvelopeId") redEnvelopeId: Long + ): Single> + + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/RoomMusicDialog.kt b/app/src/main/java/com/chwl/app/avroom/dialog/RoomMusicDialog.kt new file mode 100644 index 0000000..8da8d73 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/RoomMusicDialog.kt @@ -0,0 +1,30 @@ +package com.chwl.app.avroom.dialog + +import android.content.DialogInterface +import android.view.Gravity +import android.view.WindowManager +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.databinding.DialogRoomMusicBinding + +class RoomMusicDialog : BaseDialogFragment() { + + + override var width = WindowManager.LayoutParams.MATCH_PARENT + override var height = WindowManager.LayoutParams.MATCH_PARENT + override var dimAmount = 0f + override var gravity = Gravity.BOTTOM + + + override fun init() { + binding.musicView.setCallBack { + dismiss() + } + binding.musicView.showBoxInAnim(); + } + + override fun onDismiss(dialog: DialogInterface) { + binding.musicView.release() + super.onDismiss(dialog) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/RoomNotifyBoomDialog.kt b/app/src/main/java/com/chwl/app/avroom/dialog/RoomNotifyBoomDialog.kt new file mode 100644 index 0000000..080860e --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/RoomNotifyBoomDialog.kt @@ -0,0 +1,57 @@ +package com.chwl.app.avroom.dialog + +import android.content.Context +import android.view.LayoutInflater +import com.chwl.app.R +import com.chwl.app.application.GlobalHandleManager +import com.chwl.app.avroom.activity.AVRoomActivity +import com.chwl.app.common.widget.dialog.DialogManager +import com.chwl.app.common.widget.dialog.DialogManager.OkCancelDialogListener +import com.chwl.app.databinding.RoomNotifyBoomBinding +import com.chwl.app.ui.utils.loadImage +import com.chwl.core.gift.bean.BoomMsgDialogBean +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.library.utils.ResUtil +import com.example.lib_utils.ktx.getString + +class RoomNotifyBoomDialog(context: Context) : + BaseRoomNotifyDialog(context) { + + var data: BoomMsgDialogBean? = null + + override fun createBinding(inflater: LayoutInflater): RoomNotifyBoomBinding { + return RoomNotifyBoomBinding.inflate(inflater) + } + + override fun init() { + data?.let { data -> + mBinding.boomIcon.loadImage(data.pic) + mBinding.avatar.loadImage(data.avatar) + mBinding.roomName.text = data.roomTitle + mBinding.boomDes.text = R.string.roomBoomNotify.getString() + + mBinding.clickArea.setOnClickListener { + val activity = GlobalHandleManager.get().activity ?: return@setOnClickListener + val mDialogManager = DialogManager(activity) + mDialogManager?.showOkCancelDialog( + ResUtil.getString(R.string.changeRoomTips), + true, + object : + OkCancelDialogListener { + override fun onCancel() { + mDialogManager?.dismissDialog() + } + + override fun onOk() { + mDialogManager?.dismissDialog() + if (AvRoomDataManager.get().roomUid != data.roomUid) { + AVRoomActivity.start(context, data.roomUid) + } + } + }) + } + } + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/RoomNotifyBravoDialog.kt b/app/src/main/java/com/chwl/app/avroom/dialog/RoomNotifyBravoDialog.kt new file mode 100644 index 0000000..ffbc975 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/RoomNotifyBravoDialog.kt @@ -0,0 +1,80 @@ +package com.chwl.app.avroom.dialog + +import android.content.Context +import android.view.LayoutInflater +import com.chwl.app.R +import com.chwl.app.application.GlobalHandleManager +import com.chwl.app.avroom.activity.AVRoomActivity +import com.chwl.app.common.widget.dialog.DialogManager +import com.chwl.app.common.widget.dialog.DialogManager.OkCancelDialogListener +import com.chwl.app.databinding.RoomNotifyBravoGiftBinding +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.core.gift.bean.BravoGiftMsgNotifyBean +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.library.common.util.formatToString +import com.chwl.library.common.util.setVis +import com.chwl.library.utils.ResUtil + +/** + * @Author Vance + * 超级礼物飘屏 + */ +class RoomNotifyBravoDialog(private val context: Context) : BaseRoomNotifyDialog(context) { + + override fun createBinding(inflater: LayoutInflater): RoomNotifyBravoGiftBinding { + return RoomNotifyBravoGiftBinding.inflate(inflater) + } + + private var mDialogManager: DialogManager? = null + var data: BravoGiftMsgNotifyBean? = null + + override fun init() { + + } + + override fun useAutoDismiss(): Boolean { + return false + } + + private fun ready() { + mBinding.root.setVis(true) + + + ImageLoadUtils.loadAvatar(data?.sender?.avatar?:"",mBinding.sendAvatar) + ImageLoadUtils.loadImage(mBinding.giftPic,data?.giftPic?:"") + mBinding.coin.text = data?.coins?.formatToString() + + mBinding.clickArea.setOnClickListener { + data?.roomUid?.let { roomUid -> + if (AvRoomDataManager.get().roomUid == roomUid) return@setOnClickListener + val activity = GlobalHandleManager.get().activity ?: return@setOnClickListener + mDialogManager = DialogManager(activity) + mDialogManager?.showOkCancelDialog(ResUtil.getString(R.string.changeRoomTips), true, object : OkCancelDialogListener { + override fun onCancel() { + mDialogManager?.dismissDialog() + } + + override fun onOk() { + mDialogManager?.dismissDialog() + AVRoomActivity.start(context, roomUid) + } + }) + } + } + + val svga = "svga/bravo_notify_bg.svga" + try { + mBinding.bg.loadFile(svga) + } catch (e: Exception) { + e.printStackTrace() + } + + startAutoDismiss() + } + + override fun showDialog() { + super.showDialog() + ready() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/RoomNotifyCpBindDialog.kt b/app/src/main/java/com/chwl/app/avroom/dialog/RoomNotifyCpBindDialog.kt new file mode 100644 index 0000000..9c09f47 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/RoomNotifyCpBindDialog.kt @@ -0,0 +1,89 @@ +package com.chwl.app.avroom.dialog + +import android.content.Context +import android.graphics.Bitmap +import android.view.LayoutInflater +import com.chwl.app.databinding.RoomNotifyCpBindBinding +import com.chwl.app.ui.utils.CpUtils +import com.chwl.app.ui.utils.isDestroyed +import com.chwl.core.gift.bean.CpMsgBean +import com.tencent.qgame.animplayer.inter.IFetchResource +import com.tencent.qgame.animplayer.mix.Resource +import com.tencent.qgame.animplayer.util.ScaleType + +class RoomNotifyCpBindDialog (private val context: Context) : BaseRoomNotifyDialog(context) { + + override fun createBinding(inflater: LayoutInflater): RoomNotifyCpBindBinding { + return RoomNotifyCpBindBinding.inflate(inflater) + } + + var cpMsgBean : CpMsgBean? = null + var senderAvatar : Bitmap? = null + var receiverAvatar : Bitmap? = null + var index = 0 + + + override fun init() { + cpMsgBean?.let { data-> + mBinding.anim.setScaleType(ScaleType.CENTER_CROP) + + + mBinding.anim.setFetchResource(object : IFetchResource { + + override fun fetchImage(resource: Resource, result: (Bitmap?) -> Unit) { + result(if (resource.tag == "avatar1") senderAvatar else receiverAvatar) + } + + override fun fetchText(resource: Resource, result: (String?) -> Unit) { + var name = "" + try { + name = if (resource.tag == "name1") data.senderNick else data.receiverNick + } catch (e: Exception) { + } + result(name) + } + + override fun releaseResource(resources: List) { + resources?.forEach { + it?.bitmap?.recycle() + } + } + + }) + + mBinding.anim.startPlay(context.assets,"mp4/cp_bind.mp4") + } + + + } + + override fun useSlipSlip() = false + override fun useAutoDismiss() = true + + override fun showDialog() { + index = 0 + cpMsgBean?.let { + CpUtils.downLoadAvatar(it.senderAvatar) { resource -> + index += 1 + senderAvatar = resource + checkImg() + } + CpUtils.downLoadAvatar(it.receiverAvatar) { resource -> + index += 1 + receiverAvatar = resource + checkImg() + } + } + } + + fun checkImg() { + if (index == 2){ + if (!context.isDestroyed()) { + show() + } + } + } + + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/RoomNotifyCpGiftDialog.kt b/app/src/main/java/com/chwl/app/avroom/dialog/RoomNotifyCpGiftDialog.kt new file mode 100644 index 0000000..3af9c97 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/RoomNotifyCpGiftDialog.kt @@ -0,0 +1,31 @@ +package com.chwl.app.avroom.dialog + +import android.content.Context +import android.view.LayoutInflater +import com.chwl.app.databinding.RoomNotifyCpGiftBinding +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.core.gift.bean.CpMsgBean +import kotlin.math.truncate + +/** + * cp 飘屏 + */ +class RoomNotifyCpGiftDialog (private val context: Context) : BaseRoomNotifyDialog(context) { + + override fun createBinding(inflater: LayoutInflater): RoomNotifyCpGiftBinding { + return RoomNotifyCpGiftBinding.inflate(inflater) + } + + var cpMsgBean : CpMsgBean? = null + + override fun init() { + cpMsgBean?.let { + ImageLoadUtils.loadImage(mBinding.sendAvatar,it.senderAvatar) + ImageLoadUtils.loadImage(mBinding.receiverAvatar,it.receiverAvatar) + ImageLoadUtils.loadImage(mBinding.gift,it.giftUrl) + } + } + + override fun useSlipSlip() = true + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/RoomNotifyLevelUpDialog.kt b/app/src/main/java/com/chwl/app/avroom/dialog/RoomNotifyLevelUpDialog.kt new file mode 100644 index 0000000..e26c483 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/RoomNotifyLevelUpDialog.kt @@ -0,0 +1,96 @@ +package com.chwl.app.avroom.dialog + +import android.content.Context +import android.view.LayoutInflater +import com.chwl.app.R +import com.chwl.app.avroom.helper.AnimHelper +import com.chwl.app.databinding.RoomNotifyCpLevelUpBinding +import com.chwl.app.ui.utils.CpUtils +import com.chwl.core.gift.bean.CpMsgBean +import com.chwl.core.utils.myutil.MySpanUtils +import com.example.lib_utils.ktx.getColor +import com.example.lib_utils.ktx.getString +import com.opensource.svgaplayer.SVGADrawable +import com.opensource.svgaplayer.SVGADynamicEntity +import com.opensource.svgaplayer.SVGAParser +import com.opensource.svgaplayer.SVGAParser.Companion.shareParser +import com.opensource.svgaplayer.SVGAVideoEntity + +class RoomNotifyLevelUpDialog (private val context: Context) : BaseRoomNotifyDialog(context) { + + override fun createBinding(inflater: LayoutInflater): RoomNotifyCpLevelUpBinding { + return RoomNotifyCpLevelUpBinding.inflate(inflater) + } + + var cpMsgBean : CpMsgBean ? = null + + override fun init() { + cpMsgBean?.let { + MySpanUtils.with(mBinding.text) + .append(" ${it.senderNick} ").setForegroundColor(R.color.white.getColor()) + .append(" ${R.string.avroom_widget_roomeffectview_02.getString()} ").setForegroundColor(R.color.color_fff664.getColor()) + .append(" ${it.receiverNick} ").setForegroundColor(R.color.white.getColor()) + .append(" ${R.string.Become.getString()} ").setForegroundColor(R.color.color_fff664.getColor()) + .append(" ${CpUtils.getCpLevelUpStr(it.cpLevel)} ").setForegroundColor(R.color.white.getColor()) + .create() + mBinding.text.setBackgroundResource(CpUtils.getCpLevelUpTextBg(it.cpLevel)) + + if (it.cpLevel < 1) return + val svga = "svga/cp_level_up_${it.cpLevel}.svga" + try { + shareParser().decodeFromAssets(svga, object : SVGAParser.ParseCompletion { + override fun onComplete(svgaVideoEntity: SVGAVideoEntity) { + val dynamicEntity = SVGADynamicEntity() + +// val textPaint = TextPaint() +// textPaint.color = Color.WHITE //字体颜色 +// textPaint.textSize = 24f //字体大小 +// dynamicEntity.setDynamicText( +// StaticLayout( +// text.build(), +// 0, +// text.build().length, +// textPaint, +// 0, +// Layout.Alignment.ALIGN_CENTER, +// 1.0f, +// 0.0f, +// false +// ), "bg" +// ) + + AnimHelper.addDynamicImage( + mBinding.svga, + dynamicEntity, + it.senderAvatar, + "user_img1" + ) + AnimHelper.addDynamicImage( + mBinding.svga, + dynamicEntity, + it.receiverAvatar, + "user_img2" + ) + + val drawable = SVGADrawable(svgaVideoEntity, dynamicEntity) + mBinding.svga.setImageDrawable(drawable) + mBinding.svga.stepToFrame(0, true) +// mBinding.svga.startAnimation() + } + + override fun onError() { + } + }, null) + } catch (e: Exception) { + e.printStackTrace() + } + + + + + } + } + + override fun useSlipSlip() = false + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/RoomNotifyLuckBagDialog.kt b/app/src/main/java/com/chwl/app/avroom/dialog/RoomNotifyLuckBagDialog.kt new file mode 100644 index 0000000..327d85a --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/RoomNotifyLuckBagDialog.kt @@ -0,0 +1,82 @@ +package com.chwl.app.avroom.dialog + +import android.content.Context +import android.view.LayoutInflater +import com.chwl.app.R +import com.chwl.app.application.GlobalHandleManager +import com.chwl.app.avroom.activity.AVRoomActivity +import com.chwl.app.avroom.bean.LuckyBagEntity +import com.chwl.app.common.widget.dialog.DialogManager +import com.chwl.app.common.widget.dialog.DialogManager.OkCancelDialogListener +import com.chwl.app.databinding.ViewRoomLuckyBagNotifyBinding +import com.chwl.app.ui.utils.loadAvatar +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.redpackage.bean.RedPackageLuckyBag +import com.chwl.library.common.util.ClickUtils.click +import com.chwl.library.common.util.setVis +import com.chwl.library.utils.ResUtil +import com.example.lib_utils.ktx.getString + +class RoomNotifyLuckBagDialog(private val context: Context) : BaseRoomNotifyDialog(context) { + + + override fun createBinding(inflater: LayoutInflater): ViewRoomLuckyBagNotifyBinding { + return ViewRoomLuckyBagNotifyBinding.inflate(inflater) + } + + + private var mDialogManager: DialogManager? = null + var data: RedPackageLuckyBag? = null + + override fun useAutoDismiss(): Boolean { + return false + } + + override fun init() {} + + + private fun ready() { + mBinding.root.setVis(true) + + data?.let { + mBinding.avatar.loadAvatar(it.getSendUserAvatar()) + mBinding.nick.text = it.getSendUserNick() + + if (it.redEnvelopeType == LuckyBagEntity.Type.GIFT) { + mBinding.desc.text = R.string._ver_24_lucky_bag_room_notify_gift.getString() + mBinding.rootBg.setBackgroundResource(R.drawable.ic_lucky_bag_room_notify_gift_bg) + } else { + mBinding.desc.text = R.string._ver_24_lucky_bag_room_notify_coin.getString() + mBinding.rootBg.setBackgroundResource(R.drawable.ic_lucky_bag_room_notify_gold_bg) + } + } + + mBinding.clickView.click { + data?.roomUid?.let { roomUid -> + if (AvRoomDataManager.get().roomUid == roomUid) return@click + val activity = GlobalHandleManager.get().activity ?: return@click + mDialogManager = DialogManager(activity) + mDialogManager?.showOkCancelDialog(ResUtil.getString(R.string.changeRoomTips), true, object : + OkCancelDialogListener { + override fun onCancel() { + mDialogManager?.dismissDialog() + } + + override fun onOk() { + mDialogManager?.dismissDialog() + AVRoomActivity.start(context, roomUid) + } + }) + } + } + + startAutoDismiss() + } + + + override fun showDialog() { + super.showDialog() + ready() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/RoomNotifyLuckyGiftDialog.kt b/app/src/main/java/com/chwl/app/avroom/dialog/RoomNotifyLuckyGiftDialog.kt new file mode 100644 index 0000000..b419a5c --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/RoomNotifyLuckyGiftDialog.kt @@ -0,0 +1,83 @@ +package com.chwl.app.avroom.dialog + +import android.content.Context +import android.view.LayoutInflater +import com.chwl.app.R +import com.chwl.app.application.GlobalHandleManager +import com.chwl.app.avroom.activity.AVRoomActivity +import com.chwl.app.common.widget.dialog.DialogManager +import com.chwl.app.common.widget.dialog.DialogManager.OkCancelDialogListener +import com.chwl.app.databinding.RoomNotifyLuckGiftDlgBinding +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.core.gift.bean.LuckyGiftMsgAllBean +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.library.common.util.doToast +import com.chwl.library.common.util.setAutoSizeModel +import com.chwl.library.common.util.setRL +import com.chwl.library.common.util.setString +import com.chwl.library.common.util.setVis +import com.chwl.library.utils.ResUtil + +/** + * @Author Vance + * 幸运礼物的飘屏,全服但是展示的时候限制只有房间才展示 + */ +class RoomNotifyLuckyGiftDialog(private val context: Context) : BaseRoomNotifyDialog(context) { + + override fun createBinding(inflater: LayoutInflater): RoomNotifyLuckGiftDlgBinding { + return RoomNotifyLuckGiftDlgBinding.inflate(inflater) + } + + private var mDialogManager: DialogManager? = null + var luckyGiftMsgBean: LuckyGiftMsgAllBean ? = null + + override fun init() { + + } + + override fun useAutoDismiss(): Boolean { + return false + } + + private fun ready() { + mBinding.root.setVis(true) + + mBinding.bg.setRL() + + ImageLoadUtils.loadImage(mBinding.avatar,luckyGiftMsgBean?.sender?.avatar?:"") + mBinding.giftName.text = luckyGiftMsgBean?.giftNameMap?.getFirstText() + mBinding.winNum.text = luckyGiftMsgBean?.times.toString() + + val coinNum = luckyGiftMsgBean?.coins?:0 + mBinding.coinNum.setString(coinNum.toString()) + mBinding.coinNum.setAutoSizeModel() + + mBinding.clickArea.setOnClickListener { + "点击到了 幸运礼物飘屏".doToast() + + luckyGiftMsgBean?.roomUid?.let { roomUid -> + if (AvRoomDataManager.get().roomUid == roomUid) return@setOnClickListener + val activity = GlobalHandleManager.get().activity ?: return@setOnClickListener + mDialogManager = DialogManager(activity) + mDialogManager?.showOkCancelDialog(ResUtil.getString(R.string.changeRoomTips), true, object : OkCancelDialogListener { + override fun onCancel() { + mDialogManager?.dismissDialog() + } + + override fun onOk() { + mDialogManager?.dismissDialog() + AVRoomActivity.start(context, roomUid) + } + }) + } + } + + startAutoDismiss() + } + + override fun showDialog() { + super.showDialog() + ready() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/RoomOperationDialog.java b/app/src/main/java/com/chwl/app/avroom/dialog/RoomOperationDialog.java new file mode 100644 index 0000000..ea4ec25 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/RoomOperationDialog.java @@ -0,0 +1,830 @@ +package com.chwl.app.avroom.dialog; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Context; +import android.graphics.Color; +import android.os.Bundle; +import android.util.DisplayMetrics; +import android.view.Display; +import android.view.WindowManager; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.RecyclerView; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.app.UIHelper; +import com.chwl.app.application.GlobalHandleManager; +import com.chwl.app.avroom.activity.CreatePKActivity; +import com.chwl.app.avroom.activity.RoomSettingActivity; +import com.chwl.app.avroom.activity.RoomTypeSwitchActivity; +import com.chwl.app.avroom.anotherroompk.RoomPKCreateActivity; +import com.chwl.app.avroom.giftvalue.GiftValueDialogUiHelper; +import com.chwl.app.avroom.room_album.RoomAlbumActivity; +import com.chwl.app.avroom.singleroompk.SingleRoomPKCreateActivity; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.app.room_chat.activity.RoomInviteFansActivity; +import com.chwl.app.sadmin.RoomSAdminManagerActivity; +import com.chwl.app.ui.widget.ButtonItem; +import com.chwl.app.ui.widget.recyclerview.decoration.ColorDecoration; +import com.chwl.app.ui.widget.recyclerview.layoutmanager.FullyGridLayoutManager; +import com.chwl.app.vip.dialog.VipBroadcastDialog; +import com.chwl.core.XConstants; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.im.custom.bean.RoomPkBean; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.manager.IMNetEaseManager; +import com.chwl.core.redpackage.RedPackageModel; +import com.chwl.core.room.anotherroompk.SingleRoomPKModel; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.core.room.event.RoomExitEvent; +import com.chwl.core.room.event.RoomShieldEvent; +import com.chwl.core.room.giftvalue.GiftValueModel; +import com.chwl.core.room.model.AvRoomModel; +import com.chwl.core.room.model.HomePartyModel; +import com.chwl.core.room.queuing_mic.event.HasAnimationEffect; +import com.chwl.core.super_admin.model.SuperAdminModel; +import com.chwl.core.super_admin.util.SuperAdminUtil; +import com.chwl.core.user.UserModel; +import com.chwl.core.utils.CurrentTimeUtils; +import com.chwl.core.utils.net.BeanObserver; +import com.chwl.core.utils.net.DontWarnObserver; +import com.chwl.core.utils.net.RxHelper; +import com.chwl.library.common.util.Utils; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; +import com.coorchice.library.utils.LogUtils; +import com.google.android.material.bottomsheet.BottomSheetDialog; +import com.hjq.toast.ToastUtils; + +import org.greenrobot.eventbus.EventBus; + +import java.util.ArrayList; +import java.util.List; + +import io.reactivex.android.schedulers.AndroidSchedulers; + +/** + * 房间操作dialog + * Created by lvzebiao on 2018/11/15. + */ + +public class RoomOperationDialog extends BottomSheetDialog { + + private RecyclerView rvOPtList; + + private Context context; + private OptAdapter optAdapter; + private OnActionListener onActionListener; + private CallBack callBack; + + public void setCallBack(CallBack callBack) { + this.callBack = callBack; + } + + public interface CallBack { + void onCLick(int Type); + } + + public RoomOperationDialog(@NonNull Context context) { + super(context, R.style.ErbanBottomSheetDialogDimFalse); + this.context = context; + } + + @SuppressWarnings("ConstantConditions") + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setCanceledOnTouchOutside(true); + setContentView(R.layout.dialog_room_operation); + findView(); + WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + Display d = windowManager.getDefaultDisplay(); + DisplayMetrics realDisplayMetrics = new DisplayMetrics(); + d.getRealMetrics(realDisplayMetrics); + WindowManager.LayoutParams params = getWindow().getAttributes(); + params.width = WindowManager.LayoutParams.MATCH_PARENT; + params.height = WindowManager.LayoutParams.MATCH_PARENT; + getWindow().setAttributes(params); + + init(); + } + + private void findView() { + rvOPtList = findViewById(R.id.rv_opt_list); + } + + private void init() { + rvOPtList.addItemDecoration(new ColorDecoration( + Color.TRANSPARENT, + Utils.dip2px(getContext(), 10), + Utils.dip2px(getContext(), 20), + true)); + rvOPtList.setLayoutManager(new FullyGridLayoutManager(getContext(), 5)); + optAdapter = new OptAdapter(context, null); + addRoomAlbum(optAdapter); //房间相册 + addDatingAction(optAdapter); // 相亲 模式 + addPKAction(optAdapter); //pk PK 模式-同房间 + addRoomPKAction(optAdapter); //跨房PK + addSingleRoomPKAction(optAdapter); //个播PK +// addSendBroadcastAction(optAdapter); //发布广播 +// addInviteFansOptAdapter(); //邀请粉丝 + addRoomMusicPlay(optAdapter); //音乐设置 + addVipSendBroadcastAction(optAdapter); //小喇叭 +// addRedPacketAction(optAdapter); //红包 + addRoomSettingAction(optAdapter); //房间设置 + addRoomSettingBackPicAction(optAdapter); //房间背景设置 + addGiftEffectAction(optAdapter); //礼物特效 +// addOpenOrClosePublicScreenAction(optAdapter); //公屏开关 +// addRedPackageSwitch(); // 开关红包 + addCleanScreenAction(optAdapter); //清空公屏 +// addRoomLimit(optAdapter); //添加房间限制 +// addGiftValueAction(optAdapter); //礼物值 + addSuperAdminAction(optAdapter); //超管管理 + addShieldReportAction(optAdapter); //举报屏蔽 + addRoomTypeSwitchAction(optAdapter); //房间类型切换 + rvOPtList.setAdapter(optAdapter); + } + + /** + * PK 模式-同房间 + * + * @param optAdapter + */ + private void addPKAction(OptAdapter optAdapter) { + if (SuperAdminUtil.isSuperAdmin()) { + return; + } + if (AvRoomDataManager.get().isOpenGame()) { + return; + } + if (AvRoomDataManager.get().isSingleRoom()) { + return; + } + if (AvRoomDataManager.get().isManager() && !AvRoomDataManager.get().isCpRoom()) { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) { + return; + } + String str = AvRoomDataManager.get().isOpenPKMode() ? + getContext().getResources().getString(R.string.room_was_in_PK) : + getContext().getResources().getString(R.string.room_PK_mode); + int icon = AvRoomDataManager.get().isOpenPKMode() ? + R.drawable.ic_room_opt_op_pk : + R.drawable.ic_room_opt_in_pk; + + + optAdapter.addData(new OptAction(icon, str, () -> { + if (AvRoomDataManager.get().isDatingMode()) { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_01)); + return; + } + if (AvRoomDataManager.get().isOpenAnotherPKMode()) { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_02)); + return; + } + CreatePKActivity.start(getContext()); + })); + } + + } + + /** + * 跨房PK + * + * @param optAdapter + */ + private void addRoomPKAction(OptAdapter optAdapter) { + if (SuperAdminUtil.isSuperAdmin()) { + return; + } + if (AvRoomDataManager.get().isOpenGame()) { + return; + } + if (AvRoomDataManager.get().isSingleRoom()) { + return; + } + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) { + return; + } + if ((AvRoomDataManager.get().isRoomOwner() || AvRoomDataManager.get().isSuperAdmin()) && + !AvRoomDataManager.get().isCpRoom()) { + String str = AvRoomDataManager.get().isOpenAnotherPKMode() ? ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_03) : ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_04); + int icon = AvRoomDataManager.get().isOpenAnotherPKMode() ? + R.drawable.ic_room_opt_another_pk_in : + R.drawable.ic_room_opt_another_pk_open; + + + optAdapter.addData(new OptAction(icon, str, () -> { + if (AvRoomDataManager.get().isDatingMode()) { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_05)); + return; + } + if (AvRoomDataManager.get().isOpenPKMode()) { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_06)); + return; + } + if (AvRoomDataManager.get().isOpenAnotherPKMode()) { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_07)); + return; + } + RoomPKCreateActivity.start(getContext()); + })); + } + + } + + /** + * 个播PK + * + * @param optAdapter + */ + private void addSingleRoomPKAction(OptAdapter optAdapter) { + if (SuperAdminUtil.isSuperAdmin()) { + return; + } + if (AvRoomDataManager.get().isOpenGame()) { + return; + } + if (!AvRoomDataManager.get().isSingleRoom()) { + return; + } + + final RoomPkBean pkBean = AvRoomDataManager.get().roomPkLiveData.getValue(); + if (AvRoomDataManager.get().isRoomOwner() && !AvRoomDataManager.get().isCpRoom()) { + String str = AvRoomDataManager.get().isOpenAnotherPKMode() ? ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_08) : ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_09); + if (pkBean != null) { + if (pkBean.getPkState() == 2 && + (pkBean.getWinUid() == 0 || + pkBean.getWinUid() == AuthModel.get().getCurrentUid() || + pkBean.getPenaltyEndTime() < CurrentTimeUtils.getCurrentTime())) { + str = ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_010); + } + } + int icon = AvRoomDataManager.get().isOpenAnotherPKMode() ? + R.drawable.ic_room_opt_single_pk_open : + R.drawable.ic_room_opt_single_pk_in; + String finalStr = str; + + + optAdapter.addData(new OptAction(icon, str, () -> { + if (pkBean != null && ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_011).equals(finalStr)) { + SingleRoomPKModel.INSTANCE + .endSingleRoomPk(pkBean.getRoundId()) + .doOnSuccess(s -> SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_012))) + .doOnError(throwable -> SingleToastUtil.showToast(throwable.getMessage())) + .subscribe(); + return; + } + + if (AvRoomDataManager.get().isOpenAnotherPKMode()) { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_013)); + return; + } + SingleRoomPKCreateActivity.start(getContext()); + })); + } + } + + + //房间相册 + private void addRoomAlbum(OptAdapter optAdapter) { + if (AvRoomDataManager.get().isHasRoomAlbum()) { + optAdapter.addData(new OptAction(R.drawable.ic_room_operation_album, ResUtil.getString(R.string.room_album), () -> { + RoomAlbumActivity.start(getContext()); + })); + } + } + + /** + * 相亲 模式 + * + * @param optAdapter + */ + private void addDatingAction(OptAdapter optAdapter) { + if (SuperAdminUtil.isSuperAdmin()) { + return; + } + if (AvRoomDataManager.get().getRoomType() != RoomInfo.ROOMTYPE_HOME_PARTY) { + return; + } + if (AvRoomDataManager.get().isManager() && !AvRoomDataManager.get().isCpRoom()) { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) { + return; + } + if (!roomInfo.isCanOpenBlindDate()) { + return; + } + String str = AvRoomDataManager.get().isDatingMode() ? ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_014) : ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_015); + int icon = AvRoomDataManager.get().isDatingMode() ? + R.drawable.ic_room_opt_op_dating : + R.drawable.ic_room_opt_in_dating; + optAdapter.addData(new OptAction(icon, str, () -> { + if (AvRoomDataManager.get().isOpenPKMode()) { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_016)); + return; + } + if (AvRoomDataManager.get().isOpenAnotherPKMode()) { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_017)); + return; + } + new DialogManager(context).showOkCancelWithTitleDialog( + AvRoomDataManager.get().isDatingMode() ? ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_018) : ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_019), + AvRoomDataManager.get().isDatingMode() ? ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_020) : ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_021), + () -> { + HomePartyModel homePartyModel = new HomePartyModel(); + if (!AvRoomDataManager.get().isDatingMode()) { + homePartyModel.datingOpen(roomInfo.getUid()) + .compose(RxHelper.bindContext(context)) + .doOnError(e -> SingleToastUtil.showToast(e.getMessage())) + .subscribe(); + } else { + homePartyModel.datingClose(roomInfo.getUid()) + .compose(RxHelper.bindContext(context)) + .doOnError(e -> SingleToastUtil.showToast(e.getMessage())) + .subscribe(); + } + }); + })); + } + + } + + /** + * 红包 + * + * @param optAdapter + */ + private void addRedPacketAction(OptAdapter optAdapter) { + if (AvRoomDataManager.get().getRedEnvelopeType() > 0) { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) { + return; + } + optAdapter.addData(new OptAction(R.drawable.ic_room_opt_red_package, ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_022), () -> { + if (onActionListener != null) { + onActionListener.onRedPackageAction(); + } + })); + } + } + + /** + * 添加房间限制 + * + * @param optAdapter + */ + private void addRoomLimit(OptAdapter optAdapter) { + //添加 + + } + + /** + * 礼物特效 + * + * @param optAdapter + */ + private void addGiftEffectAction(OptAdapter optAdapter) { + boolean effect = AvRoomDataManager.get().mIsNeedGiftEffect; + String text = effect ? + context.getResources().getString(R.string.close_my_effect) : + context.getResources().getString(R.string.open_my_effect); + + int icon = effect ? + R.drawable.icon_close_my_effect : + R.drawable.icon_open_my_effect; + optAdapter.addData(new OptAction(icon, + text, + () -> { + AvRoomDataManager.get().haveSelfChange = true; + AvRoomDataManager.get().mIsNeedGiftEffect = !AvRoomDataManager.get().mIsNeedGiftEffect; + SingleToastUtil.showToast(AvRoomDataManager.get().mIsNeedGiftEffect ? ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_024) : ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_025)); + EventBus.getDefault().post(new HasAnimationEffect()); + })); + } + + /** + * 公屏开关 + * + * @param optAdapter + */ + private void addOpenOrClosePublicScreenAction(OptAdapter optAdapter) { + if (SuperAdminUtil.isSuperAdmin()) { + //超管能开关公屏 + } else { + if (!AvRoomDataManager.get().isManager()) { + return; + } + } + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) { + return; + } + boolean isCloseScreen = roomInfo.isCloseScreen(); + String text = isCloseScreen ? + context.getResources().getString(R.string.open_public_screen) : + context.getResources().getString(R.string.close_public_screen); + + int icon = isCloseScreen ? + R.drawable.icon_open_public_screen : + R.drawable.icon_close_public_screen; + optAdapter.addData(new OptAction(icon, + text, + () -> { + SuperAdminModel superAdminModel = new SuperAdminModel(); + if (isCloseScreen) { + superAdminModel.roomOperate(SuperAdminModel.OPEN_PUBLIC_SCREEN).subscribe(); + } else { + superAdminModel.roomOperate(SuperAdminModel.CLOSE_PUBLIC_SCREEN).subscribe(); + } + AvRoomModel.get().closeScreen(roomInfo.getRoomId(), + !isCloseScreen) + .compose(RxHelper.bindContext(context)) + .flatMap(data -> IMNetEaseManager.get().closeOpenScreen( + data.getRoomId(), data)) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(); + })); + } + + @SuppressLint("CheckResult") + private void addRedPackageSwitch() { + if (!AvRoomDataManager.get().isManager()) { + return; + } + if (AvRoomDataManager.get().isSingleRoom()) { + return; + } + boolean getIsShowRedPackage = AvRoomDataManager.get().isOpenRedPackage(); + LogUtils.e("getIsShowRedPackage:" + getIsShowRedPackage); + String text = getIsShowRedPackage ? + context.getResources().getString(R.string.close_redpackage_notice) : + context.getResources().getString(R.string.open_redpackage_notice); + + int icon = getIsShowRedPackage ? + R.drawable.ic_room_open_redpackage : + R.drawable.ic_room_close_redpackage; + optAdapter.addData(new OptAction(icon, text, + () -> { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) return; + RedPackageModel.INSTANCE.setRedPackageSwitch(AvRoomDataManager.get().getRoomUid()).subscribe(setIsNeedOpenRedPackage -> { + roomInfo.setServerRedEnvelopeSwitch(setIsNeedOpenRedPackage); + IMNetEaseManager.get().closeOpenRedPackage(roomInfo.getRoomId(), roomInfo); + SingleToastUtil.showToast(setIsNeedOpenRedPackage ? ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_026) : ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_027)); + }); + })); + } + + /** + * 邀请粉丝 + */ + private void addInviteFansOptAdapter() { + if (!AvRoomDataManager.get().isManager()) { + return; + } + optAdapter.addData(new OptAction(R.drawable.ic_room_invite_fans, + ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_028), + () -> { + RoomInviteFansActivity.start(context); + })); + } + + /** + * 礼物值 + */ + private void addGiftValueAction(OptAdapter optAdapter) { + if (SuperAdminUtil.isSuperAdmin()) { + return; + } + if (AvRoomDataManager.get().isCpRoom()) { + return; + } + if (!AvRoomDataManager.get().isManager()) { + return; + } + if (AvRoomDataManager.get().isOpenKTV()) { + return; + } + boolean openGiftValue = AvRoomDataManager.get().isShowGiftValue(); + optAdapter.addData(new OptAction( + openGiftValue ? R.drawable.icon_close_gift_value : R.drawable.icon_open_gift_value, + getContext().getResources().getString( + openGiftValue ? R.string.close_gift_value_text : R.string.open_gift_value_text), + () -> { + if (AvRoomDataManager.get().isCpRoom()) { + return; + } + if (AvRoomDataManager.get().isDatingMode()) { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_029)); + return; + } + if (AvRoomDataManager.get().isOpenKTV()) { + SingleToastUtil.showToast(R.string.before_open_gift_value_should_close_ktv_model); + return; + } + //开启礼物值不需要弹框 + if (!AvRoomDataManager.get().isShowGiftValue()) { + handleOpenGiftValue(); + return; + } + if (!GiftValueDialogUiHelper.get().isNeedConfirmDialog( + GiftValueDialogUiHelper.TYPE_CLOSE_SHOW_GIFT_VALUE)) { + handleOpenGiftValue(); + return; + } + GiftValueDialogUiHelper.get().showGiftValueDialog(context, null, + GiftValueDialogUiHelper.TYPE_CLOSE_SHOW_GIFT_VALUE, + this::handleOpenGiftValue); + })); + } + + private void handleOpenGiftValue() { + boolean isOpen = !AvRoomDataManager.get().isShowGiftValue(); + GiftValueModel.get().openGiftValue(isOpen) + .compose(RxHelper.bindContext(context)) + .subscribe(new DontWarnObserver() { + @Override + public void accept(String s, String error) { + super.accept(s, error); + if (error != null) { + SingleToastUtil.showToast(error); + } else { + + } + } + }); + } + + /** + * 房间设置 + * + * @param optAdapter + */ + private void addRoomSettingAction(OptAdapter optAdapter) { + if (SuperAdminUtil.isSuperAdmin()) { + return; + } + if (AvRoomDataManager.get().isManager()) { + optAdapter.addData(new OptAction(R.drawable.icon_room_setting, + getContext().getResources().getString(R.string.room_setting), () -> RoomSettingActivity.start(getContext()))); + } + } + + /** + * 房间背景设置 + * + * @param optAdapter + */ + private void addRoomSettingBackPicAction(OptAdapter optAdapter) { + if (SuperAdminUtil.isSuperAdmin()) { + return; + } + if (AvRoomDataManager.get().isManager()) { + optAdapter.addData(new OptAction(R.drawable.icon_room_bg, getContext().getResources().getString(R.string.roomBg), () -> { + Activity activity = GlobalHandleManager.get().getActivity(); + if (activity != null) { + RoomBgSetDialog roomBgSetDialog = new RoomBgSetDialog(); + roomBgSetDialog.show(activity); + } + })); + } + } + + + /** + * 房间类型切换 + * + * @param optAdapter + */ + private void addRoomTypeSwitchAction(OptAdapter optAdapter) { + if (RoomTypeSwitchActivity.Companion.isCanSwitch()) { + optAdapter.addData(new OptAction(R.drawable.icon_room_type_switch, + getContext().getResources().getString(R.string.room_type), () -> RoomTypeSwitchActivity.Companion.start(getContext()))); + } + } + + /** + * 超管管理 + */ + private void addSuperAdminAction(OptAdapter optAdapter) { + if (!SuperAdminUtil.isSuperAdmin()) { + return; + } + optAdapter.addData(new OptAction(R.drawable.icon_room_super_admin, + getContext().getResources().getString(R.string.sa_label_room_super_a_manager), + true, + () -> { + RoomSAdminManagerActivity.start(context); + } + )); + } + + /** + * 发布广播 + */ + private void addSendBroadcastAction(OptAdapter optAdapter) { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null || + roomInfo.getIsPermitRoom() == 1 || + !AvRoomDataManager.get().isRoomOwner() || + AvRoomDataManager.get().isSingleRoom()) { + return; + } + + //暂时隐藏 +// optAdapter.addData(new OptAction(R.drawable.icon_room_send_broadcast, +// "发布广播", +// () -> { +// if (AvRoomDataManager.get().getOnMicUserCount() > 0) { +// SendBroadcastDialog.Companion.newInstance().show(context); +// } else { +// SingleToastUtil.showToast("当前房间麦上没有用户,暂不支持发布广播"); +// } +// } +// )); + } + + /** + * 音乐播放设置 + */ + private void addRoomMusicPlay(OptAdapter optAdapter) { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) { + return; + } + boolean isOnMic = AvRoomDataManager.get().isOnMic(AuthModel.get().getCurrentUid()); + if (!isOnMic) return; + + boolean isGameRoom = AvRoomDataManager.get().isOpenGame(); + if (isGameRoom) return; + + optAdapter.addData(new OptAction(R.drawable.icon_room_operation_music, + ResUtil.getString(R.string.layout_dialog_voice_seek_02), + () -> { + if (onActionListener != null) { + onActionListener.onActionClick(R.drawable.icon_room_operation_music,R.drawable.icon_room_operation_music); + } + + } + )); + } + + /** + * 小喇叭 + */ + private void addVipSendBroadcastAction(OptAdapter optAdapter) { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) { + return; + } + if ( UserModel.get().getCacheLoginUserInfo() != null && UserModel.get().getCacheLoginUserInfo().isSuperAdmin()) return; + optAdapter.addData(new OptAction(R.drawable.icon_room_vip_send_broadcast, + ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_033), + () -> VipBroadcastDialog.newInstance().show(context) + )); + } + + /** + * 清空公屏 + */ + private void addCleanScreenAction(OptAdapter optAdapter) { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) { + return; + } + if (!AvRoomDataManager.get().isManager()) { + return; + } + if ( UserModel.get().getCacheLoginUserInfo() != null && UserModel.get().getCacheLoginUserInfo().isSuperAdmin()) return; + optAdapter.addData(new OptAction(R.drawable.icon_room_clean_screen, + ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_034), + () -> new DialogManager(context) + .showOkCancelDialog(ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_035), () -> + AvRoomModel.get().cleanScreen(roomInfo.getUid(), AuthModel.get().getCurrentUid()) + .doOnSuccess(s -> SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_dialog_roomoperationdialog_036))) + .doOnError(throwable -> SingleToastUtil.showToast(throwable.getMessage())) + .subscribe()) + )); + } + + /** + * 举报屏蔽 + */ + private void addShieldReportAction(OptAdapter optAdapter) { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) { + return; + } + optAdapter.addData(new OptAction(R.drawable.icon_room_shield_report, + ResUtil.getString(R.string.me_shield_report), + () -> { + DialogManager dialogManager = new DialogManager(context); + List buttonItems = new ArrayList<>(); + ButtonItem buttonItem1 = new ButtonItem(ResUtil.getString(R.string.me_shield_room), () -> { + UserModel.get().addReport(roomInfo.getUid(), 1) + .subscribe(new BeanObserver() { + @Override + public void onErrorMsg(String error) { + dialogManager.dismissDialog(); + dismiss(); + ToastUtils.show(error); + } + + @Override + public void onSuccess(String s) { + ToastUtils.show(ResUtil.getString(R.string.me_shield_success)); + dialogManager.dismissDialog(); + EventBus.getDefault().post(new RoomShieldEvent()); + EventBus.getDefault().post(new RoomExitEvent()); + dismiss(); + } + }); + }); + buttonItems.add(buttonItem1); + ButtonItem buttonItem2 = new ButtonItem(ResUtil.getString(R.string.layout_dialog_exit_room_01), () -> { + UIHelper.showReportPage( + context, + roomInfo.getUid(), + XConstants.REPORT_TYPE_ROOM + ); + dialogManager.dismissDialog(); + dismiss(); + }); + buttonItems.add(buttonItem2); + dialogManager.showCommonPopupDialog( + buttonItems, + ResUtil.getString(R.string.cancel) + ); + } + )); + } + + @Override + protected void onStop() { + super.onStop(); + this.onActionListener = null; + } + + public void setOnActionListener(OnActionListener onActionListener) { + this.onActionListener = onActionListener; + } + + public interface OnActionListener { + + default void onRedPackageAction(){}; + + default void onActionClick(int type,Object data){}; + + } + + static class OptAction { + private int icon; + private String name; + private OnAction onAction; + private boolean isAppColor; + + public OptAction(int icon, String name, OnAction onAction) { + this(icon, name, false, onAction); + } + + public OptAction(int icon, String name, boolean isAppColor, OnAction onAction) { + this.icon = icon; + this.name = name; + this.isAppColor = isAppColor; + this.onAction = onAction; + } + + interface OnAction { + void onAction(); + } + + } + + private class OptAdapter extends BaseQuickAdapter { + + private final Context context; + + OptAdapter(Context context, @Nullable List data) { + super(R.layout.item_room_opt_dialog, data); + this.context = context; + } + + @Override + protected void convert(BaseViewHolder helper, OptAction item) { + helper.setText(R.id.tv_name, item.name) + .setImageResource(R.id.iv_icon, item.icon) + .setTextColor(R.id.tv_name, context.getResources().getColor( + item.isAppColor ? R.color.appColor : R.color.white_transparent_50)); + helper.itemView.setOnClickListener(v -> { + item.onAction.onAction(); + dismiss(); + }); + } + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/RoomTeamPKResultDialog.java b/app/src/main/java/com/chwl/app/avroom/dialog/RoomTeamPKResultDialog.java new file mode 100644 index 0000000..5930bae --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/RoomTeamPKResultDialog.java @@ -0,0 +1,351 @@ +package com.chwl.app.avroom.dialog; + +import android.content.Context; +import android.os.Bundle; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.app.databinding.RoomTeamPkResultDialogBinding; +import com.chwl.app.ui.widget.dialog.BaseDialog; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.room.pk.bean.PKTeamInfo; +import com.chwl.core.room.pk.bean.PKTeamMember; +import com.chwl.core.room.pk.bean.RoomPkData; +import com.chwl.library.utils.FormatUtils; +import com.chwl.library.utils.ResUtil; +import com.netease.nim.uikit.support.glide.GlideApp; + +import java.util.ArrayList; +import java.util.List; + +import lombok.Data; + +/** + * @author jack + * @Description + * @Date 2019/1/4 + */ +public class RoomTeamPKResultDialog extends BaseDialog { + private final static int TEAM_RED = PKTeamInfo.TEAM_RED; + private final static int TEAM_BLUE = PKTeamInfo.TEAM_BLUE; + + private final static int PK_RESULT_VICTORY = 1; + private final static int PK_RESULT_FAIL = -1; + private final static int PK_RESULT_TIE = 0; + private RoomTeamPkResultDialogBinding binding; + private ImageView ivResultTop; + private RecyclerView rvList; + private TextView tvScore; + private TextView tvGuardianName; + private TextView tvGuardianValue; + private TextView tvTeamStatus; + private TextView tvSeeOtherTeam; + + private int pkResult = PK_RESULT_TIE; + private boolean isShowOpponent = false;//是否在显示对手 + private PkResultMemberAdapter adapter; + private RoomPkData roomPkData; + private PKTeamInfo teamInfo; + + public RoomTeamPKResultDialog(Context context, RoomPkData roomPkData) { + super(context, R.style.full_screen_dialog); + binding = RoomTeamPkResultDialogBinding.inflate(LayoutInflater.from(getContext())); + Window window = getWindow(); + if (window != null) { + WindowManager.LayoutParams lps = window.getAttributes(); + lps.width = WindowManager.LayoutParams.MATCH_PARENT; + lps.height = WindowManager.LayoutParams.WRAP_CONTENT; + lps.gravity = Gravity.CENTER; + window.setAttributes(lps); + } + this.roomPkData = roomPkData; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setCanceledOnTouchOutside(true); + setContentView(binding.getRoot()); + + ivResultTop = (ImageView) findViewById(R.id.iv_result_top); + rvList = (RecyclerView) findViewById(R.id.recycler_view); + + tvScore = (TextView) findViewById(R.id.tv_score); + tvGuardianName = (TextView) findViewById(R.id.tv_guardian_name); + tvGuardianValue = (TextView) findViewById(R.id.tv_guardian_value); + tvTeamStatus = (TextView) findViewById(R.id.tv_team_status); + tvSeeOtherTeam = (TextView) findViewById(R.id.tv_see_other_team); + + + adapter = new PkResultMemberAdapter(null); + rvList.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false)); + rvList.setAdapter(adapter); + + tvSeeOtherTeam.setOnClickListener(v -> { + if (!isShowOpponent) { + showOpponentResult(); + } else { + showMyResult(); + } + }); + + init(); + } + + private void init() { + if (roomPkData == null) { + return; + } + if (roomPkData.getVoteMode() == RoomPkData.VOTE_MODE_PERSON) { + binding.groupGuardianName.setVisibility(View.GONE); + binding.groupGuardianValue.setVisibility(View.GONE); + } + int result = roomPkData.getResult(); + int teamId = findTeamIdByAccount(String.valueOf(AuthModel.get().getCurrentUid())); + if (teamId == PKTeamInfo.TEAM_NONE) { + //观众 + if (result == RoomPkData.PK_RESULT_DRAW) { + teamInfo = findTeamByTeamId(PKTeamInfo.TEAM_RED); + pkResult = PK_RESULT_TIE; + tvTeamStatus.setText(ResUtil.getString(R.string.avroom_dialog_pkresultdialog_01)); + if (teamInfo != null) { + tvScore.setText(teamInfo.getScore() + ""); + } else { + tvScore.setText("0"); + } + binding.groupGuardianName.setVisibility(View.GONE); + binding.groupGuardianValue.setVisibility(View.GONE); + refreshView(pkResult, teamInfo); + } else { + pkResult = PK_RESULT_VICTORY; + teamInfo = findTeamByTeamId(result); + refreshView(pkResult, teamInfo); + } + + } else { + //非观众 + teamInfo = findTeamByTeamId(teamId); + + if (result == RoomPkData.PK_RESULT_DRAW) { + pkResult = PK_RESULT_TIE; + tvTeamStatus.setText(ResUtil.getString(R.string.avroom_dialog_pkresultdialog_02)); + if (teamInfo != null) { + tvScore.setText(teamInfo.getScore() + ""); + } else { + tvScore.setText("0"); + } + binding.groupGuardianName.setVisibility(View.GONE); + binding.groupGuardianValue.setVisibility(View.GONE); + refreshView(pkResult, teamInfo); + + } else { + pkResult = teamId == result ? PK_RESULT_VICTORY : PK_RESULT_FAIL; + refreshView(pkResult, teamInfo); + } + } + } + + + private void showTeamMembers(int pkResult, PKTeamInfo teamInfo) { + List pkResultMembers = new ArrayList<>(); + for (PKTeamMember pkTeamMember : teamInfo.getTeamMembers()) { + PkResultMember resultMember = new PkResultMember(); + resultMember.avatar = pkTeamMember.getAvatar(); + resultMember.nick = pkTeamMember.getNick(); + resultMember.isMVP = pkTeamMember.getUid().equals(teamInfo.getMvp()); + pkResultMembers.add(resultMember); + } + if (pkResult == PK_RESULT_VICTORY) { + adapter.setAvatarBg(R.drawable.room_team_pk_result_avatar_bg_win); + } else if (pkResult == PK_RESULT_FAIL) { + adapter.setAvatarBg(R.drawable.room_team_pk_result_avatar_bg_fail); + } else { + adapter.setAvatarBg(R.drawable.room_team_pk_result_avatar_bg_draw); + } + adapter.setNewData(pkResultMembers); + } + + private void showColorByTeam(PKTeamInfo pkTeamInfo) { + if (pkTeamInfo.getTeam() == PKTeamInfo.TEAM_RED) { + tvScore.setTextColor(getContext().getResources().getColor(R.color.color_FF396F)); + tvGuardianName.setTextColor(getContext().getResources().getColor(R.color.color_FF396F)); + tvGuardianValue.setTextColor(getContext().getResources().getColor(R.color.color_FF396F)); + tvTeamStatus.setTextColor(getContext().getResources().getColor(R.color.color_FF4B81)); + tvSeeOtherTeam.setTextColor(getContext().getResources().getColor(R.color.color_73B8FF)); + } else if (pkTeamInfo.getTeam() == PKTeamInfo.TEAM_BLUE) { + tvScore.setTextColor(getContext().getResources().getColor(R.color.color_73B8FF)); + tvGuardianName.setTextColor(getContext().getResources().getColor(R.color.color_73B8FF)); + tvGuardianValue.setTextColor(getContext().getResources().getColor(R.color.color_73B8FF)); + tvTeamStatus.setTextColor(getContext().getResources().getColor(R.color.color_73B8FF)); + tvSeeOtherTeam.setTextColor(getContext().getResources().getColor(R.color.color_FF4B81)); + } else { + //未知 + } + } + + private void refreshBgByStatus() { + if (pkResult == PK_RESULT_VICTORY) { + ivResultTop.setImageResource(R.drawable.room_team_pk_result_top_win); + } else if (pkResult == PK_RESULT_FAIL) { + ivResultTop.setImageResource(R.drawable.room_team_pk_result_top_fail); + } else if (pkResult == PK_RESULT_TIE) { + ivResultTop.setImageResource(R.drawable.room_team_pk_result_top_draw); + } + } + + private int findTeamIdByAccount(String account) { + for (PKTeamInfo pkTeamInfo : roomPkData.getTeams()) { + for (PKTeamMember pkTeamMember : pkTeamInfo.getTeamMembers()) { + if (pkTeamMember.getUid().equals(account)) { + return pkTeamInfo.getTeam(); + } + } + } + return 0; + } + + /** + * 反转队伍,状态 + */ + private void reverseTeamAndStatus() { + if (teamInfo.getTeam() == TEAM_RED) { + teamInfo = findTeamByTeamId(TEAM_BLUE); + } else if (teamInfo.getTeam() == TEAM_BLUE) { + teamInfo = findTeamByTeamId(TEAM_RED); + } + + if (pkResult == PK_RESULT_VICTORY) { + pkResult = PK_RESULT_FAIL; + } else if (pkResult == PK_RESULT_FAIL) { + pkResult = PK_RESULT_VICTORY; + } + } + + /** + * 显示本队的结果 + */ + private void showMyResult() { + if (isShowOpponent) { + isShowOpponent = false; + reverseTeamAndStatus(); + } + refreshView(pkResult, teamInfo); + } + + /** + * 显示对手队结果 + */ + private void showOpponentResult() { + isShowOpponent = true; + reverseTeamAndStatus(); + refreshView(pkResult, teamInfo); + } + + private void refreshView(int pkResult, PKTeamInfo teamInfo) { + refreshBgByStatus(); + showTeamMembers(pkResult, teamInfo); + showColorByTeam(teamInfo); + + tvScore.setText(FormatUtils.formatPKValue(teamInfo.getScore())); + + if (teamInfo.getProtector() != null && teamInfo.getProtector().getUid() != 0) { + tvGuardianName.setText(teamInfo.getProtector().getNick()); + tvGuardianValue.setText(FormatUtils.formatPKValue(teamInfo.getProtecScore())); + } else { + tvGuardianName.setText(ResUtil.getString(R.string.avroom_dialog_pkresultdialog_03)); + tvGuardianValue.setText("0"); + } + + int myTeamId = findTeamIdByAccount(String.valueOf(AuthModel.get().getCurrentUid())); + if (teamInfo.getTeam() == PKTeamInfo.TEAM_RED) { + + tvTeamStatus.setText(ResUtil.getString(R.string.avroom_dialog_pkresultdialog_04)); + if (myTeamId == PKTeamInfo.TEAM_NONE) { + tvSeeOtherTeam.setText(ResUtil.getString(R.string.avroom_dialog_pkresultdialog_05)); + } else if (myTeamId == teamInfo.getTeam()) { + if (pkResult == PK_RESULT_VICTORY) { + tvTeamStatus.setText(ResUtil.getString(R.string.avroom_dialog_pkresultdialog_06)); + } else if (pkResult == PK_RESULT_FAIL) { + } + tvSeeOtherTeam.setText(ResUtil.getString(R.string.avroom_dialog_pkresultdialog_07)); + } else { + tvSeeOtherTeam.setText(ResUtil.getString(R.string.avroom_dialog_pkresultdialog_08)); + } + } else if (teamInfo.getTeam() == PKTeamInfo.TEAM_BLUE) { + tvTeamStatus.setText(ResUtil.getString(R.string.avroom_dialog_pkresultdialog_09)); + if (myTeamId == PKTeamInfo.TEAM_NONE) { + tvSeeOtherTeam.setText(ResUtil.getString(R.string.avroom_dialog_pkresultdialog_010)); + } else if (myTeamId == teamInfo.getTeam()) { + if (pkResult == PK_RESULT_VICTORY) { + tvTeamStatus.setText(ResUtil.getString(R.string.avroom_dialog_pkresultdialog_011)); + } else if (pkResult == PK_RESULT_FAIL) { + } + tvSeeOtherTeam.setText(ResUtil.getString(R.string.avroom_dialog_pkresultdialog_012)); + } else { + tvSeeOtherTeam.setText(ResUtil.getString(R.string.avroom_dialog_pkresultdialog_013)); + } + } else { + tvTeamStatus.setText(ResUtil.getString(R.string.avroom_dialog_pkresultdialog_014)); + tvSeeOtherTeam.setVisibility(View.GONE); + } + + } + + @Data + class PkResultMember { + String avatar; + String nick; + boolean isMVP; + } + + class PkResultMemberAdapter extends BaseQuickAdapter { + + private int avatarBgResId = R.drawable.room_team_pk_result_avatar_bg_win; + + public void setAvatarBg(int redId) { + this.avatarBgResId = redId; + } + + public PkResultMemberAdapter(@Nullable List data) { + super(R.layout.room_team_pk_result_item, data); + } + + @Override + protected void convert(BaseViewHolder helper, PkResultMember item) { + ImageView avatarBg = helper.getView(R.id.iv_avatar_bg); + avatarBg.setImageResource(avatarBgResId); + ImageView avatar = helper.getView(R.id.iv_avatar); + GlideApp.with(avatar) + .load(item.avatar) + .placeholder(R.drawable.default_avatar) + .dontAnimate() + .into(avatar); + } + } + + + private PKTeamInfo findTeamByTeamId(int teamId) { + if (roomPkData == null) { + return null; + } + for (PKTeamInfo pkTeamInfo : roomPkData.getTeams()) { + if (teamId == pkTeamInfo.getTeam()) { + return pkTeamInfo; + } + } + return null; + } + +} diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/RoomTeamPkDialog.kt b/app/src/main/java/com/chwl/app/avroom/dialog/RoomTeamPkDialog.kt new file mode 100644 index 0000000..7df665c --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/RoomTeamPkDialog.kt @@ -0,0 +1,325 @@ +package com.chwl.app.avroom.dialog + +import android.text.TextUtils +import android.view.WindowManager +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.view.isVisible +import com.chwl.app.R +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.databinding.RoomTeamPkDialogBinding +import com.chwl.app.ui.utils.loadAvatar +import com.chwl.app.ui.widget.dialog.CommonTipDialog +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.room.pk.bean.PKTeamInfo +import com.chwl.core.room.pk.bean.RoomPKInvitedUpMicMember +import com.chwl.core.room.pk.bean.RoomPkData +import com.chwl.core.room.pk.event.PKDataUpdateEvent +import com.chwl.core.room.pk.event.PKTimeFinishEvent +import com.chwl.core.room.pk.event.PKTimeTickEvent +import com.chwl.core.room.pk.model.PkModel +import com.chwl.library.utils.FormatUtils +import com.chwl.library.utils.ResUtil +import com.chwl.library.utils.SingleToastUtil +import io.reactivex.SingleObserver +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.disposables.Disposable +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode +import java.util.Locale + +class RoomTeamPkDialog : BaseDialogFragment() { + + private var compositeDisposable: CompositeDisposable? = null + + private var onActionListener: OnActionListener? = null + + override var width = WindowManager.LayoutParams.MATCH_PARENT + + override fun init() { + binding.layoutRoot.setOnClickListener { + dismissAllowingStateLoss() + } + binding.userListBlue.showBlueStyle() + binding.ivClose.setOnClickListener { + dismissAllowingStateLoss() + } + binding.tvNext.setOnClickListener { + if (PkModel.get().isFighting) { + onRestartClick() + } else { + onStartClick() + } + } + binding.ivAvatarRed.setOnClickListener { + if (!PkModel.get().isFighting) { + onSeatClick(PKTeamInfo.TEAM_RED) + } + } + binding.ivAvatarBlue.setOnClickListener { + if (!PkModel.get().isFighting) { + onSeatClick(PKTeamInfo.TEAM_BLUE) + } + } + binding.userListRed.setOnClickListener { + if (!PkModel.get().isFighting) { + onSeatClick(PKTeamInfo.TEAM_RED) + } + } + binding.userListBlue.setOnClickListener { + if (!PkModel.get().isFighting) { + onSeatClick(PKTeamInfo.TEAM_BLUE) + } + } + updateView() + } + + override fun onStart() { + super.onStart() + EventBus.getDefault().register(this) + compositeDisposable = CompositeDisposable() + } + + override fun onStop() { + super.onStop() + EventBus.getDefault().unregister(this) + compositeDisposable?.dispose() + } + + fun setOnActionListener(onActionListener: OnActionListener?) { + this.onActionListener = onActionListener + } + + fun updateView() { + if (_binding == null) { + return + } + updateTeamUserList() + updateTime() + updateProgress() + if (PkModel.get().isFighting) { + binding.tvNext.setText(R.string.pk_restart) + } else { + binding.tvNext.setText(R.string.start_pk) + } + updateManageButtonVisible(AvRoomDataManager.get().isManager) + } + + private fun updateTeamUserList() { + val pkMemberInfoList = PkModel.get().pkMemberInfoList + val redList = + pkMemberInfoList.filter { it.teamId == PKTeamInfo.TEAM_RED }.take(4).mapNotNull { + it.userInfo + } + val blueList = + pkMemberInfoList.filter { it.teamId == PKTeamInfo.TEAM_BLUE }.take(4).mapNotNull { + it.userInfo + } + binding.userListRed.updateData(redList.drop(1).map { + it.avatar + }) + binding.userListBlue.updateData(blueList.drop(1).map { + it.avatar + }) + binding.ivAvatarRed.loadAvatar(redList.firstOrNull()?.avatar) + binding.ivAvatarBlue.loadAvatar(blueList.firstOrNull()?.avatar) + } + + private fun updateManageButtonVisible(isVisible: Boolean) { + val dimensionRatio: String + if (isVisible) { + binding.ivBg.setImageResource(R.drawable.room_team_pk_bg) + binding.tvNext.isVisible = true + dimensionRatio = "309:379" + } else { + binding.ivBg.setImageResource(R.drawable.room_team_pk_bg_no_manage) + binding.tvNext.isVisible = false + dimensionRatio = "309:324" + } + val params = binding.layoutContent.layoutParams as ConstraintLayout.LayoutParams + params.dimensionRatio = dimensionRatio + binding.layoutContent.layoutParams = params + } + + private fun updateTime() { + if (_binding == null) { + return + } + val roomPkData = PkModel.get().curPkInfo + val pkTimeUntilEnd: Long + if (roomPkData?.pkStatus != RoomPkData.PK_STATUS_IN_PK) { + pkTimeUntilEnd = roomPkData?.duration ?: 0 + } else { + pkTimeUntilEnd = roomPkData.curPkTimeUntilEnd + } + binding.tvTime.text = + String.format(Locale.ENGLISH, "%1$02d:%2$02d", pkTimeUntilEnd / 60, pkTimeUntilEnd % 60) + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onPKDataUpdateEvent(event: PKDataUpdateEvent) { + updateProgress() + if (event.type == PKDataUpdateEvent.TYPE_RESULT) { + safeDismiss() + } + } + + private fun updateProgress() { + if (_binding == null) { + return + } + val roomPkData = PkModel.get().curPkInfo + if (roomPkData?.pkStatus != RoomPkData.PK_STATUS_IN_PK) { + updateProgress(0, 0) + return + } + val redTeam = PkModel.get().findTeamByTeamId(PKTeamInfo.TEAM_RED) + val blueTeam = PkModel.get().findTeamByTeamId(PKTeamInfo.TEAM_BLUE) + if (redTeam == null || blueTeam == null) { + updateProgress(0, 0) + return + } + updateProgress(redTeam.score, blueTeam.score) + } + + private fun updateProgress(redScore: Long, blueScore: Long) { + val totalScore = redScore + blueScore + if (totalScore > 0) { + binding.tvScoreRed.text = FormatUtils.formatPKValue(redScore) + binding.tvScoreBlue.text = FormatUtils.formatPKValue(blueScore) + updateProgress(redScore.toFloat() / totalScore.toFloat()) + } else { + updateProgress(0.5f) + } + } + + private fun updateProgress(percent: Float) { + binding.pbScore.post { + binding.pbScore.progress = (percent * 100).toInt() + val progress = binding.pbScore.width * (percent) + var bias = + (progress - binding.svgaHot.width / 2f) / (binding.pbScore.width - binding.svgaHot.width) + val layoutParams = binding.svgaHot.layoutParams as ConstraintLayout.LayoutParams + bias = 1f.coerceAtMost(bias) + bias = 0f.coerceAtLeast(bias) + layoutParams.horizontalBias = bias + binding.svgaHot.layoutParams = layoutParams + } + } + + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onPKTimeTickEvent(event: PKTimeTickEvent?) { + updateTime() + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onPKTimeFinishEvent(event: PKTimeFinishEvent?) { + updateView() + } + + private fun onSeatClick(teamType: Int) { + //不是管理员或者房主弹出排麦dialog + if (!AvRoomDataManager.get().isManager) { + //已经排麦不操作 + if (!PkModel.get().pkMemberInfoList.isNullOrEmpty() && AvRoomDataManager.get().myIsInQueue) { + SingleToastUtil.showToastShort(ResUtil.getString(R.string.avroom_widget_pkboardview_03)) + return + } + onActionListener?.onShowPKMicQueueDialog() + return + } + //添加红队人员 + val selectDialog = + PKSelectPeopleDialog(context, teamType, PkModel.get().pkMemberInfoList) + selectDialog.setOnSelectPeopleListener { micEntityList -> //更新队伍,麦序,显示头像 + val upMicMemberList: MutableList = + ArrayList() + for (micEntity in micEntityList) { + if (TextUtils.isEmpty(micEntity.uid)) { + continue + } + val roomPKInvitedUpMicMember = RoomPKInvitedUpMicMember() + if (micEntity.isSelect) { + roomPKInvitedUpMicMember.groupType = teamType + } else { + if (TextUtils.isEmpty(micEntity.uid)) { + roomPKInvitedUpMicMember.groupType = PKTeamInfo.TEAM_NONE + } else { + val teamId = PkModel.get().getTeamIdInPKMemberList(micEntity.uid) + roomPKInvitedUpMicMember.groupType = + if (teamId == teamType) PKTeamInfo.TEAM_NONE else teamId + } + } + roomPKInvitedUpMicMember.uid = micEntity.uid + roomPKInvitedUpMicMember.nick = micEntity.nick + val micQueue = AvRoomDataManager.get().mMicQueueMemberMap + //设置坑位的位置 + for (i in 0 until micQueue.size()) { + val key = micQueue.keyAt(i) + val roomQueueInfo = micQueue[key] + if (roomQueueInfo.mChatRoomMember != null && roomQueueInfo.mChatRoomMember.account == micEntity.uid + ) { + roomPKInvitedUpMicMember.position = key + } + } + upMicMemberList.add(roomPKInvitedUpMicMember) + } + PkModel.get().inviteInTeam(upMicMemberList) + .doOnError { throwable: Throwable -> + SingleToastUtil.showToastShort( + throwable.message + ) + } + .subscribe() + } + selectDialog.show() + } + + private fun onStartClick() { + onActionListener?.onBeginPK() + } + + private fun onRestartClick() { + if (PkModel.get().curPkInfo == null) { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_dialog_pkscoreboarddialog_01)) + dismissAllowingStateLoss() + return + } + if (PkModel.get().curPkInfo?.pkStatus == RoomPkData.PK_STATUS_AFTER_PK) { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_dialog_pkscoreboarddialog_02)) + dismissAllowingStateLoss() + return + } + val tipDialog = CommonTipDialog(context) + tipDialog.setTipMsg( + ResUtil.getString(R.string.avroom_dialog_pkscoreboarddialog_03) + + ResUtil.getString(R.string.avroom_dialog_pkscoreboarddialog_04) + ) + tipDialog.setOnActionListener( + object : CommonTipDialog.OnActionListener { + override fun onOk() { + PkModel.get().toPKAgain().subscribe(object : SingleObserver { + override fun onSubscribe(d: Disposable) { + compositeDisposable?.add(d) + } + + override fun onSuccess(t: String) { + dismissAllowingStateLoss() + } + + override fun onError(e: Throwable) { + SingleToastUtil.showToast(e.message) + } + }) + } + } + ) + tipDialog.show() + } + + interface OnActionListener { + fun onBeginPK() + fun onShowPKMicQueueDialog() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/SelectLabelDialog.kt b/app/src/main/java/com/chwl/app/avroom/dialog/SelectLabelDialog.kt new file mode 100644 index 0000000..45414e5 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/SelectLabelDialog.kt @@ -0,0 +1,41 @@ +package com.chwl.app.avroom.dialog + +import android.content.Context +import android.view.View +import com.donkingliang.labels.LabelsView +import com.chwl.app.R +import com.chwl.app.databinding.DialogSelectLabelBinding +import com.chwl.app.base.BaseBindingDialog +import com.chwl.library.annatation.ActLayoutRes + +@ActLayoutRes(R.layout.dialog_select_label) +class SelectLabelDialog( + context: Context, + private val title: String, + private val labels: List, + private val selectLabel: String?, + private val onLabelClickListener: LabelsView.OnLabelClickListener, + private val onSaveClickListener: View.OnClickListener +) : + BaseBindingDialog(context, R.style.dialog), + View.OnClickListener { + override fun init() { + binding.click = this + binding.tvTitle.text = title + binding.labelsView.setOnLabelClickListener(onLabelClickListener) + binding.labelsView.setLabels(labels) + if (labels.contains(selectLabel)) { + binding.labelsView.setSelects(labels.indexOf(selectLabel)) + } + } + + override fun onClick(v: View) { + when (v.id) { + R.id.tv_confirm -> { + onSaveClickListener.onClick(v) + dismiss() + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/SendBroadcastDialog.kt b/app/src/main/java/com/chwl/app/avroom/dialog/SendBroadcastDialog.kt new file mode 100644 index 0000000..f7dfe43 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/SendBroadcastDialog.kt @@ -0,0 +1,152 @@ +package com.chwl.app.avroom.dialog + +import android.annotation.SuppressLint +import android.graphics.Color +import android.os.Bundle +import android.text.Editable +import android.text.style.ForegroundColorSpan +import android.view.WindowManager +import androidx.recyclerview.widget.LinearLayoutManager +import com.chwl.app.avroom.adapter.SendBroadcastAdapter +import com.chwl.app.base.BaseActivity +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.databinding.DialogSendBroadcastBinding +import com.chwl.app.ui.utils.RVDelegate +import com.chwl.app.utils.SpannableBuilder +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.room.bean.BroadcastInfo +import com.chwl.core.room.model.AvRoomModel +import com.chwl.core.utils.extension.toast +import com.chwl.library.utils.CommonUtils +import com.chwl.library.utils.TextWatcherWrapper +import io.reactivex.Observable +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import java.util.concurrent.TimeUnit + +class SendBroadcastDialog : BaseDialogFragment() { + + private lateinit var rvDelegate: RVDelegate + private lateinit var adapter: SendBroadcastAdapter + override var width = WindowManager.LayoutParams.MATCH_PARENT + private var disposable: Disposable? = null + private var broadcastInfo: BroadcastInfo? = null + + companion object { + fun newInstance(): SendBroadcastDialog { + val args = Bundle() + + val fragment = SendBroadcastDialog() + fragment.arguments = args + return fragment + } + } + + @SuppressLint("CheckResult", "SetTextI18n") + override fun init() { + binding?.ivClose?.setOnClickListener { + dismissAllowingStateLoss() + } + + adapter = SendBroadcastAdapter() + rvDelegate = RVDelegate.Builder() + .setAdapter(adapter) + .setRecyclerView(binding?.rvRecommend) + .setLayoutManager(LinearLayoutManager(context)) + .build() + + adapter.setOnItemClickListener { _, _, position -> + binding?.editContent?.setText(adapter.getItem(position)) + } + + binding?.editContent?.addTextChangedListener(object : TextWatcherWrapper() { + override fun afterTextChanged(editable: Editable?) { + val contentLength = editable?.length ?: 0 + binding?.tvContentNumLimit?.text = + "${contentLength}/${broadcastInfo?.maxWords ?: 20}" + binding?.tvSend?.isEnabled = contentLength != 0 + } + }) + + binding?.tvSend?.setOnClickListener { + if (CommonUtils.isFastDoubleClick(1000)) return@setOnClickListener + sendBroadcast() + } + + AvRoomModel.get() + .getBroadcastConfig(AvRoomDataManager.get().mCurrentRoomInfo?.type ?: 0) + .compose(bindToLifecycle()) + .subscribe( + { + initData(it) + }, { + rvDelegate.loadErr(true) + } + ) + + } + + @SuppressLint("SetTextI18n") + private fun initData(info: BroadcastInfo) { + broadcastInfo = info + rvDelegate.setNewData(info.recommends) + binding?.tvAvailableCountNum?.text = "${info.availableTimes}/${info.total}" + binding?.editContent?.hint = "输入内容不能少于${info.minWords}个字,请文明发言哦~" + binding?.tvContentNumLimit?.text = "0/${info.maxWords}" + if (info.seconds > 0) { + beginIntervalTime(info) + } else { + binding?.tvSendHint?.text = "发布后,${info.minutes}分钟内不可再发布广播" + } + } + + @SuppressLint("SetTextI18n") + private fun beginIntervalTime(info: BroadcastInfo) { + disposable?.dispose() + disposable = Observable.intervalRange(0, info.seconds + 1, 0, 1, TimeUnit.SECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .compose(bindToLifecycle()) + .doOnComplete { + binding?.tvSendHint?.text = "发布后,${info.minutes}分钟内不可再发布广播" + } + .subscribe { + binding?.tvSendHint?.text = SpannableBuilder() + .append( + "${info.seconds - it}", + ForegroundColorSpan(Color.parseColor("#FFFDA615")) + ) + .append("后可以再次发布") + .build() + } + } + + @SuppressLint("CheckResult") + private fun sendBroadcast() { + if (broadcastInfo == null) { + "数据加载中,请稍后...".toast() + return + } + broadcastInfo?.let { + val msg = binding?.editContent?.text + if (msg.isNullOrEmpty() || msg.length < it.minWords) { + "输入内容不能少于${it.minWords}个字!".toast() + return@let + } + val dialogManager = (requireActivity() as BaseActivity).dialogManager + dialogManager.showProgressDialog(context) + AvRoomModel.get().sendRoomBroadcast(msg.toString(), AvRoomDataManager.get().roomId) + .compose(bindToLifecycle()) + .subscribe( + { + "发送成功".toast() + dialogManager.dismissDialog() + dismissAllowingStateLoss() + }, + { t -> + t.message.toast() + dialogManager.dismissDialog() + }) + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/dialog/SingleRoomTipDialog.kt b/app/src/main/java/com/chwl/app/avroom/dialog/SingleRoomTipDialog.kt new file mode 100644 index 0000000..0b3bcad --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/dialog/SingleRoomTipDialog.kt @@ -0,0 +1,18 @@ +package com.chwl.app.avroom.dialog + +import android.annotation.SuppressLint +import android.view.WindowManager +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.databinding.DialogSingleRoomTipBinding + +class SingleRoomTipDialog : + BaseDialogFragment() { + @SuppressLint("ClickableViewAccessibility") + override fun init() { + binding?.root?.setOnClickListener { + dismissAllowingStateLoss() + } + dialog?.window?.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/fragment/BaseRoomFragment.kt b/app/src/main/java/com/chwl/app/avroom/fragment/BaseRoomFragment.kt new file mode 100644 index 0000000..d0bca03 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/fragment/BaseRoomFragment.kt @@ -0,0 +1,2108 @@ +package com.chwl.app.avroom.fragment + +import android.Manifest +import android.annotation.SuppressLint +import android.app.Activity +import android.content.Intent +import android.content.pm.PackageManager +import android.graphics.Color +import android.graphics.drawable.Drawable +import android.graphics.drawable.GradientDrawable +import android.os.Bundle +import android.text.TextUtils +import android.view.KeyEvent +import android.view.MotionEvent +import android.view.View +import android.view.ViewGroup +import android.view.ViewStub +import android.widget.EditText +import android.widget.FrameLayout +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.RelativeLayout +import android.widget.TextView +import androidx.annotation.CallSuper +import androidx.core.content.ContextCompat +import androidx.core.view.isVisible +import androidx.fragment.app.FragmentManager +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.LiveData +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.withResumed +import androidx.recyclerview.widget.RecyclerView +import androidx.viewpager2.widget.ViewPager2 +import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.avroom.BottomViewListenerWrapper +import com.chwl.app.avroom.SoftKeyBoardListener +import com.chwl.app.avroom.SoftKeyBoardListener.OnSoftKeyBoardChangeListener +import com.chwl.app.avroom.activity.AVRoomActivity +import com.chwl.app.avroom.activity.RoomInviteActivity +import com.chwl.app.avroom.activity.RoomTitleEditActivity +import com.chwl.app.avroom.adapter.OnMicroItemClickListener +import com.chwl.app.avroom.adapter.RoomMessageIndicatorAdapter +import com.chwl.app.avroom.dialog.AttentionHintDialog +import com.chwl.app.avroom.dialog.DatingVipRuleDialog +import com.chwl.app.avroom.dialog.RoomBoomInfoDialog +import com.chwl.app.avroom.dialog.RoomGameListDialog +import com.chwl.app.avroom.dialog.RoomGameplayDialog +import com.chwl.app.avroom.dialog.RoomLuckyBagDialog +import com.chwl.app.avroom.dialog.RoomOperationDialog +import com.chwl.app.avroom.presenter.BaseRoomPresenter +import com.chwl.app.avroom.room_album.RoomAlbumModel +import com.chwl.app.avroom.view.IBaseRoomView +import com.chwl.app.avroom.widget.BottomView +import com.chwl.app.avroom.widget.LuckyBagBtn +import com.chwl.app.avroom.widget.MessageView +import com.chwl.app.avroom.widget.MicroView +import com.chwl.app.base.BaseMvpActivity +import com.chwl.app.base.BaseMvpFragment +import com.chwl.app.base.PhotoPickActivity +import com.chwl.app.event.OpenRoomIntroEvent +import com.chwl.app.friend.view.SelectFriendActivity +import com.chwl.app.home.adapter.RoomActAdapter +import com.chwl.app.music.widget.MusicPlayerView +import com.chwl.app.room_chat.activity.RoomMsgActivity +import com.chwl.app.ui.utils.GameUtil +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.app.ui.utils.loadImage +import com.chwl.app.ui.webview.CommonWebViewActivity +import com.chwl.app.ui.webview.DialogWebViewActivity +import com.chwl.app.ui.widget.ButtonItem +import com.chwl.app.ui.widget.GiftDialog +import com.chwl.app.ui.widget.GiftDialog.OnGiftDialogBtnClickListener +import com.chwl.app.ui.widget.GiftDialog.SenGiftCallback +import com.chwl.app.ui.widget.UserInfoDialog +import com.chwl.app.ui.widget.dynamicface.DynamicFaceDialog +import com.chwl.app.ui.widget.magicindicator.MagicIndicator +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.CommonNavigator +import com.chwl.app.ui.widget.rollviewpager.RollPagerView +import com.chwl.app.ui.widget.rollviewpager.Util +import com.chwl.app.ui.widget.rollviewpager.hintview.ColorPointHintView +import com.chwl.app.utils.KeyBoardUtils +import com.chwl.app.utils.RoomBoomManager +import com.chwl.app.utils.RoomHelperManager +import com.chwl.app.vip.util.VipHelper +import com.chwl.core.Constants +import com.chwl.core.UriProvider +import com.chwl.core.auth.AuthModel +import com.chwl.core.bean.RoomMicInfo +import com.chwl.core.contacts.MyConstant +import com.chwl.core.gift.GiftModel +import com.chwl.core.gift.bean.BoomInfo +import com.chwl.core.gift.bean.BoomMsgAnimBean +import com.chwl.core.gift.bean.BoomMsgAwardList +import com.chwl.core.gift.bean.BoomMsgDialogBean +import com.chwl.core.gift.bean.BoomMsgExpPushBean +import com.chwl.core.gift.bean.GiftInfo +import com.chwl.core.gift.event.GiftComboEvent +import com.chwl.core.gift.event.NotifyEvent +import com.chwl.core.gift.event.RoomFreeGiftEvent +import com.chwl.core.helper.AtProxy +import com.chwl.core.home.bean.BannerInfo +import com.chwl.core.home.event.OpenRoomMessageInputEvent +import com.chwl.core.im.custom.bean.CustomAttachment +import com.chwl.core.im.custom.bean.RoomFollowOwnerAttachment +import com.chwl.core.im.custom.bean.RoomFollowOwnerAttachment2 +import com.chwl.core.manager.AudioEngineManager +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.manager.IMNetEaseManager +import com.chwl.core.manager.RoomEvent +import com.chwl.core.mentoring_relationship.event.MentoringStopCountingEvent +import com.chwl.core.room.anotherroompk.ShowGiftDialogEvent +import com.chwl.core.room.anotherroompk.ShowUserInfoDialogEvent +import com.chwl.core.room.bean.RightBottomIconConfig +import com.chwl.core.room.bean.RoomBoomInfo +import com.chwl.core.room.bean.RoomIcon +import com.chwl.core.room.bean.RoomInfo +import com.chwl.core.room.core.RoomDataService +import com.chwl.core.room.event.RoomAtEvent +import com.chwl.core.room.event.RoomClearScreenEvent +import com.chwl.core.room.game.GameModel.getGameList +import com.chwl.core.room.game.GameStatus +import com.chwl.core.room.game.bean.BaiShunGameConfig +import com.chwl.core.room.game.bean.GameInfo +import com.chwl.core.room.giftvalue.helper.GiftValueMrg +import com.chwl.core.room.model.AvRoomModel +import com.chwl.core.room.queue.bean.MicMemberInfo +import com.chwl.core.share.bean.SessionType +import com.chwl.core.super_admin.SaConstant +import com.chwl.core.super_admin.model.SuperAdminModel +import com.chwl.core.super_admin.util.SuperAdminUtil +import com.chwl.core.support.room.AudioRoomContext +import com.chwl.core.support.room.AudioRoomContext.Companion.get +import com.chwl.core.support.room.RoomContext +import com.chwl.core.support.room.RoomView +import com.chwl.core.support.room.RoomWidget +import com.chwl.core.user.UserModel +import com.chwl.core.user.bean.BaseInfo +import com.chwl.core.user.bean.UserInfo +import com.chwl.core.utils.LogUtils +import com.chwl.core.utils.myutil.MyUtil +import com.chwl.core.utils.net.VipLevelNotEnoughException +import com.chwl.library.common.util.ClickUtils.click +import com.chwl.library.common.util.LimitClickUtils +import com.chwl.library.common.util.doLog +import com.chwl.library.common.util.doToast +import com.chwl.library.common.util.isVerify +import com.chwl.library.common.util.postSafe +import com.chwl.library.common.util.setMargin +import com.chwl.library.common.util.setViewWH +import com.chwl.library.common.util.setVis +import com.chwl.library.net.rxnet.utils.RxNetWorkUtils +import com.chwl.library.rxbus.RxBus +import com.chwl.library.utils.JavaUtil +import com.chwl.library.utils.ListUtils +import com.chwl.library.utils.ResUtil +import com.chwl.library.utils.SingleToastUtil +import com.chwl.library.utils.UIUtils +import com.example.lib_utils.ktx.getString +import com.google.gson.Gson +import com.netease.nim.uikit.common.antispam.AntiSpamEvent +import com.netease.nimlib.sdk.StatusCode +import com.netease.nimlib.sdk.chatroom.ChatRoomMessageBuilder +import com.netease.nimlib.sdk.chatroom.model.ChatRoomKickOutEvent +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage +import com.orhanobut.logger.Logger +import com.tbruyelle.rxpermissions2.RxPermissions +import com.trello.rxlifecycle3.android.FragmentEvent +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import kotlinx.coroutines.launch +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode + + +/** + * 房間基類,這裏實現了一些房間基礎功能 + * 如發消息、公屏、底部按鈕等等... + * + * @author chenran + * @date 2017/7/26 + */ +open class BaseRoomFragment?> : + BaseMvpFragment(), + View.OnClickListener, OnGiftDialogBtnClickListener, IBaseRoomView, OnMicroItemClickListener, + RoomView { + private var myUid: Long = 0 + protected lateinit var messagePager: ViewPager2 + protected lateinit var messageView: MessageView + protected lateinit var bottomView: BottomView + protected lateinit var inputLayout: RelativeLayout + protected lateinit var inputEdit: EditText + protected lateinit var inputSend: ImageView + protected lateinit var inputSendImg: ImageView + protected lateinit var microView: MicroView + protected var mMusicPlayIconView: ImageView? = null + + + protected lateinit var floatBtnLayout: LinearLayout + protected lateinit var floatBtnLayoutFold: LinearLayout + protected lateinit var btnFold: ImageView + protected lateinit var boomLayout: FrameLayout + protected lateinit var boomIcon: ImageView + protected lateinit var boomProMax: ImageView + protected lateinit var boomPro: ImageView + protected lateinit var luckyBagBtn: LuckyBagBtn + protected lateinit var ivTeamPk: ImageView + protected lateinit var btnIvConfigEntrance: ImageView + protected lateinit var btnIvgame: ImageView + protected lateinit var mIvQueuingMicro: ImageView + + + //---连击时间 需要透明化的view + protected var mPlayTogether:View? = null + protected var mLayoutDragon:View? = null + + private var musicPlayerView: MusicPlayerView? = null + private var mVsMusicPlayer: ViewStub? = null + private var mDisposable: Disposable? = null + private var isCloseScreen = false + private var isOpenRedPackage = false + + private val mClickLimit by lazy { LimitClickUtils() } + + @JvmField + protected var isDatingMode = false + + /** + * 快捷發言 + */ + private var lastSendTime: Long = 0 + + + /** + * 是否開啟禮物值顯示 + */ + private var showGiftValue = false + private val mOnSoftKeyBoardChangeListener: OnSoftKeyBoardChangeListener = + object : OnSoftKeyBoardChangeListener { + override fun keyBoardShow(height: Int) { + /*軟鍵盤顯示:執行隱藏title動畫,並修改listview高度和裝載禮物容器的高度*/ + } + + override fun keyBoardHide(height: Int) { + /*軟鍵盤隱藏:隱藏聊天輸入框並顯示聊天按鈕,執行顯示title動畫,並修改listview高度和裝載禮物容器的高度*/ + inputLayout.visibility = View.GONE + } + } + private var dynamicFaceDialog: DynamicFaceDialog? = null + private var giftDialog: GiftDialog? = null + + private var atProxy: AtProxy? = null + + // 房间小组件 + private var widgets: HashMap = HashMap() + + //boomInfo 弹窗 + private var mBoomInfoDialog : RoomBoomInfoDialog ? = null + + private val PICK_CODE_IMG_MSG = 11113 + + @CallSuper + override fun onFindViews() { + initMessageView() + bottomView = mView.findViewById(R.id.bottom_view) + inputLayout = mView.findViewById(R.id.input_layout) + inputEdit = mView.findViewById(R.id.input_edit) + inputEdit.setOnKeyListener { _, keyCode, event -> + if (keyCode == KeyEvent.KEYCODE_ENTER && event.action == KeyEvent.ACTION_UP) { + sendMsg() + return@setOnKeyListener true + } + + false + } + inputSend = mView.findViewById(R.id.input_send) + inputSendImg = mView.findViewById(R.id.input_sendImg) + microView = mView.findViewById(R.id.micro_view) + + mMusicPlayIconView = mView.findViewById(R.id.iv_music) + mVsMusicPlayer = mView.findViewById(R.id.vs_music_player) + messageView.setClickConsumer { + if (!TextUtils.isEmpty(it) && it != "0") { + showUserCardDialog(it) + } + } + messageView.setOnClick(object : MessageView.OnClick { + override fun onFollowClick(position: Int) { + mvpPresenter?.followOwner(position, AvRoomDataManager.get().roomUid) + } + + override fun onJoinMiniWorldClick(position: Int) {} + override fun onShowRoomIntroduction() { + showRoomIntroduction(false) + } + }) + + initFloatBtnLayout() + + mLayoutDragon = mView.findViewById(R.id.layout_dragon) + mPlayTogether = mView.findViewById(R.id.play_together) + + } + + protected open fun initMessageView() { + messagePager = mView.findViewById(R.id.message_pager) + messageView = MessageView(context) + val tabList: MutableList = java.util.ArrayList(2) + tabList.add(getString(R.string.all)) + tabList.add(getString(R.string.send_msg)) + tabList.add(getString(R.string.send_gift_tab_title)) + messageView.setMsgType(getString(R.string.all)) + val messageIndicator = mView.findViewById(R.id.message_indicator) + messagePager.offscreenPageLimit = tabList.size + messagePager.adapter = object : RecyclerView.Adapter() { + override fun onCreateViewHolder( + parent: ViewGroup, + viewType: Int + ): RecyclerView.ViewHolder { + val view = messageView + view.layoutParams = ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT + ) + return BaseViewHolder(view) + } + + override fun getItemCount(): Int { + return 1 + } + + override fun getItemViewType(position: Int): Int { + return position + } + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + + } + } + val commonNavigator = CommonNavigator(context) + commonNavigator.setTitleWrapContent(false) + val magicIndicatorAdapter = RoomMessageIndicatorAdapter(context, tabList) + magicIndicatorAdapter.setOnItemSelectListener { position: Int, view: TextView? -> +// messagePager.currentItem = position + val tab = tabList.getOrNull(position) + tab?.let { + messageIndicator.onPageSelected(position) + messageView.setMsgType(it) + } + } + commonNavigator.adapter = magicIndicatorAdapter + messageIndicator.navigator = commonNavigator + messagePager.registerOnPageChangeCallback(object : OnPageChangeCallback() { + override fun onPageScrolled( + position: Int, + positionOffset: Float, + positionOffsetPixels: Int + ) { + messageIndicator.onPageScrolled( + position, + positionOffset, + positionOffsetPixels + ) + } + + override fun onPageSelected(position: Int) { + messageIndicator.onPageSelected(position) + } + + override fun onPageScrollStateChanged(state: Int) { + messageIndicator.onPageScrollStateChanged(state) + } + }) + } + + @CallSuper + override fun onSetListener() { + bottomView.setMagicBtnEnable(true) + inputSend.setOnClickListener(this) + inputSendImg.setOnClickListener(this) + inputLayout.setOnTouchListener { _: View?, _: MotionEvent? -> + inputEdit.clearFocus() + inputLayout.visibility = View.GONE + KeyBoardUtils.hideKeyBoard(activity, inputEdit) + false + } + + messageView.setOnLongClickListener { _, account, name -> + showInputLayout() + if (atProxy == null) atProxy = AtProxy(inputEdit) + atProxy?.insertAitMember(account, name) + } + softKeyboardListener() + } + + @SuppressLint("CheckResult") + @CallSuper + override fun initiate() { + initWidget() + //如果不需要開麥,並且還沒有權限的情況下,重置狀態為需要去打開麥克風 + myUid = AuthModel.get().currentUid + isCloseScreen = AvRoomDataManager.get().isCloseScreen + isOpenRedPackage = AvRoomDataManager.get().isOpenRedPackage + showGiftValue = AvRoomDataManager.get().isShowGiftValue + openOrCloseGiftValue(true) + updateView() + updateMicBtn() + AudioEngineManager.get().isNotRecord = AudioEngineManager.get().isNotRecord + microView.setOnMicroItemClickListener(this) + mDisposable = IMNetEaseManager.get().chatRoomEventObservable + .subscribe { onReceiveRoomEvent(it) } + if (AvRoomDataManager.get().mCurrentRoomInfo != null && + IMNetEaseManager.get().mCacheRoomQueueInfo != null && + !AvRoomDataManager.get().isFirstEnterRoomOrChangeOtherRoom( + AvRoomDataManager.get().mCurrentRoomInfo?.uid ?: 0 + ) + ) { + mvpPresenter?.chatRoomReConnect(IMNetEaseManager.get().mCacheRoomQueueInfo) + } + + // 接收公屏消息點擊 可點擊房間編輯頁查看 事件 + RxBus.get().toFlowable(OpenRoomIntroEvent::class.java) + .compose(bindToLifecycle()) + .subscribe { showRoomIntroduction(false) } + + RxBus.get().toFlowable(ShowGiftDialogEvent::class.java) + .compose(bindUntilEvent(FragmentEvent.DESTROY_VIEW)) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { onSendGiftBtnClick(it.giftId) } + + RxBus.get().toFlowable(ShowUserInfoDialogEvent::class.java) + .compose(bindUntilEvent(FragmentEvent.DESTROY_VIEW)) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { showUserCardDialog(it.uid) } + + // 刷新禮物列表,獲取房間專屬禮物列表 + GiftModel.get().refreshGiftList(AvRoomDataManager.get().roomUid.toString()).subscribe() + checkFollowOwner() + GiftValueMrg.get().updateRoomGiftValue(false) + + //获取免费礼物详情 + mvpPresenter?.queryFreeFlower() + initRoomAlbum() + initRoomBoom() + requestGamesData() + } + + fun initRoomBoom() { + LogUtils.d("roomLog RoomBoomManager initRoomBoom() roomUid = "+AvRoomDataManager.get().roomUid + " RoomBoomManager.mRoomUid = "+RoomBoomManager.mRoomUid) + if (RoomBoomManager.mRoomUid == -1L) return + checkBoomInfo() + upDateBoomExp() + LogUtils.d("roomLog RoomBoomManager initRoomBoom() end") + + } + + @SuppressLint("CheckResult") + private fun initRoomAlbum() { + RoomAlbumModel.listUnlockRoomPhoto(AvRoomDataManager.get().roomUid) + .compose(bindToLifecycle()) + .subscribe({ + AvRoomDataManager.get().unlockedRoomAlbumPhotos = it + }, { toast(it.message) }) + } + + @CallSuper + open fun onReceiveRoomEvent(roomEvent: RoomEvent?) { + if (roomEvent == null) return + val event = roomEvent.event + when (event) { + RoomEvent.ROOM_CHAT_RECONNECTION -> { + // 重新調服務器的userroom/inV2,保持座位上有貴族 + mvpPresenter?.userRoomIn() + //從新獲取隊列信息 + mvpPresenter?.chatRoomReConnect(roomEvent.roomQueueInfo) + //如果用戶在麥上的話,會重新上麥一次,如果不在麥上,則自行更新 + if (RxNetWorkUtils.isAvailable(mContext) && !AvRoomDataManager.get().isOwnerOnMic) { + GiftValueMrg.get().handleReconnect(false) + } + } + + RoomEvent.ROOM_EXIT -> { + // 退出房間,把標誌置為 false + AvRoomDataManager.get().isFromMentoring = false + // 退出房間的時候,要停止倒計時 + EventBus.getDefault().post(MentoringStopCountingEvent()) + } + + RoomEvent.DOWN_CROWDED_MIC -> if (AvRoomDataManager.get().isOwner(roomEvent.account)) { + toast(R.string.crowded_down) + } + + RoomEvent.ROOM_MANAGER_ADD, RoomEvent.ROOM_MANAGER_REMOVE -> { + updateView() + } + + RoomEvent.ROOM_INFO_UPDATE -> { +// "收到房间 ROOM_INFO_UPDATE 消息, 开始 跟新房间信息和UI ".doLog() + Logger.i(ResUtil.getString(R.string.avroom_fragment_baseroomfragment_01)) + addOpenDatingTips() //一定要放在updateView之前!!! + updateScreen() + updateRedPackage() + updateView() + updateRemoteMuteBtn() + updateConfigButtonArea() + openOrCloseGiftValue(false) + } + + RoomEvent.ENTER_ROOM -> { + Logger.i(ResUtil.getString(R.string.avroom_fragment_baseroomfragment_02)) + updateView() + updateRemoteMuteBtn() + openOrCloseGiftValue(true) + GiftValueMrg.get().updateRoomGiftValue(false) + onEnterRoom() + } + + RoomEvent.ADD_BLACK_LIST -> onChatRoomMemberBlackAdd(roomEvent.account) + RoomEvent.MIC_QUEUE_STATE_CHANGE -> onQueueMicStateChange() + RoomEvent.KICK_DOWN_MIC_BY_S_ADMIN, RoomEvent.KICK_DOWN_MIC -> if (event == RoomEvent.KICK_DOWN_MIC) { + SingleToastUtil.showToast( + mContext.resources.getString( + R.string.kick_mic + ) + ) + } else if (event == RoomEvent.KICK_DOWN_MIC_BY_S_ADMIN) { + SingleToastUtil.showToast( + mContext.resources.getString( + R.string.kick_mic_by_s_admin + ) + ) + } + + RoomEvent.DOWN_MIC -> { + onDownMicro() + } + + RoomEvent.UP_MIC -> { + onUpMicro() + } + + RoomEvent.INVITE_UP_MIC -> if (AvRoomDataManager.get().isOwner(roomEvent.account)) { + //自己的消息 + onInviteUpMic(roomEvent.micPosition) + } + + RoomEvent.KICK_OUT_ROOM -> { + val reason = roomEvent.reason + if (reason != null && reason.reason == ChatRoomKickOutEvent.ChatRoomKickOutReason.CHAT_ROOM_INVALID) { + releaseView() + } + AvRoomDataManager.get().removeChatRoomMember(roomEvent.account.toString()) + } + // 用戶的貴族字段過期或者開通貴族,可以實時地監聽ext字段變化,顯示頭飾,光暈等 + RoomEvent.ON_QUEUE_MEMBER_INFO_UPDATE -> microView.adapter.notifyDataSetChanged() + RoomEvent.OTHER_KICK_OUT_ROOM, + RoomEvent.OTHER_ADD_BLACK, + RoomEvent.OTHER_KICK_OUT_OR_ADD_BLACK_BY_S_ADMIN -> { + val targetUid = roomEvent.account + if (!TextUtils.isEmpty(targetUid)) { + AvRoomDataManager.get().removeChatRoomMember(targetUid) + } + } + + RoomEvent.LEAVE_MODE -> microView.adapter.notifyDataSetChanged() + RoomEvent.ROOM_CLEAN_SCREEN -> messageView.clear() + + RoomEvent.MSG_BOOM -> onBoomAboutMsg(roomEvent); + + RoomEvent.MSG_SELF_ENTER_ROOM -> initRoomBoom(); + + RoomEvent.MSG_ROOM_LUCKY_BAG_ADD -> onLuckyBagAdd(roomEvent); + } + } + + /** + * 開啟或關閉公屏 + */ + private fun updateScreen() { + if (AvRoomDataManager.get().mCurrentRoomInfo == null || + isCloseScreen == AvRoomDataManager.get().mCurrentRoomInfo?.isCloseScreen + ) return + isCloseScreen = AvRoomDataManager.get().mCurrentRoomInfo?.isCloseScreen == true + if (isCloseScreen) { + AvRoomDataManager.get().chatRoomDataRelease(false) + messageView.clear() + } + mvpPresenter?.updateScreen(isCloseScreen) + } + + private fun updateRedPackage() { + if (AvRoomDataManager.get().mCurrentRoomInfo == null || + isOpenRedPackage == AvRoomDataManager.get().mCurrentRoomInfo?.isServerRedEnvelopeSwitch + ) return + isOpenRedPackage = + AvRoomDataManager.get().mCurrentRoomInfo?.isServerRedEnvelopeSwitch == true + } + + /** + * 嗨聊房切換重置公屏消息(綠色公告) + */ + private fun addMessage(msg: ChatRoomMessage?) { + AvRoomDataManager.get().addChatRoomMessage(msg) + } + + /** + * 開啟或關閉禮物值 + */ + private fun openOrCloseGiftValue(isEnterRoom: Boolean) { + if (AvRoomDataManager.get().isOpenKTV || AvRoomDataManager.get().isCpRoom) { + GiftValueMrg.get().clearObsever() + return + } + if (!isEnterRoom && + (AvRoomDataManager.get().mCurrentRoomInfo == null + || showGiftValue == AvRoomDataManager.get().isShowGiftValue) + ) return + showGiftValue = AvRoomDataManager.get().isShowGiftValue + GiftValueMrg.get().openOrCloseGiftValue() + } + + override fun onNewIntent(intent: Intent) { + super.onNewIntent(intent) + // 釋放公屏和麥上的所有信息信息和動畫 + val roomUid = intent.getLongExtra(Constants.ROOM_UID, 0) + if (roomUid != 0L && roomUid != AvRoomDataManager.get().mCurrentRoomInfo?.uid) { + releaseView() + } + } + + fun initRoomAct( + rollPagerView: RollPagerView, + dialogInfo: List, + bottomDp: Float = 0f + ) { + if (!ListUtils.isListEmpty(dialogInfo)) { + rollPagerView.visibility = View.VISIBLE + // 只有一個圖標,隱藏底部指示器 + val show = dialogInfo.size > 1 + rollPagerView.setHintView(object : ColorPointHintView( + mContext, Color.WHITE, ContextCompat.getColor( + mContext, + R.color.color_66FFFFFF + ) + ) { + override fun makeFocusDrawable(): Drawable? { + val dotFocus = GradientDrawable() + dotFocus.setColor(Color.WHITE) + dotFocus.cornerRadius = Util.dip2px( + context, 2f + ).toFloat() + dotFocus.setSize( + Util.dip2px(context, 9f), Util.dip2px( + context, 4f + ) + ) + return if (show) dotFocus else null + } + + override fun makeNormalDrawable(): Drawable? { + val dotNormal = GradientDrawable() + dotNormal.setColor(ContextCompat.getColor(mContext, R.color.color_66FFFFFF)) + dotNormal.cornerRadius = Util.dip2px( + context, 2f + ).toFloat() + dotNormal.setSize( + Util.dip2px(context, 4f), Util.dip2px( + context, 4f + ) + ) + return if (show) dotNormal else null + } + }) + val bannerAdapter = RoomActAdapter(mContext, dialogInfo) + rollPagerView.adapter = bannerAdapter + rollPagerView.setPlayDelay(3000) + //設置透明度 + rollPagerView.setAnimationDurtion(500) + bannerAdapter.notifyDataSetChanged() + + // 模擬指示器在viewpager底部效果 + val viewPager = rollPagerView.viewPager + viewPager.offscreenPageLimit = dialogInfo.size + val layoutParams = viewPager.layoutParams as RelativeLayout.LayoutParams + layoutParams.setMargins(0, 0, 0, UIUtil.dip2px(mContext, bottomDp.toDouble())) + viewPager.layoutParams = layoutParams + } + } + + private fun releaseView() { + messageView.release() + microView.release() + musicPlayerView?.release() + GiftValueMrg.get().clearObsever() + } + + @CallSuper + open fun updateView() { + // 更新底欄 + showBottomViewForDifRole() + bottomView.notifyStateChanged() + } + + /** + * 根據角色顯示不同的狀態 + */ + @CallSuper + open fun showBottomViewForDifRole() { + val isOnMic = AvRoomDataManager.get().isOnMic(myUid) + if (isOnMic) { + bottomView.showHomePartyUpMicBottom() + } else { + bottomView.showHomePartyDownMicBottom() + } + bottomView.showInputOrIcon(isOnMic) + bottomView.updateGameEntrance() + // 更新聽筒消息 + bottomView.setRemoteMuteOpen(!AudioEngineManager.get().isRemoteMute) + if (isOnMic) { + if (musicPlayerView == null) { + musicPlayerView = mVsMusicPlayer?.inflate() as? MusicPlayerView + musicPlayerView?.let { + onInitMusicPlayerView(it) + } + } + musicPlayerView?.visibility = View.VISIBLE + } else { + musicPlayerView?.visibility = View.GONE + } + } + + /** + * 檢查是否關註房主,然後彈出 + */ + private fun checkFollowOwner() { + val currentRoomInfo = AvRoomDataManager.get().mCurrentRoomInfo ?: return + //如果當前賬號是房主也過濾 + if (AvRoomDataManager.get().isRoomOwner) { + return + } + mvpPresenter?.checkFollow(currentRoomInfo.uid) + } + + @CallSuper + open fun updateMicBtn() { + //xxx 关麦开麦 + val currentRoomInfo = AvRoomDataManager.get().mCurrentRoomInfo + if (currentRoomInfo != null) { + if (AudioEngineManager.get().isAudienceRole) { + bottomView.setMicBtnEnable(false) + bottomView.setMicBtnOpen(false) + } else { + val roomQueueInfo = AvRoomDataManager.get().getRoomQueueMemberInfoByAccount(myUid.toString()) + if (roomQueueInfo?.mChatRoomMember != null + && myUid.toString() == roomQueueInfo.mChatRoomMember.account + && roomQueueInfo.mRoomMicInfo?.isMicMute == true + ) { + //先判斷坑位是否被閉麥了 + bottomView.setMicBtnEnable(false) + bottomView.setMicBtnOpen(false) + } else { + bottomView.setMicBtnEnable(true) + if (AudioEngineManager.get().isMute) { + bottomView.setMicBtnOpen(false) + } else { + //獲取當前是否有麥克風權限 + val isPermission = isHavingMicPermissions + if (!isPermission) { + AudioEngineManager.get().isMute = true + } + bottomView.setMicBtnOpen(isPermission) + } + } + } + } else { + bottomView.setMicBtnEnable(false) + bottomView.setMicBtnOpen(false) + } + } + + private fun updateRemoteMuteBtn() { + if (AvRoomDataManager.get().mCurrentRoomInfo != null) { + bottomView.setRemoteMuteOpen(!AudioEngineManager.get().isRemoteMute) + } + } + + private fun onMicStateChanged() { + updateMicBtn() + } + + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + EventBus.getDefault().register(this) + } + + override fun onResume() { + super.onResume() + musicPlayerView?.updateVoiceValue() + updateMicBtn() + val chatRoomStatusChangeData = AvRoomDataManager.get().chatRoomStatusChangeData + if (chatRoomStatusChangeData != null && + chatRoomStatusChangeData.status == StatusCode.LOGINED + ) { + // 重新調服務器的userroom/inV2,保持座位上有貴族 + mvpPresenter?.userRoomIn() + } + } + + override fun onDestroyView() { + if (giftDialog != null) { + giftDialog?.setOnDismissListener(null) + giftDialog?.dismiss() + giftDialog = null + } + luckyBagBtn?.doDetach() + super.onDestroyView() + releaseView() + unregisterWidgets() + RoomBoomManager.mRoomUid = -1L + mBoomInfoDialog?.dismiss() + mBoomInfoDialog = null + } + + override fun onDestroy() { + mDisposable?.dispose() + mDisposable = null + EventBus.getDefault().unregister(this) + super.onDestroy() + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onAntiSpamEvent(event: AntiSpamEvent?) { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_fragment_baseroomfragment_04)) + } + + /** + * 清除公屏信息 + */ + @Subscribe(threadMode = ThreadMode.MAIN) + fun onClearScreenEvent(event: RoomClearScreenEvent?) { + messageView.clear() + } + + private fun isPublicMessageTab(): Boolean { + return messagePager.currentItem == 1 + } + + @CallSuper + override fun onClick(v: View) { + if (mClickLimit.checkForTime(500)) return + when (v.id) { + R.id.iv_config_entrance -> { + val roomInfo = AvRoomDataManager.get().mCurrentRoomInfo ?: return + val configInfo = AvRoomDataManager.get().rightBottomIconConfig ?: return + if (configInfo.skipType == 1) { + playConfigWeb(configInfo.skipUrl) + } else if (configInfo.skipType == 2) { + playConfigBaishunGame(configInfo) + } + } + R.id.iv_game -> { + val dialog = RoomGameListDialog(); + dialog.code = hashCode() + dialog.listener = object : RoomGameListDialog.GameplayDialogListener { + override fun onShowBaiShunGame(url: String, config: BaiShunGameConfig) { + (activity as? AVRoomActivity)?.showBaiShunGame(url, config) + } + + override fun onShowLeaderccGame(url: String, config: BaiShunGameConfig) { + (activity as? AVRoomActivity)?.showLeaderccGame(url, config) + } + override fun onShowJoyPlayGame(url: String, config: BaiShunGameConfig) { + (activity as? AVRoomActivity)?.showJoyPlayGame(url, config) + } + + override fun onShowLuckyBag() { + if (UserModel.get().cacheLoginUserInfo?.isRechargeUser == true) { + R.string._ver_23_Lucky_bag_Limit_tips.doToast() + return + } + RoomLuckyBagDialog().show(context) + } + } + dialog.show(childFragmentManager, "GAME_LIST") + } + R.id.input_send -> { + sendMsg() + } + R.id.input_sendImg -> { + sendImgMsg() + } + R.id.layout_room_rank -> { + DialogWebViewActivity.start(mContext, UriProvider.getRoomRanking()) + } + } + } + + private fun playConfigWeb(url: String) { + CommonWebViewActivity.start(mContext, url) + } + + private fun playConfigBaishunGame(configInfo: RightBottomIconConfig) { + val roomIcon: RoomIcon = RoomIcon( + skipContent = configInfo.skipUrl, + skipType = 3, + showType = 1, + code = "BAISHUN", + ruleValue = configInfo.reserve) + try { + val url = roomIcon.skipContent + val ruleValue = Gson().fromJson( + roomIcon.ruleValue, + RoomIcon.RuleValueBean::class.java + ) + val config = Gson().fromJson( + ruleValue.RESERVE, + BaiShunGameConfig::class.java + ) + if (config != null && url != null) { + config.reloadDynamicParams() + (activity as? AVRoomActivity)?.showBaiShunGame(url, config) + } else { + SingleToastUtil.showToast(R.string.manager_trtc_trtcengineadapter_042) + } + } catch (e: Exception) { + e.printStackTrace() + } + } + + private fun sendMsg() { + val message = inputEdit.text.toString().trim() + if (isPublicMessageTab()) { + sendPublicChatMessage(message) + } else { + sendMsg(message) + } + } + + //xxx - 发送图片消息 + private fun sendImgMsg() { + UserModel.get().cacheLoginUserInfo?.let { + UserModel.get().getUserInfoFromServerUpdate(it.uid,true) + .compose(bindToLifecycle()) + .doOnSuccess { user-> + if (VipHelper.roomPicScreen(user)) { + activity?.let { act-> + try { + inputEdit.clearFocus() + inputLayout.visibility = View.GONE + KeyBoardUtils.hideKeyBoard(activity, inputEdit) + PhotoPickActivity.startImg(act,PICK_CODE_IMG_MSG) + } catch (e: Exception) { + } + } + } else { + dialogManager?.showOkDialog(R.string._ver_24_sentImgVipError.getString()) + } + } + .doOnError { + it?.message?.doToast() + } + .subscribe() + } + } + + @SuppressLint("CheckResult") + fun sendMsg(msg: String) { + if (!AuthModel.get().isImLogin) { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_fragment_baseroomfragment_07)) + return + } + if (TextUtils.isEmpty(msg)) { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_fragment_baseroomfragment_08)) + return + } + val roomInfo = AvRoomDataManager.get().mCurrentRoomInfo ?: return + if (roomInfo.isCloseScreen) { + toast(ResUtil.getString(R.string.avroom_fragment_baseroomfragment_09)) + return + } + mvpPresenter?.sendTextMsg(msg, atProxy) + messageView.setNeedAutoScroll(true) // 發送後自動滾動公屏列表 + inputEdit.setText("") + } + + private fun sendPublicChatMessage(message: String){ + if (!AuthModel.get().isImLogin) { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_fragment_baseroomfragment_07)) + return + } + if (TextUtils.isEmpty(message)) { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_fragment_baseroomfragment_08)) + return + } + mvpPresenter?.sendPublicChatTextMessage(message) + inputEdit.setText("") + } + + /** + * 軟鍵盤顯示與隱藏的監聽 + */ + private fun softKeyboardListener() { + SoftKeyBoardListener.setListener(activity, mOnSoftKeyBoardChangeListener) + } + + @SuppressLint("CheckResult") + override fun onSendGiftBtnClick( + giftInfo: GiftInfo, + micMemberInfos: ArrayList, + number: Int, + msg: String?, + isKnap: Boolean, + isWholdMic: Boolean, + drawFixedArray: List>?, + callback: SenGiftCallback + ) { + val targetUids: MutableList = ArrayList() + for (i in micMemberInfos.indices) { + targetUids.add(micMemberInfos[i].account.toLong()) + } + + EventBus.getDefault().post(GiftComboEvent(GiftComboEvent.Action.ACT_GIFT_BEGIN)) + + GiftModel.get() + .sendRoomGift( + giftInfo.giftId, + targetUids, + number, + msg, + isKnap, + isWholdMic, + drawFixedArray + ) + .compose(bindUntilEvent(FragmentEvent.DESTROY)) + .doOnError { + if (it is VipLevelNotEnoughException) { + val message = context?.getString( + R.string.send_gift_vip_level_tips, + giftInfo.giftName ?: "", + giftInfo.giftVipInfo?.vipName ?: "" + ) + dialogManager.showOkDialog(message) + } + } + .subscribe { gift, throwable -> + if (throwable != null) { + toast(throwable.message) + callback.onFail() + EventBus.getDefault().post(GiftComboEvent(GiftComboEvent.Action.ACT_GIFT_COMBO_CANCEL)) + } else { + callback.onSuccess() + } + } + } + + private fun onUpMicro() { + showBottomViewForDifRole() + updateMicBtn() + microView.adapter.notifyDataSetChanged() + } + + @CallSuper + open fun onInviteUpMic(micPosition: Int) { + mvpPresenter?.upMicroPhone(micPosition, AuthModel.get().currentUid.toString(), true) + if (UIUtils.isTopActivity(baseActivity)) { + (activity as BaseMvpActivity<*, *>?)?.dialogManager + ?.showOkWithTitleDialog(getString(R.string.embrace_on_mic), true) + } + } + + private fun onDownMicro() { + showBottomViewForDifRole() + updateMicBtn() + microView.adapter.notifyDataSetChanged() + //下麥時更新最高最低頭飾 + GiftValueMrg.get().updateRoomGiftValue(false) + } + + private fun onQueueMicStateChange() { + microView.adapter.notifyDataSetChanged() + onMicStateChanged() + } + + override fun kickDownMicroPhoneSuccess() { + updateMicBtn() + toast(R.string.kick_mic) + } + + override fun showOwnerClickDialog( + roomMicInfo: RoomMicInfo, + micPosition: Int, + currentUid: Long + ) { + val buttonItems: MutableList = ArrayList(4) + val presideMic = AvRoomDataManager.get().isDatingMode && micPosition == -1 + val presideText = if (presideMic) ResUtil.getString(R.string.switch_host) else "" + val buttonItem1 = ButtonItem( + getString(R.string.embrace_up_mic) + presideText, + object : ButtonItem.OnClickListener { + override fun onClick() { + RoomInviteActivity.openActivity(activity, micPosition, presideMic) + } + }) + val buttonItem2 = + ButtonItem(if (roomMicInfo.isMicMute) getString(R.string.no_forbid_mic) else getString( + R.string.forbid_mic + ), object : ButtonItem.OnClickListener { + override fun onClick() { + if (roomMicInfo.isMicMute) { + if (SuperAdminUtil.isSuperAdmin()) { + SingleToastUtil.showToast(SaConstant.TOAST_ERROR_TIPS) + return + } + mvpPresenter?.openMicroPhone(micPosition) + } else { + mvpPresenter?.roomOperate(SuperAdminModel.CLOSE_MIC) + mvpPresenter?.closeMicroPhone(micPosition) + } + } + }) + val isQueue = AvRoomDataManager.get().isQueuingMicro + val isBossMic = micPosition == -1 + val unlockStr = + getString(if (isQueue && (!isBossMic)) R.string.unlock_mic_queue else R.string.unlock_mic) + val lockStr = + getString(if (isQueue && (!isBossMic)) R.string.lock_mic_queue else R.string.lock_mic) + val buttonItem3 = ButtonItem( + if (roomMicInfo.isMicLock) unlockStr else lockStr, + ButtonItem.OnClickListener { + if (roomMicInfo.isMicLock) { + if (SuperAdminUtil.isSuperAdmin()) { + SingleToastUtil.showToast(SaConstant.TOAST_ERROR_TIPS) + return@OnClickListener + } + mvpPresenter?.unLockMicroPhone(micPosition) + } else { + mvpPresenter?.roomOperate(SuperAdminModel.LOCK_MIC) + mvpPresenter?.lockMicroPhone(micPosition) + } + }) + val buttonItem4 = + ButtonItem(ResUtil.getString(R.string.up_mic)) { + toUpMicroPhone( + micPosition, + currentUid.toString() + "", + false + ) + } + //別問為什麽,ui調整了順序 + //禁用超管的上麥和抱TA上麥 + if (!SuperAdminUtil.isSuperAdmin()) { + //個播房沒有主動上麥功能 + if (!AvRoomDataManager.get().isSingleRoom) { + buttonItems.add(buttonItem4) + } + //個播房只有房主有抱上麥功能 + if ((!AvRoomDataManager.get().isSingleRoom || AvRoomDataManager.get().isRoomOwner || AvRoomDataManager.get().isRoomAdmin) && + !AvRoomDataManager.get().isDatingVipMic(micPosition) + ) { + buttonItems.add(buttonItem1) + } + +// if (AvRoomDataManager.get().isSingleRoom) { +// if (AvRoomDataManager.get().isRoomOwner && !AvRoomDataManager.get().isDatingVipMic(micPosition)) { +// buttonItems.add(buttonItem1) +// } +// } else { +// if ((AvRoomDataManager.get().isRoomOwner || AvRoomDataManager.get().isRoomAdmin) && !AvRoomDataManager.get().isDatingVipMic(micPosition)){ +// buttonItems.add(buttonItem1) +// } +// } + + } + if (!AvRoomDataManager.get().isOpenPKMode) { + //超管只有鎖麥操作 + if (SuperAdminUtil.isSuperAdmin()) { + if (!roomMicInfo.isMicLock && !isQueue) { + buttonItems.add(buttonItem3) + } + } else { + if (!AvRoomDataManager.get().isDatingVipMic(micPosition)) { + buttonItems.add(buttonItem3) + } + } + } + //超管只有閉麥操作 + if (SuperAdminUtil.isSuperAdmin()) { + if (!roomMicInfo.isMicMute) { + buttonItems.add(buttonItem2) + } + } else { + buttonItems.add(buttonItem2) + } + dialogManager.showCommonPopupDialog(buttonItems, getString(R.string.cancel)) + } + + override fun chatRoomReConnectView() { + if (microView.adapter != null) microView.adapter.notifyDataSetChanged() + } + + override fun onAvatarBtnClick(position: Int) { + val roomInfo = AvRoomDataManager.get().mCurrentRoomInfo + if ((roomInfo != null) && + (roomInfo.isLeaveMode || AvRoomDataManager.get().isSingleRoom) + && position == -1 + ) { + showUserCardDialog(roomInfo.uid.toString()) + } else { + val roomQueueInfo = AvRoomDataManager.get() + .getRoomQueueMemberInfoByMicPosition(position) + if (roomQueueInfo?.mChatRoomMember == null) { + return + } + val account = roomQueueInfo.mChatRoomMember.account + if (TextUtils.isEmpty(account)) { + return + } + showUserCardDialog(account) + } + } + + override fun onUpMicBtnClick(position: Int, chatRoomMember: MicMemberInfo?) { + if (MyUtil.upMicIng) { + "上麦 , 点击频繁限制".doLog() + R.string.avroom_dialog_micqueuedialog_01.doToast() + return + } + + if (AvRoomDataManager.get().isDatingVipMic(position) && !AvRoomDataManager.get().isDatingVip(AuthModel.get().currentUid)) { + DatingVipRuleDialog.newInstance(mContext).show() + } else { + mvpPresenter?.microPhonePositionClick(position, chatRoomMember) + } + } + + override fun onLockBtnClick(position: Int) { + mvpPresenter?.unLockMicroPhone(position) + } + + override fun onRoomSettingsClick() { + showRoomIntroduction(AvRoomDataManager.get().isRoomOwner || AvRoomDataManager.get().isRoomAdmin) + } + + @CallSuper + open fun clearDialog() { + try { + giftDialog?.dismiss() + dynamicFaceDialog?.dismiss() + } catch (e: Exception) { + e.printStackTrace() + } + } + + private fun showRoomIntroduction(modify: Boolean) { + var isModify = modify + val info = AvRoomDataManager.get().mCurrentRoomInfo ?: return + if (SuperAdminUtil.isSuperAdmin()) { + isModify = false + } + if (isModify) { + RoomTitleEditActivity.startForResult(activity, info.roomDesc, info.introduction) + } else { + val dialogFragment = + RoomTitleDialogFragment.getInstance(info.roomDesc, info.introduction) + dialogFragment.show(requireActivity().supportFragmentManager, "roomTitle") + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (requestCode == 200 && resultCode == 100) { + if (data != null && data.extras != null) { + val account = data.extras?.getString("account") + val nick = data.extras?.getString("nick") + if (TextUtils.isEmpty(account)) return + if (AvRoomDataManager.get().isLeaveMode && + (account == AvRoomDataManager.get().roomUid.toString()) + ) { + showToast(getString(R.string.tips_close_leave_mode_first)) + return + } + val micPosition = data.extras?.getInt(Constants.KEY_POSITION, Int.MIN_VALUE) + if (micPosition == Int.MIN_VALUE) return + + //抱人上麥 + mvpPresenter?.inviteMicroPhone(BaseInfo(account, nick), micPosition ?: Int.MIN_VALUE) + } + } else if (requestCode == SelectFriendActivity.CODE_REQUEST_TO_SHARE_ROOM && resultCode == Activity.RESULT_OK) { + val targetUid = data?.getStringExtra(SelectFriendActivity.EXTRA_TARGET_UID) + val sessionType = + data?.getIntExtra(SelectFriendActivity.EXTRA_SESSION_TYPE, SessionType.P2P) + ?: SessionType.P2P + IMNetEaseManager.get().sendSharingRoomMessage(sessionType, targetUid) + }else if (requestCode == PICK_CODE_IMG_MSG && resultCode == Activity.RESULT_OK) { + RoomHelperManager.sendPicMsg(this@BaseRoomFragment,data) + } + } + + fun onChatRoomMemberBlackAdd(account: String?) { + //拉黑 + if (AvRoomDataManager.get().isOnMic(account)) { + val micPosition = AvRoomDataManager.get().getMicPosition(account) + mvpPresenter?.downMicroPhone(micPosition, true) + } + val memberListIterator = AvRoomDataManager.get().mRoomManagerList.listIterator() + while (memberListIterator.hasNext()) { + if ((memberListIterator.next().account == account)) { + memberListIterator.remove() + } + } + if (AvRoomDataManager.get().isRoomOwner(account)) { + //當前是房主 + AvRoomDataManager.get().mRoomCreateMember = null + } + } + + override fun showToast(msg: String?) { + toast(msg) + } + + override fun onSendMsgSuccess(msg: String?) { + inputEdit.setText("") + KeyBoardUtils.hideKeyBoard(activity, inputEdit) + } + + override fun onSendPublicChatMsgSuccess(msg: ChatRoomMessage) { + inputEdit.setText("") + KeyBoardUtils.hideKeyBoard(activity, inputEdit) + } + + /** + * 顯示資料卡片 + */ + private fun showUserCardDialog(account: String) { + UserInfoDialog.showNewUserInfoDialog( + mContext, + JavaUtil.str2long(account), + true, + true, + true, + this@BaseRoomFragment + ) + } + + @SuppressLint("CheckResult") + override fun toUpMicroPhone(micPosition: Int, currentUid: String, b: Boolean) { + if (!lifecycle.currentState.isAtLeast(androidx.lifecycle.Lifecycle.State.CREATED)) { + return + } + if (AvRoomDataManager.get().isSelfGamePlaying) { + SingleToastUtil.showToast(R.string.avroom_presenter_baseroompresenter_01) + return + } + UserModel.get().cacheLoginUserInfo?.gameStatus = GameStatus.STATUS_NOT_JOIN + checkPermission(Manifest.permission.RECORD_AUDIO) + .subscribe({ result: Boolean -> + if (result) { + mvpPresenter?.upMicroPhone(micPosition, currentUid, b) + } else { + toast(R.string.permission_mic_tips) + } + }, { error: Throwable? -> + error?.let { + toast(it.message) + } ?: toast(R.string.exception_try_again) + }) + } + + /** + * 是否有麥克風權限 + * + * @return + */ + private val isHavingMicPermissions: Boolean + get() = ContextCompat.checkSelfPermission( + mContext, + Manifest.permission.RECORD_AUDIO + ) == PackageManager.PERMISSION_GRANTED + + override fun noFollow() { + messageView.post { + val roomInfo: RoomInfo? = AvRoomDataManager.get().mCurrentRoomInfo + val userInfo: UserInfo? = UserModel.get().cacheLoginUserInfo + if (roomInfo == null || userInfo == null) { + return@post + } + val roomFollowOwnerAttachment = RoomFollowOwnerAttachment() + roomFollowOwnerAttachment.ownerUid = AvRoomDataManager.get().roomUid + roomFollowOwnerAttachment.userInfo = userInfo + AvRoomDataManager.get().addChatRoomMessage( + ChatRoomMessageBuilder.createChatRoomCustomMessage( + roomInfo.roomId.toString(), roomFollowOwnerAttachment + ) + ) + + } + } + + override fun showAttentionDialog() { + val roomInfo = AvRoomDataManager.get().mCurrentRoomInfo + if (roomInfo != null) { + AttentionHintDialog(mContext).show() + } + } + + override fun noFollow2() { + messageView.post { + val roomInfo: RoomInfo? = AvRoomDataManager.get().mCurrentRoomInfo + val userInfo: UserInfo? = UserModel.get().cacheLoginUserInfo + if (roomInfo == null || userInfo == null) { + return@post + } + val roomFollowOwnerAttachment = RoomFollowOwnerAttachment2() + roomFollowOwnerAttachment.ownerUid = AvRoomDataManager.get().roomUid + roomFollowOwnerAttachment.userInfo = userInfo + + AvRoomDataManager.get().addChatRoomMessage( + ChatRoomMessageBuilder.createChatRoomCustomMessage( + roomInfo.roomId.toString(), + roomFollowOwnerAttachment + ) + ) + } + } + override fun onFollowSuccess(position: Int) { + messageView.changeFollowStatus(position, true) + } + + override fun onFollowFail(msg: String?) { + msg?.let { + toast(msg) + } + } + + override fun updateMicView() { + microView.adapter.notifyDataSetChanged() + } + + private fun onSendGiftBtnClick(giftId: Int = 0) { + if (giftDialog == null) { + GiftDialog.GIFT_DIALOG_FROM = getString(R.string.room) + giftDialog = GiftDialog(context, giftId) + giftDialog?.setGiftDialogBtnClickListener(this@BaseRoomFragment) + giftDialog?.setOnDismissListener { giftDialog = null } + } + if (giftDialog?.isShowing != true && !requireActivity().isFinishing) { + EventBus.getDefault().post(GiftComboEvent(GiftComboEvent.Action.ACT_GIFT_POINT)) + EventBus.getDefault().post(GiftComboEvent(GiftComboEvent.Action.ACT_GIFT_DIALOG_DISMISS)) + if (activity != null && activity?.isFinishing == false && activity?.isDestroyed == false && this@BaseRoomFragment.isAdded){ + if (AvRoomDataManager.get().hasAvRoomAct) { + giftDialog?.show() + } + } + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onGiftComboEvent(event: GiftComboEvent) { + if (event.action == GiftComboEvent.Action.ACT_GIFT_SEND_SUCCESS) { + //展示连击view ,隐藏其他view + setComboViewVis(false) + + } else if (event.action == GiftComboEvent.Action.ACT_GIFT_DIALOG_SHOW) { + //隐藏连击view ,展示其他view + setComboViewVis(true) + } + } + + private fun setComboViewVis(vis: Boolean) { + floatBtnLayout.alpha = if (vis) 1f else 0f //bottom_view + bottomView.alpha = if (vis) 1f else 0f //bottom_view + inputLayout.alpha = if (vis) 1f else 0f //input_layout + mLayoutDragon?.alpha = if (vis) 1f else 0f //layout_dragon + mPlayTogether?.alpha = if (vis) 1f else 0f //play_together + +// floatBtnLayout.setVisNoSafe(vis,true) +// bottomView.setVisNoSafe(vis,true) +// inputLayout.setVisNoSafe(vis,true) +// mLayoutDragon?.setVisNoSafe(vis,true) +// mPlayTogether?.setVisNoSafe(vis,true) + } + + /** + * 開啟相親模式管理增加一條公屏提示 + */ + private fun addOpenDatingTips() { + if (AvRoomDataManager.get().isDatingMode && !isDatingMode && AvRoomDataManager.get().isManager) { + val tipMessage = + ChatRoomMessageBuilder.createTipMessage(ResUtil.getString(R.string.yizhuan_xchat_android_constants_xchatconstants_09)) + tipMessage.content = ResUtil.getString(R.string.yizhuan_xchat_android_constants_xchatconstants_09) + IMNetEaseManager.get().addMessages(tipMessage) + } + } + + /** + * 用戶彈窗點擊@Ta + * + * @param event + */ + @Subscribe(threadMode = ThreadMode.MAIN) + open fun onRoomAtEvent(event: RoomAtEvent) { + if (atProxy == null) atProxy = AtProxy(inputEdit) + showInputLayout() + atProxy?.insertAitMember(event.account, event.name) + } + + private fun showInputLayout() { + inputLayout.postDelayed({ + inputLayout.visibility = View.VISIBLE + inputEdit.isFocusableInTouchMode = true + inputEdit.requestFocus() + KeyBoardUtils.showKeyBoard(context, inputEdit) + }, 200) + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onRoomFreeGiftEvent(event: RoomFreeGiftEvent) { + } + + + /** + * 底部按鈕點擊處理 + */ + open inner class BaseRoomBottomViewWrapper : BottomViewListenerWrapper() { + + @SuppressLint("CheckResult") + override fun onOpenMicBtnClick(type : Int) { + //xxx 关麦开麦 + val roomQueueInfo = AvRoomDataManager.get().getRoomQueueMemberInfoByAccount(AuthModel.get().currentUid.toString()) + if (roomQueueInfo?.mRoomMicInfo == null) return + //先判斷麥上是否是開麥的 + if (!roomQueueInfo.mRoomMicInfo.isMicMute && !AudioEngineManager.get().isAudienceRole) { + + if (!isHavingMicPermissions) { + val rxPermissions = RxPermissions(this@BaseRoomFragment) + rxPermissions.request(Manifest.permission.RECORD_AUDIO) + .subscribe { aBoolean: Boolean -> + if (aBoolean) { + + if (type == MyConstant.MicType.open) { + AudioEngineManager.get().isMute = false + AudioEngineManager.get().isNotRecord = false +// AudioEngineManager.get().setRole(Constants.CLIENT_ROLE_BROADCASTER) + }else if (type == MyConstant.MicType.music) { + AudioEngineManager.get().isMute = false +// AudioEngineManager.get().setRole(Constants.CLIENT_ROLE_BROADCASTER) + AudioEngineManager.get().isNotRecord = true + }else if (type == MyConstant.MicType.close) { + AudioEngineManager.get().isMute = true +// AudioEngineManager.get().setRole(Constants.CLIENT_ROLE_AUDIENCE) + AudioEngineManager.get().isNotRecord = false + } + updateMicBtn() + } else { + toast(R.string.ask_again.getString()) + } + } + return + } + + if (type == MyConstant.MicType.open) { + AudioEngineManager.get().isMute = false + AudioEngineManager.get().isNotRecord = false +// AudioEngineManager.get().setRole(Constants.CLIENT_ROLE_BROADCASTER) + }else if (type == MyConstant.MicType.music) { + AudioEngineManager.get().isMute = false +// AudioEngineManager.get().setRole(Constants.CLIENT_ROLE_BROADCASTER) + AudioEngineManager.get().isNotRecord = true + }else if (type == MyConstant.MicType.close) { + AudioEngineManager.get().isMute = true +// AudioEngineManager.get().setRole(Constants.CLIENT_ROLE_AUDIENCE) + AudioEngineManager.get().isNotRecord = false + } + + updateMicBtn() + + if (AudioEngineManager.get().isMute) { + AudioEngineManager.get().stopLocalAudio() + } else if (AvRoomDataManager.get().isOnMic(myUid)) { + AudioEngineManager.get().setRole(Constants.CLIENT_ROLE_BROADCASTER) + } + + } + } + + + + override fun onSendFaceBtnClick() { + if (AvRoomDataManager.get().isOnMic(myUid) || AvRoomDataManager.get().isRoomOwner) { + if (dynamicFaceDialog == null) { + dynamicFaceDialog = DynamicFaceDialog() + dynamicFaceDialog?.setOnDismissListener { + dynamicFaceDialog = null + } + } + + if (dynamicFaceDialog?.isAdded != true) { + dynamicFaceDialog?.show(context) + } + } else { + toast("上麥才能發表情哦!") + } + } + + override fun onSendMsgBtnClick() { + openMessageInput(null) + } + + override fun onSendGiftBtnClick() { + this@BaseRoomFragment.onSendGiftBtnClick() + } + + override fun onRemoteMuteBtnClick() { + val isRemoteMute = !AudioEngineManager.get().isRemoteMute + AudioEngineManager.get().isRemoteMute = isRemoteMute + updateRemoteMuteBtn() + } + + override fun onMoreBtnClick() { + val dialog = RoomOperationDialog(mContext) + dialog?.setOnActionListener(object : RoomOperationDialog.OnActionListener { + override fun onActionClick(type: Int, data: Any?) { + if (type == R.drawable.icon_room_operation_music) { + mMusicPlayIconView?.performClick() + } + } + }) + dialog.show() + } + + override fun onRoomMessageClick() { + RoomMsgActivity.start(mContext) + } + + override fun onRoomGameplayClick(isOnlyPK: Boolean) { + if (isOnlyPK) { + val dialog = RoomGameplayDialog() + dialog.isOnlyPK = isOnlyPK + dialog.listener = object : RoomGameplayDialog.GameplayDialogListener { + override fun onShowBaiShunGame(url: String, config: BaiShunGameConfig) { + (activity as? AVRoomActivity)?.showBaiShunGame(url, config) + } + } + dialog.show(childFragmentManager, "ROOM_GAME_PLAY") + } else { + RoomGameListDialog().show(childFragmentManager, "GAME_LIST") + } + } + } + + /** + * 注册组件 + */ + protected fun registerWidget(name: String, widget: RoomWidget) { + widgets.put(name, widget) + widget.onStart(this) + } + + /** + * 取消注册组件 + */ + protected fun unregisterWidgets() { + widgets.values.forEach { + it.onStop() + } + widgets.clear() + } + + override fun getLifecycleOwner(): LifecycleOwner { + return this + } + + override fun getViewFragmentManager(): FragmentManager { + return activity?.supportFragmentManager ?: childFragmentManager + } + + override fun findWidget(name: String): RoomWidget? { + return widgets[name] + } + + override fun getRoomContext(): RoomContext? { + return AudioRoomContext.get() + } + + override fun getRoomContextLiveData(): LiveData { + return AudioRoomContext.contextLiveData + } + + open fun initWidget() { + } + + @Subscribe(threadMode = ThreadMode.MAIN) + open fun onOpenRoomMessageInputEvent(event: OpenRoomMessageInputEvent) { + lifecycleScope.launch { + lifecycle.withResumed { + view?.postDelayed({ + openMessageInput(event.text) + }, 500) + } + } + } + + /** + * 打开公屏输入 + */ + fun openMessageInput(text: String?) { + inputLayout.visibility = View.VISIBLE + if (text != null) { + inputEdit.setText(text) + inputEdit.setSelection(inputEdit.length()) + } + inputEdit.isFocusableInTouchMode = true + inputEdit.requestFocus() + KeyBoardUtils.showKeyBoard(context, inputEdit) + } + + protected open fun onEnterRoom(){ + + } + + protected open fun onInitMusicPlayerView(view: MusicPlayerView) { + mMusicPlayIconView?.let { + view.linkIconView(it,it) + } + } + + + + + + //通用消息 + @Subscribe(threadMode = ThreadMode.MAIN) + fun onNotifyEvent(event: NotifyEvent) { + when (event.action) { + NotifyEvent.Action.ACT_BAI_SHUN_GAME-> { + val gameId = event.data + if (gameId is String){ + val roomContext = get() + if (roomContext != null) { + val dataService = roomContext.findAbility(RoomDataService::class.java.simpleName) + if (dataService != null) { + val gameplay_list = "gameplay_list#" + hashCode() + val gameplayList = dataService?.getData(gameplay_list) as? List + if (gameplayList.isVerify()) { + val game = GameUtil.findGame(gameId.toLong(), gameplayList!!) + if (game != null) { + GameUtil.startGame(game){url, config-> + if (game.isLeadercc()) { + (activity as? AVRoomActivity)?.showLeaderccGame(url, config) + }else if (game.isBaiShunGame()) { + (activity as? AVRoomActivity)?.showBaiShunGame(url, config) + }else if (game.isJoyPlay()) { + (activity as? AVRoomActivity)?.showJoyPlayGame(url, config) + } + } + } + } + } + } + } + } + + else -> {} + } + } + + + var hasBaishunGames = false + var mGameSize = 0 + private fun requestGamesData() { + val roomContext = get() + if (roomContext != null) { + mGameSize = 0 + val dataService = roomContext.findAbility(RoomDataService::class.java.simpleName) + + if (dataService != null) { + val game_list = "game_list#" + hashCode() + val gameplay_list = "gameplay_list#" + hashCode() + + val getGameList = getGameList(AvRoomDataManager.get().roomUid) + .doOnError { + hasBaishunGames = mGameSize > 0 + updateConfigButtonArea() + } + .subscribe { it: List -> + if (dataService != null) { + LogUtils.d("gameListData-- game_list 2 save code=$game_list size=${it.size}") + mGameSize+=it.size + dataService.putData(game_list, it) + hasBaishunGames = mGameSize > 0 + updateConfigButtonArea() + } + } + + val roomGamePlayList = AvRoomModel.get().roomGamePlayList.doOnError { + hasBaishunGames = mGameSize > 0 + updateConfigButtonArea() + }.subscribe { roomIcons -> + if (dataService != null) { + LogUtils.d("gameListData-- gameplay_list 1 save code=$gameplay_list size=${roomIcons.size}") + dataService.putData(gameplay_list, roomIcons) + } + mGameSize+=roomIcons.size + hasBaishunGames = mGameSize > 0 + updateConfigButtonArea() + } + } + } + } + + private fun updateConfigButtonArea() { + val configModel = AvRoomDataManager.get().rightBottomIconConfig + if (configModel == null) { + btnIvConfigEntrance.setVisibility(View.GONE) + } else { + if (configModel.icon1Url == null || TextUtils.isEmpty(configModel.icon1Url)) { + btnIvConfigEntrance.setVisibility(View.GONE) + } else { + ImageLoadUtils.loadAvatar(configModel.icon1Url, btnIvConfigEntrance) + btnIvConfigEntrance.setVisibility(View.VISIBLE) + } + + if (configModel.icon2Url != null) { + ImageLoadUtils.loadImage( btnIvgame,configModel.icon2Url) + } + } + + if (hasBaishunGames) { + btnIvgame.setVisibility(View.VISIBLE) + } else { + btnIvgame.setVisibility(View.GONE) + } + } + + + /** + * boom 玩法消息 + */ + private fun onBoomAboutMsg(roomEvent: RoomEvent) { + val data = roomEvent.boomMsg + if (data != null) { + LogUtils.d(" RoomBoomManager BaseRoom onBoomAboutMsg() second=${data.second} ") + if (data.second == CustomAttachment.BOOM_SECOND_EXP_PUSH) { + val expPushBean = data.expPushBean + if (expPushBean != null) { + onExpPush(expPushBean) + } + } else if (data.second == CustomAttachment.BOOM_SECOND_AWARD) { + val awardList = data.awardList + if (awardList != null) { + onAwardDialog(awardList) + } + } else if (data.second == CustomAttachment.BOOM_SECOND_DIALOG) { + // 播放动画 + val dialogBean = data.DialogBean + if (dialogBean != null) { + onBoomAnim(dialogBean) + } + } + } + } + + var mBoomExp: BoomMsgExpPushBean?=null + //更新boom进度 + private fun onExpPush(expPushBean: BoomMsgExpPushBean,isOverride:Boolean=false) { + LogUtils.d(" RoomBoomManager BaseRoom onExpPush() indexLevel=${mBoomExp?.level} expPushLevel=${expPushBean.level} indexSpeed=${mBoomExp?.speed} expPushSpeed=${expPushBean.speed} ") + + mBoomInfoDialog?.setPro(expPushBean.speed,expPushBean.level) + + if (!isOverride){ + if (mBoomExp != null) { + if (mBoomExp!!.level > expPushBean.level) return + if (mBoomExp!!.level == expPushBean.level && mBoomExp!!.speed >= expPushBean.speed) return + } + } + + mBoomExp = expPushBean + boomLayout.setVis(true) + boomIcon.loadImage(expPushBean.pic) + boomProMax.post { + val width = (boomProMax.width * (expPushBean.speed.toFloat() / 100)).toInt() + LogUtils.d(" RoomBoomManager BaseRoom onExpPush() width = $width") + boomPro.setViewWH(width = width, isDP = false) + } + boomPro.scaleType = if (expPushBean.speed < 90) ImageView.ScaleType.MATRIX else ImageView.ScaleType.FIT_XY + } + + //boom中奖弹窗 + private fun onAwardDialog(awardList: BoomMsgAwardList) { + LogUtils.d(" RoomBoomManager BaseRoom onAwardDialog() ") + RoomBoomManager.addAward(awardList) + } + + //boom进度满了 播放动画 + private fun onBoomAnim(dialogBean: BoomMsgDialogBean) { + LogUtils.d(" RoomBoomManager BaseRoom onBoomAnim() ") + if (dialogBean.roomUid == AvRoomDataManager.get().roomUid) { + RoomBoomManager.addAnim(BoomMsgAnimBean().apply { + countDownUrl = dialogBean.countDownVapUrl.trim() + endUrl = dialogBean.endVapUrl.trim() + level = dialogBean.level + }) + upDateBoomExp() + } + } + + private fun showBoomInfoDialog() { + mBoomInfoDialog = RoomBoomInfoDialog().apply { + roomUid = AvRoomDataManager.get().roomUid + } + mBoomInfoDialog?.setOnDismissListener { + mBoomInfoDialog = null + } + + mBoomInfoDialog?.mCallBack = object : RoomBoomInfoDialog.CallBack { + override fun onCurrBoomInfo(boomInfo: BoomInfo) { + onExpPush(BoomMsgExpPushBean().apply { + speed = boomInfo.speed + level = boomInfo.level + pic = boomInfo.pic + },true) + } + + override fun onClick(type: Int, data: Any) { + mBoomInfoDialog?.dismiss() + onSendGiftBtnClick() + } + } + context?.let { + mBoomInfoDialog?.show(it) + } + } + + private fun upDateBoomExp(){ + AvRoomModel.get().getBoomInfo(AvRoomDataManager.get().roomUid) + .compose(bindToLifecycle()) + .doOnSuccess { + it.forEach { info-> + if (info.currLevel) { + mBoomExp = BoomMsgExpPushBean().apply { + level = info.level + speed = info.speed + pic = info.pic + } + boomLayout.setVis(true) + boomIcon.loadImage(info.pic) + boomProMax.post { + boomPro.setViewWH(width = (boomProMax.width * (info.speed.toFloat() / 100)).toInt(), isDP = false) + } + boomPro.scaleType = if (info.speed < 90) ImageView.ScaleType.MATRIX else ImageView.ScaleType.FIT_XY + } + } + } + .doOnError { + LogUtils.d(""+it?.message) + } + .subscribe() + } + + private fun checkBoomInfo() { + checkLuckyBagInfo() + "checkBoomInfo".doLog() + RoomBoomManager.clearQueue() + AvRoomModel.get().getRoomBoomInfo(AvRoomDataManager.get().roomUid) + .compose(bindToLifecycle()) + .doOnSuccess { boomInfo: RoomBoomInfo -> + + if (boomInfo.roomBoomSignVoList.isVerify()) { + boomInfo.roomBoomSignVoList.forEachIndexed { index, roomBoomInfoSign -> + RoomBoomManager.addAnim(BoomMsgAnimBean().apply { + countDownUrl = roomBoomInfoSign.countDownVapUrl + endUrl = roomBoomInfoSign.endVapUrl + level = roomBoomInfoSign.level + }) + } + } else { + return@doOnSuccess + } + + if (boomInfo.prizes.isVerify()) { + val toMap = boomInfo.prizes.groupBy { it.level }.toMap() + toMap.forEach { + RoomBoomManager.addAward(BoomMsgAwardList().apply { + list = it.value + }) + } + } + } + .doOnError { + LogUtils.d("") + } + .subscribe() + + + } + + //幸运礼包推送 + private fun onLuckyBagAdd(roomEvent: RoomEvent) { + luckyBagBtn?.postSafe(200) { + RoomHelperManager.onLuckyBagAdd(roomEvent,luckyBagBtn) + } + } + + private fun checkLuckyBagInfo() { + luckyBagBtn?.postSafe(200){ + "红包信息 = checkLuckyBagInfo = $isAdded".doLog() + RoomHelperManager.getLuckyBagInfo { + luckyBagBtn?.postSafe { + "红包信息 = isAdded = $isAdded".doLog() + if (isAdded) { + "红包信息 = $it".doLog() + if (it.redEnvelopeListVoList.isVerify()) { + luckyBagBtn.setNewData(it.redEnvelopeListVoList) + } + } + } + } + } + } + + + public fun initFloatBtnLayout() { + + floatBtnLayout = mView.findViewById(R.id.floatBtnLayout) + + floatBtnLayoutFold = floatBtnLayout.findViewById(R.id.floatBtnLayoutFold) + btnFold = floatBtnLayout.findViewById(R.id.btnFold) + + boomLayout = floatBtnLayout.findViewById(R.id.boomLayout) + boomIcon = floatBtnLayout.findViewById(R.id.boomIcon) + boomProMax = floatBtnLayout.findViewById(R.id.boomProMax) + boomPro = floatBtnLayout.findViewById(R.id.boomPro) + + luckyBagBtn = floatBtnLayout.findViewById(R.id.luckyBagBtn) + + ivTeamPk = floatBtnLayout.findViewById(R.id.iv_team_pk) + + btnIvConfigEntrance = floatBtnLayout.findViewById(R.id.iv_config_entrance) + + btnIvgame = floatBtnLayout.findViewById(R.id.iv_game) + + mIvQueuingMicro = floatBtnLayout.findViewById(R.id.iv_queuing_micro) + + boomIcon.post { + boomIcon.rotation = -30f + } + + boomLayout.setOnClickListener { + showBoomInfoDialog() + } + + + boomLayout.postSafe(3000){ + upDateBoomExp() + requestGamesData() + checkLuckyBagInfo() + } + + + if (AvRoomDataManager.get().isGameRoom) { + btnIvgame.setVis(false) + mIvQueuingMicro?.setVis(false) + } else if (AvRoomDataManager.get().isSingleRoom) { + ivTeamPk?.setVis(false) + mIvQueuingMicro?.setVis(false) + } + + btnFold.setVis((AvRoomDataManager.get().is19Room || AvRoomDataManager.get().is20Room|| AvRoomDataManager.get().isGameRoom)) + floatBtnLayoutFold.setViewWH( + height = if (btnFold.isVisible) 1 else ViewGroup.LayoutParams.WRAP_CONTENT, + isDP = false + ) + btnFold.tag = btnFold.isVisible + btnFold.click { + val tag = btnFold.tag + if (tag is Boolean) { + if (tag) { + btnFold.tag = false + btnFold.setImageResource(R.drawable.icon_fold_down) + floatBtnLayoutFold.setViewWH( + height = ViewGroup.LayoutParams.WRAP_CONTENT, + isDP = false + ) + } else { + btnFold.tag = true + btnFold.setImageResource(R.drawable.icon_fold_up) + floatBtnLayoutFold.setViewWH(height = 1, isDP = false) + } + } + } + + bottomView.post { + floatBtnLayout.setMargin(bottom = bottomView.height, isDP = false) + setComboViewVis(true) + } + + mIvQueuingMicro?.setOnClickListener(this) + btnIvgame?.setOnClickListener(this) + btnIvConfigEntrance?.setOnClickListener(this) + ivTeamPk?.setOnClickListener(this) + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/fragment/FakeSingleRoomBackFragment.kt b/app/src/main/java/com/chwl/app/avroom/fragment/FakeSingleRoomBackFragment.kt new file mode 100644 index 0000000..b4b655c --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/fragment/FakeSingleRoomBackFragment.kt @@ -0,0 +1,123 @@ +package com.chwl.app.avroom.fragment + +import android.annotation.SuppressLint +import com.chwl.app.R +import com.chwl.app.avroom.activity.AVRoomActivity +import com.chwl.app.base.BaseViewBindingFragment +import com.chwl.app.databinding.FragmentFakeSingleRoomBinding +import com.chwl.core.room.bean.RoomInfo +import com.chwl.core.room.event.SwitchRoomEvent +import com.chwl.core.room.model.AvRoomModel +import com.chwl.core.utils.CurrentTimeUtils +import com.chwl.core.utils.StringFormatUtils +import com.chwl.library.utils.ResUtil +import io.reactivex.Single +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode +import java.util.concurrent.TimeUnit + +class FakeSingleRoomBackFragment : BaseViewBindingFragment() { + + private var preRoomInfo: RoomInfo? = null + private var needJump = false + private var lastRequestTime = 0L + private val minRequestTime = 60 * 1000 + private val bgPicture = arrayOf("") + private var requesting = false + private var initBg = false + private var disposable: Disposable? = null + + private val cacheRoomInfoList = ArrayList() + + override fun init() { + EventBus.getDefault().register(this) + } + + @SuppressLint("CheckResult") + fun requestPreRoomInfo() { + if (cacheRoomInfoList.isEmpty()) { + (activity as AVRoomActivity).setCurrentItem(1) + return + } + if (!initBg) { + AVRoomActivity.setBackBg( + mContext, + cacheRoomInfoList[0], + binding.svgaImageViewBg, + bgPicture + ) + initBg = true + } else if (!binding.svgaImageViewBg.isAnimating) { + binding.svgaImageViewBg.startAnimation() + } + if (requesting || CurrentTimeUtils.getCurrentTime() - lastRequestTime < minRequestTime) { + return + } + preRoomInfo = null + lastRequestTime = CurrentTimeUtils.getCurrentTime() + requesting = true + AvRoomModel.get() + .requestRoomInfo(cacheRoomInfoList[0].uid.toString()) + .subscribe({ + if (needJump) { + jumpRoom(it) + } else { + preRoomInfo = it + if (!StringFormatUtils.isBlank(it.backPic)) { + AVRoomActivity.setBackBg(mContext, it, binding.svgaImageViewBg, bgPicture) + } + } + }, { + toast(ResUtil.getString(R.string.avroom_fragment_fakesingleroombackfragment_01)) + reSet() + (activity as AVRoomActivity).setCurrentItem(1) + }) + } + + fun tryJumpRoom() { + preRoomInfo?.let { + jumpRoom(it) + } ?: run { + needJump = true + } + } + + private fun jumpRoom(roomInfo: RoomInfo) { + cacheRoomInfoList.removeAt(0) + AVRoomActivity.start(mContext, roomInfo) + reSet() + } + + + private fun reSet() { + initBg = false + preRoomInfo = null + lastRequestTime = 0 + needJump = false + requesting = false + disposable?.dispose() + disposable = Single.timer(10, TimeUnit.SECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ + binding.svgaImageViewBg.stopAnimation() + }, { + it.printStackTrace() + }) + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onSwitchRoomEvent(event: SwitchRoomEvent) { + cacheRoomInfoList.add(0, event.roomInfo) + } + + override fun onDestroyView() { + EventBus.getDefault().unregister(this) + initBg = false + disposable?.dispose() + binding.svgaImageViewBg.clear() + super.onDestroyView() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/fragment/FakeSingleRoomFragment.kt b/app/src/main/java/com/chwl/app/avroom/fragment/FakeSingleRoomFragment.kt new file mode 100644 index 0000000..47d3a4f --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/fragment/FakeSingleRoomFragment.kt @@ -0,0 +1,119 @@ +package com.chwl.app.avroom.fragment + +import android.annotation.SuppressLint +import com.opensource.svgaplayer.SVGADrawable +import com.opensource.svgaplayer.SVGAImageView +import com.opensource.svgaplayer.SVGAParser +import com.opensource.svgaplayer.SVGAVideoEntity +import com.chwl.app.R +import com.chwl.app.avroom.activity.AVRoomActivity +import com.chwl.app.base.BaseViewBindingFragment +import com.chwl.app.databinding.FragmentFakeSingleRoomBinding +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.room.bean.RoomInfo +import com.chwl.core.room.event.SwitchRoomEvent +import com.chwl.core.room.model.AvRoomModel +import com.chwl.core.utils.CurrentTimeUtils +import com.chwl.core.utils.StringFormatUtils +import io.reactivex.Single +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import org.greenrobot.eventbus.EventBus +import java.util.concurrent.TimeUnit + +class FakeSingleRoomFragment : BaseViewBindingFragment() { + + private var preRoomInfo: RoomInfo? = null + private var needJump = false + private var lastRequestTime = 0L + private val minRequestTime = 60 * 1000 + private val bgPicture = arrayOf("") + private var requesting = false + private var initBg = false + private var disposable: Disposable? = null + + override fun init() { + } + + @SuppressLint("CheckResult") + fun requestPreRoomInfo() { + if (!initBg) { + playSvgaBg(binding.svgaImageViewBg, "svga/single_back.svga") + initBg = true + } else if (!binding.svgaImageViewBg.isAnimating) { + binding.svgaImageViewBg.startAnimation() + } + if (requesting || CurrentTimeUtils.getCurrentTime() - lastRequestTime < minRequestTime) { + return + } + preRoomInfo = null + lastRequestTime = CurrentTimeUtils.getCurrentTime() + requesting = true + AvRoomModel.get() + .nextSingleRoomInfo + .subscribe({ + if (needJump) { + jumpRoom(it) + } else { + preRoomInfo = it + if (!StringFormatUtils.isBlank(it.backPic)) { + AVRoomActivity.setBackBg(mContext, it, binding.svgaImageViewBg, bgPicture) + } + } + }, { + toast(getString(R.string.room_down_to_the_bottom)) + reSet() + (activity as AVRoomActivity).setCurrentItem(1) + }) + } + + fun tryJumpRoom() { + preRoomInfo?.let { + jumpRoom(it) + } ?: run { + needJump = true + } + } + + private fun jumpRoom(roomInfo: RoomInfo) { + EventBus.getDefault().post(SwitchRoomEvent(AvRoomDataManager.get().mCurrentRoomInfo)) + AVRoomActivity.start(mContext, roomInfo) + reSet() + } + + private fun reSet() { + preRoomInfo = null + lastRequestTime = 0 + needJump = false + requesting = false + disposable?.dispose() + disposable = Single.timer(10, TimeUnit.SECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ + binding.svgaImageViewBg.stopAnimation() + }, { + it.printStackTrace() + }) + } + + private fun playSvgaBg(svgaRoomBg: SVGAImageView, assets: String) { + SVGAParser.shareParser().decodeFromAssets(assets, object : SVGAParser.ParseCompletion { + override fun onComplete(videoItem: SVGAVideoEntity) { + val drawable = SVGADrawable(videoItem) + svgaRoomBg.setImageDrawable(drawable) + svgaRoomBg.startAnimation() + } + + override fun onError() { + } + + }, null) + } + + override fun onDestroyView() { + initBg = false + disposable?.dispose() + binding.svgaImageViewBg.clear() + super.onDestroyView() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/fragment/GameRoomFragment.kt b/app/src/main/java/com/chwl/app/avroom/fragment/GameRoomFragment.kt new file mode 100644 index 0000000..123adc7 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/fragment/GameRoomFragment.kt @@ -0,0 +1,278 @@ +package com.chwl.app.avroom.fragment + +import android.annotation.SuppressLint +import android.os.Bundle +import android.view.MotionEvent +import android.view.View +import android.view.View.OnTouchListener +import android.view.ViewGroup +import androidx.core.view.isVisible +import androidx.databinding.DataBindingUtil +import androidx.recyclerview.widget.RecyclerView +import com.chwl.app.R +import com.chwl.app.avroom.adapter.GameMicroViewAdapter +import com.chwl.app.avroom.adapter.GameMiniMicroViewAdapter +import com.chwl.app.avroom.adapter.OnMicroItemClickListener +import com.chwl.app.avroom.game.GameDelegate +import com.chwl.app.avroom.game.OnGameStatusChangeListener +import com.chwl.app.avroom.headline.RoomHeadlineWidget +import com.chwl.app.avroom.online.RoomOnlineWidget +import com.chwl.app.avroom.presenter.GameRoomPresenter +import com.chwl.app.avroom.rank.RoomRankNumberWidget +import com.chwl.app.avroom.view.IGameRoomView +import com.chwl.app.databinding.FragmentGameRoomBinding +import com.chwl.app.home.helper.OpenRoomHelper +import com.chwl.app.ui.webview.DialogWebViewActivity +import com.chwl.app.ui.widget.GiftDialog.OnGiftDialogBtnClickListener +import com.chwl.core.UriProvider +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.music.model.PlayerModel +import com.chwl.core.room.bean.RoomInfo +import com.chwl.core.room.event.FinishAvRoomEvent +import com.chwl.core.sud.model.GameViewInfoModel +import com.chwl.library.base.factory.CreatePresenter +import com.chwl.library.utils.SingleToastUtil +import com.netease.nim.uikit.common.util.sys.ScreenUtil +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode + +/** + * 轰趴房间 + * + * @author chenran + * @date 2017/7/26 + */ +@CreatePresenter(GameRoomPresenter::class) +class GameRoomFragment : BaseRoomFragment(), + View.OnClickListener, OnGiftDialogBtnClickListener, IGameRoomView, OnMicroItemClickListener, + OnGameStatusChangeListener { + + companion object { + @JvmStatic + fun newInstance(): GameRoomFragment { + val roomFragment = GameRoomFragment() + val bundle = Bundle() + roomFragment.arguments = bundle + return roomFragment + } + } + + private lateinit var gameBinding: FragmentGameRoomBinding + private lateinit var gameDelegate: GameDelegate + private var isShowMiniMic = false + + override fun getRootLayoutId(): Int { + return R.layout.fragment_game_room + } + + override fun onFindViews() { + super.onFindViews() + gameBinding = DataBindingUtil.bind(mView)!! + gameBinding.lifecycleOwner = this + gameBinding.click = this + gameBinding.ktvModel = false + gameDelegate = GameDelegate( + requireActivity(), + gameBinding.flGameContainer, + AvRoomDataManager.get().mCurrentRoomInfo?.mgId + ) + gameDelegate.setOnGameStatusChangeListener(this) + } + + @SuppressLint("CheckResult") + override fun initiate() { + gameBinding.microView.bindAdapter(GameMicroViewAdapter(context)) + resetGameViewRect() + super.initiate() + //游戏模式暂时不需要这个 + PlayerModel.get().stop() + gameBinding.roomInfo = AvRoomDataManager.get().mCurrentRoomInfo + gameBinding.tvShowMiniMic.setOnClickListener { showMiniMic() } + gameBinding.ivShowMic.setOnClickListener { showMic() } + gameBinding.headlineWidget.setOnClickListener { + switchMessageLayoutHeight() + } + } + + @SuppressLint("ClickableViewAccessibility") + override fun initMessageView() { + super.initMessageView() + messageView.messageListView?.let { + setMessagePagerAutoHeight(it) + } + } + + override fun onClick(v: View) { + super.onClick(v) + when (v.id) { + R.id.iv_back_room -> { + if (AvRoomDataManager.get().isGamePlaying) { + SingleToastUtil.showToast(getString(R.string.avroom_fragment_homepartyfragment_03)) + return + } + dialogManager.showOkCancelDialog( + getString(R.string.room_switch_standard_room_tips) + ) { + var type = AvRoomDataManager.get().mCurrentRoomInfo?.oldType + if (type == null || type <= 0) { + type = RoomInfo.ROOMTYPE_HOME_PARTY + } + OpenRoomHelper.updateRoomInfo( + baseActivity, + AvRoomDataManager.get().mCurrentRoomInfo, + type, + 0, + false + ) + } + } + R.id.layout_hour_rank -> { + DialogWebViewActivity.start( + mContext, + UriProvider.getRoomHourRankUrl(AvRoomDataManager.get().roomUid) + ) + } + } + } + + @SuppressLint("ClickableViewAccessibility") + private fun setMessagePagerAutoHeight(recyclerView: RecyclerView) { + recyclerView.setOnTouchListener(OnTouchListener { v: View?, event: MotionEvent -> + if (recyclerView.scrollState == RecyclerView.SCROLL_STATE_IDLE + && event.action == MotionEvent.ACTION_UP + ) { + switchMessageLayoutHeight() + } + false + }) + } + + private fun switchMessageLayoutHeight() { + val view = gameBinding.layoutMessage + val layoutParams: ViewGroup.LayoutParams = view.layoutParams + val bigHeight = ScreenUtil.dip2px(200f) + val littleHeight = ScreenUtil.dip2px(80f) + layoutParams.height = + if (layoutParams.height == littleHeight) bigHeight else littleHeight + view.layoutParams = layoutParams + } + + private fun showMiniMic() { + if (isShowMiniMic) return + isShowMiniMic = true + gameBinding.microView.bindAdapter(GameMiniMicroViewAdapter(context).apply { + setOnClick { showMic() } + }) + gameBinding.tvShowMiniMic.isVisible = false + gameBinding.microView.postDelayed({ + gameBinding.ivShowMic.isVisible = true + gameBinding.llMicView.setBackgroundResource(R.drawable.bg_mini_mic_entrance) + }, 100) + } + + private fun showMic() { + if (!isShowMiniMic) return + isShowMiniMic = false + gameBinding.microView.bindAdapter(GameMicroViewAdapter(context)) + gameBinding.tvShowMiniMic.isVisible = true + gameBinding.llMicView.background = null + gameBinding.ivShowMic.isVisible = false + } + + override fun onSetListener() { + super.onSetListener() + bottomView.setBottomViewListener(BaseRoomBottomViewWrapper()) + } + + override fun updateView() { + super.updateView() + gameDelegate.updateGame(AvRoomDataManager.get().mCurrentRoomInfo?.mgId) + gameBinding.roomInfo = AvRoomDataManager.get().mCurrentRoomInfo +// if (isSixMic()) { +// gameBinding.tvShowMiniMic.isVisible = !isShowMiniMic +// gameBinding.ivShowMic.isVisible = isShowMiniMic +// } else { +// showMic() +// gameBinding.tvShowMiniMic.isInvisible = true +// gameBinding.ivShowMic.isVisible = false +// } + gameBinding.microView.adapter.notifyDataSetChanged() + if (AvRoomDataManager.get().mCurrentRoomInfo?.isPermitRoom == 1) { + gameBinding.layoutHourRank.visibility = View.VISIBLE + } else { + gameBinding.layoutHourRank.visibility = View.GONE + } + } + + private fun resetGameViewRect(){ + gameBinding.vGameRect.post { + gameDelegate.gameViewRect = GameViewInfoModel.GameViewRectModel().apply { + top = gameBinding.vGameRect.top + bottom = gameBinding.layoutRoot.height - gameBinding.vGameRect.bottom + } + } + } + + override fun onGameStart() { + if (isSixMic()) { +// showMiniMic() + } + } + + override fun onGameEnd() { + if (isSixMic()) { + showMic() + } + } + + private fun isSixMic(): Boolean { + return AvRoomDataManager.get().mgMicNum == AvRoomDataManager.GAME_DEF_MIC_COUNT + } + + override fun onSendMsgSuccess(msg: String?) { + super.onSendMsgSuccess(msg) + msg?.let { + if (AvRoomDataManager.get().isSelfGamePlaying) { + gameDelegate.hitTheMark(msg) + } + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onFinishAvRoomEvent(event: FinishAvRoomEvent) { + gameDelegate.exitGame() + } + + override fun onStart() { + super.onStart() + gameDelegate.onStart() + } + + override fun onResume() { + super.onResume() + gameDelegate.onResume() + } + + + override fun onPause() { + super.onPause() + gameDelegate.onPause() + } + + override fun onStop() { + super.onStop() + gameDelegate.onStop() + } + + override fun onDestroy() { + gameDelegate.onDestroy() + super.onDestroy() + } + + override fun initWidget() { + super.initWidget() + registerWidget(RoomOnlineWidget::class.java.simpleName, gameBinding.onlineWidget) + registerWidget(RoomHeadlineWidget::class.java.simpleName, gameBinding.headlineWidget) + registerWidget(RoomRankNumberWidget::class.java.simpleName, gameBinding.rankNumberWidget) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/fragment/HomePartyFragment.java b/app/src/main/java/com/chwl/app/avroom/fragment/HomePartyFragment.java new file mode 100644 index 0000000..31a112f --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/fragment/HomePartyFragment.java @@ -0,0 +1,928 @@ +package com.chwl.app.avroom.fragment; + +import android.annotation.SuppressLint; +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.view.Gravity; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewStub; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.Nullable; +import androidx.databinding.DataBindingUtil; +import androidx.fragment.app.DialogFragment; +import androidx.fragment.app.Fragment; + +import com.chwl.app.R; +import com.chwl.app.avroom.activity.AVRoomActivity; +import com.chwl.app.avroom.activity.RoomTitleEditActivity; +import com.chwl.app.avroom.dialog.ExitRoomPopupWindow; +import com.chwl.app.avroom.dialog.RoomBgSetDialog; +import com.chwl.app.avroom.widget.GiftV2View; +import com.chwl.app.avroom.widget.RoomEffectView; +import com.chwl.app.base.BaseFragment; +import com.chwl.app.databinding.FragmentChatroomGameMainBinding; +import com.chwl.app.notify.GlobalNotifyManager; +import com.chwl.app.ui.utils.ImageLoadKt; +import com.chwl.app.ui.utils.ImageLoadUtilsV2; +import com.chwl.app.ui.widget.BonsellaJoinAttackButtonView; +import com.chwl.app.ui.widget.GiftDialog; +import com.chwl.app.ui.widget.UserInfoDialog; +import com.chwl.app.utils.RegexUtil; +import com.chwl.app.utils.RoomBoomManager; +import com.chwl.app.utils.RoomNotifyDialogManager; +import com.chwl.app.utils.ShareManager; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.gift.bean.BravoGiftMsgNotifyBean; +import com.chwl.core.gift.bean.BravoGiftRewardBean; +import com.chwl.core.gift.bean.CpMsgBean; +import com.chwl.core.gift.bean.GiftMultiReceiverInfo; +import com.chwl.core.gift.bean.GiftReceiveInfo; +import com.chwl.core.gift.bean.LuckyBagGifts; +import com.chwl.core.gift.bean.MsgSuperLuckyGift; +import com.chwl.core.gift.bean.MultiGiftReceiveInfo; +import com.chwl.core.gift.bean.RoomBgChangeBean; +import com.chwl.core.gift.bean.RoomLevelChangeBean; +import com.chwl.core.gift.bean.RoomNotifyDialogBean; +import com.chwl.core.gift.event.GiftComboEvent; +import com.chwl.core.gift.toolbox.GiftToolbox; +import com.chwl.core.home.event.FollowRoomEvent; +import com.chwl.core.home.model.CollectionRoomModel; +import com.chwl.core.im.custom.bean.CustomAttachment; +import com.chwl.core.im.custom.bean.RoomInfoAttachment; +import com.chwl.core.magic.bean.MagicReceivedInfo; +import com.chwl.core.magic.bean.MultiMagicReceivedInfo; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.manager.IMNetEaseManager; +import com.chwl.core.manager.RoomEvent; +import com.chwl.core.noble.bean.AllServiceGiftProtocol; +import com.chwl.core.praise.PraiseModel; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.core.room.queuing_mic.event.HasAnimationEffect; +import com.chwl.core.super_admin.util.SuperAdminUtil; +import com.chwl.core.user.UserModel; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.core.utils.ComboUtil; +import com.chwl.core.utils.CoreLogger; +import com.chwl.library.common.util.OtherExtKt; +import com.chwl.library.utils.JavaUtil; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; +import com.example.lib_utils.UiUtils; +import com.netease.nim.uikit.common.util.string.StringUtil; +import com.netease.nimlib.sdk.chatroom.ChatRoomMessageBuilder; +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage; +import com.netease.nimlib.sdk.msg.attachment.MsgAttachment; +import com.opensource.svgaplayer.SVGAImageView; +import com.trello.rxlifecycle3.android.FragmentEvent; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.lang.reflect.Field; +import java.util.List; + +import io.reactivex.SingleObserver; +import io.reactivex.disposables.Disposable; +import kotlin.jvm.functions.Function0; + +/** + * 轰趴房 + * Created by 2016/9/22. + * + * @author Administrator + */ +public class HomePartyFragment extends BaseFragment implements View.OnClickListener { + + private Fragment roomFragment; + + private TextView roomTitle; + private TextView roomId; + private ImageView ivFollowRoom; +// private AppCompatImageView mIvGoodNumber; + + private ImageView roomMore; + // private ImageView ivRoomShare; + private GiftV2View giftView; + private ViewStub mVsGift2View; + private RoomEffectView mRoomEffectView; + + private SVGAImageView svgaRoomBg; + private String[] bgPicture = new String[]{""}; + + private UserInfo mUserInfo; + public FragmentChatroomGameMainBinding gameMainBinding; + + //收藏房间 + private String FOLLOW_ROOM_TYPE = ""; + + + public static HomePartyFragment newInstance() { + HomePartyFragment homePartyFragment = new HomePartyFragment(); + Bundle bundle = new Bundle(); + homePartyFragment.setArguments(bundle); + return homePartyFragment; + } + + @Override + public void onNewIntent(Intent intent) { + super.onNewIntent(intent); + // clear views + roomTitle.setText(""); + gameMainBinding.ivRoomCover.setImageResource(R.drawable.default_cover); + setRoomId(0, 0); + updateOnlineNumberView(0); + if (roomFragment instanceof HomePartyRoomFragment) { + ((HomePartyRoomFragment) roomFragment).onNewIntent(intent); + } + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + EventBus.getDefault().register(this); + } + + private void setRoomId(long id, int onlineNumber) { + String htmlText = "ID:" + id; + roomId.setText(htmlText); + roomId.setOnLongClickListener(view -> { + try { + if (id > 0L) { + ClipboardManager cm = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE); + cm.setPrimaryClip(ClipData.newPlainText("text", String.valueOf(id))); + toast(getString(R.string.have_copy)); + } + } catch (Exception e) { + CoreLogger.info("copyText", e.toString()); + toast(e.toString()); + } + return true; + }); + } + + @Override + public int getRootLayoutId() { + return R.layout.fragment_chatroom_game_main; + } + + @Override + public void onFindViews() { + gameMainBinding = DataBindingUtil.bind(mView); + roomTitle = mView.findViewById(R.id.room_title); + setupRoomTitleMarquee(); + roomMore = mView.findViewById(R.id.room_more); +// ivRoomShare = mView.findViewById(R.id.iv_room_share); +// if (SuperAdminUtil.isSuperAdmin()) { +// ivRoomShare.setVisibility(View.INVISIBLE); +// } else { +// ivRoomShare.setVisibility(View.VISIBLE); +// } + roomId = mView.findViewById(R.id.room_id); + mVsGift2View = mView.findViewById(R.id.vs_gift_view); +// mIvGoodNumber = mView.findViewById(R.id.iv_good_number); + ivFollowRoom = mView.findViewById(R.id.iv_follow_room); + svgaRoomBg = mView.findViewById(R.id.svga_image_view_bg); + mRoomEffectView = mView.findViewById(R.id.room_effect_view); + } + + /** + * 添加跑马灯 + * 以及反射一些参数影响跑马灯 + */ + private void setupRoomTitleMarquee() { + try { + ViewConfiguration configuration = ViewConfiguration.get(getContext()); + Class claz = configuration.getClass(); + Field field = claz.getDeclaredField("mFadingMarqueeEnabled"); + field.setAccessible(true); + field.set(configuration, true); + + } catch (NoSuchFieldException e) { + e.printStackTrace(); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + roomTitle.setSelected(true); + } + + @Override + public void onSetListener() { + gameMainBinding.ivRoomNotice.setOnClickListener(this); + roomMore.setOnClickListener(this); + gameMainBinding.ivShareRoom.setOnClickListener(this); + ivFollowRoom.setOnClickListener(this); +// ivRoomShare.setOnClickListener(this); + gameMainBinding.ivBack.setOnClickListener(this); + + mRoomEffectView.setOnPlayAnimCallback(new Function0() { + @Override + public Boolean invoke() { + return getIsAnim(); + } + }); + } + + @SuppressLint("CheckResult") + @Override + public void initiate() { + RoomBoomManager.INSTANCE.init(gameMainBinding.roomAnim); + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) return; + if (!AvRoomDataManager.get().haveSelfChange) { + AvRoomDataManager.get().mIsNeedGiftEffect = AvRoomDataManager.get().mCurrentRoomInfo.isHasAnimationEffect(); + } + } + + public void setRoomBg(RoomInfo roomInfo) { + if (svgaRoomBg == null) return; + AVRoomActivity.setBackBg(mContext, roomInfo, svgaRoomBg, bgPicture); + OtherExtKt.setVis(gameMainBinding.roomLevelIcon,OtherExtKt.isVerify(roomInfo.getRoomLevelIcon()),false); + ImageLoadKt.loadImage(gameMainBinding.roomLevelIcon,roomInfo.getRoomLevelIcon()); + } + + + @SuppressLint("CheckResult") + @Override + public void onResume() { + super.onResume(); + updateView(AvRoomDataManager.get().mCurrentRoomInfo); + IMNetEaseManager.get().getChatRoomEventObservable() + .compose(bindToLifecycle()) + .doOnNext(roomEvent -> { + OtherExtKt.postSafe(gameMainBinding.getRoot(), () -> { + try { + if (roomEvent == null) return null; + int event = roomEvent.getEvent(); +// OtherExtKt.doLog("房间消息 接收到房间消息 - "+event + " == 34 ?"); + switch (event) { + case RoomEvent.ENTER_ROOM: + try { + if (AvRoomDataManager.get().mCurrentRoomInfo != null) { + updateOnlineNumberView(AvRoomDataManager.get().mCurrentRoomInfo.onlineNum); + } + addTipMsg(); + } catch (Exception e) { + OtherExtKt.doLog("房间消息 接收到房间消息=1 报错 - "+e.getMessage()); + } + case RoomEvent.ROOM_INFO_UPDATE: + updateView(AvRoomDataManager.get().mCurrentRoomInfo); + break; + case RoomEvent.RECEIVE_NORMALE_GIFT://普通 + onReceiveGiftMsg(roomEvent.getGiftReceiveInfo()); + break; + case RoomEvent.RECEIVE_NORMALE_GIFT_ALL_SERVICE:// 全服普通 + onReceiveGiftMsgAllService(roomEvent.getGiftReceiveInfo()); + case RoomEvent.RECEIVE_NORMALE_GIFT_ALL_SERVICE_NOTIFY:// 全服飘屏 + onReceiveGiftMsgAllServiceNotify(roomEvent.getAnyData()); + break; + case RoomEvent.RECEIVE_MUTLT_NORMALEI_GIFT://普通多人 + onReceiveMultiGiftMsg(roomEvent.getGiftMultiReceiverInfo()); + break; + case RoomEvent.RECEIVE_ALL_MIC__NORMALEI_GIFT://普通全麦 + onReceiveAllMicGiftMsg(roomEvent.getMultiGiftReceiveInfo()); + break; + //福袋礼物 + case RoomEvent.RECEIVE_LUCKY_GIFT: + case RoomEvent.RECEIVE_MULTI_LUCKY_GIFT: + case RoomEvent.RECEIVE_ALL_MIC_LUCKY_GIFT: + onReceiveLuckyGiftToMultiMsg(roomEvent.getLuckygiftMultiReceiverInfo()); + break; + case RoomEvent.RECEIVED_SINGLE_MAGIC: + onReceiveMagicMsg(roomEvent.getMagicReceivedInfo()); + break; + case RoomEvent.RECEIVED_ALL_MIC_MAGIC: + onReceiveMultiMagicMsg(roomEvent.getMultiMagicReceivedInfo()); + break; + case RoomEvent.FANS_TEAM_JOIN: + onReceiveFansTeamJoinMsg(roomEvent.getChatRoomMessage()); + break; + case RoomEvent.MSG_SUPER_LUCKY_GIFT: + onLuckyGiftMsg(roomEvent); + break; + case RoomEvent.MSG_CP_ABOUT: + onCpAboutMsg(roomEvent); + break; + case RoomEvent.MSG_ROOM_BG_CHANGE: + onRoomBgChange(roomEvent); + break; + case RoomEvent.MSG_ROOM_LEVEL_CHANGE: + onRoomLevelChange(roomEvent); + break; + case RoomEvent.MSG_SUPER_BRAVO_NOTIFY: + onBravoNotify(roomEvent); + break; + case RoomEvent.MSG_SUPER_BRAVO_REWARD: + onBravoReward(roomEvent); + break; + default: + break; + } + } catch (Exception e) { + OtherExtKt.doLog("房间消息 报错 "+roomEvent.getEvent()+" "+e.getMessage()); + } + + return null; + }); + + }) + .subscribe(); + } + + + /** + * 获取礼物飘屏是否展示 + * + * @return + */ + private boolean getIsAnim() { + if (giftView != null) { + return giftView.getIsPlayAnim(); + } + return false; + } + + /** + * 获取玩法飘屏是否展示 + */ + private boolean getIsPlayAnim() { + return mRoomEffectView.getIsPlayAnim(); + } + + private void onReceiveLuckyGiftToMultiMsg(LuckyBagGifts giftMultiReceiverInfo) { + if (giftMultiReceiverInfo == null || !isResumed()) return; + if (giftView == null) { + giftView = (GiftV2View) mVsGift2View.inflate(); + } + giftView.onReceiveLuckyGiftToMultiMsg(giftMultiReceiverInfo); + } + + /** + * 进入房间时的提示信息 + */ + private void addTipMsg() { + if (AvRoomDataManager.get().mCurrentRoomInfo != null && AvRoomDataManager.get().mCurrentRoomInfo.isCloseScreen()) { + MsgAttachment attachment = new RoomInfoAttachment(CustomAttachment.CUSTOM_MSG_UPDATE_ROOM_INFO, + CustomAttachment.CUSTOM_MSG_UPDATE_ROOM_INFO_CLOSE_SCREEN); + ChatRoomMessage closeMsg = ChatRoomMessageBuilder.createChatRoomCustomMessage( + String.valueOf(AvRoomDataManager.get().getRoomId()), attachment); + closeMsg.setContent(ResUtil.getString(R.string.avroom_fragment_homepartyfragment_06)); + IMNetEaseManager.get().addCloseScreenMessages(closeMsg); + } else if (AvRoomDataManager.get().mCurrentRoomInfo != null && !AvRoomDataManager.get().mCurrentRoomInfo.isHasAnimationEffect()) { + ChatRoomMessage tipMessage = ChatRoomMessageBuilder.createTipMessage(""); + tipMessage.setContent(ResUtil.getString(R.string.avroom_fragment_homepartyfragment_07)); + IMNetEaseManager.get().addCloseScreenMessages(tipMessage); + } + } + + private void setIdOnlineData() { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) return; + + UserModel.get().getUserInfo(roomInfo.getUid()).subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) { + mCompositeDisposable.add(d); + } + + @Override + public void onSuccess(UserInfo userInfo) { + mUserInfo = userInfo; + setRoomId(mUserInfo.getErbanNo(), roomInfo.onlineNum); +// mIvGoodNumber.setVisibility(mUserInfo.isHasPrettyErbanNo() ? View.VISIBLE : View.GONE); + } + + @Override + public void onError(Throwable e) { + setRoomId(0, roomInfo.onlineNum); +// mIvGoodNumber.setVisibility(View.GONE); + } + }); + + gameMainBinding.setRoomInfo(roomInfo); + + gameMainBinding.roomTitleMax.post(() -> { + if (gameMainBinding.roomTitleIcons.isAttachedToWindow()) { + gameMainBinding.roomTitleIcons.post(() -> { + if (gameMainBinding.roomTitleIcons.isAttachedToWindow() + && gameMainBinding.roomTitleIcons.isAttachedToWindow() + && gameMainBinding.roomTitle.isAttachedToWindow()) { + int roomTitleIconsWidth = gameMainBinding.roomTitleIcons.getWidth(); + int roomTitleMaxWidth = gameMainBinding.roomTitleMax.getWidth(); + gameMainBinding.roomTitle.setMaxWidth(roomTitleMaxWidth-roomTitleIconsWidth); + } + }); + } + }); + + } + + @SuppressLint("CheckResult") + public void updateView(RoomInfo currentRoomInfo) { + if (currentRoomInfo != null) { + + Fragment tempFragment = roomFragment; + switch (currentRoomInfo.getType()) { + case RoomInfo.ROOMTYPE_GAME: + if (!(tempFragment instanceof GameRoomFragment)) { + tempFragment = GameRoomFragment.newInstance(); + } + break; + case RoomInfo.ROOM_TYPE_SINGLE: + if (!(tempFragment instanceof SingleRoomFragment)) { + tempFragment = SingleRoomFragment.newInstance(); + } + break; + case RoomInfo.ROOMTYPE_PARTY: + if (!(tempFragment instanceof PartyRoomFragment)) { + tempFragment = PartyRoomFragment.Companion.newInstance(); + } + break; + case RoomInfo.ROOMTYPE_REVELRY: + if (!(tempFragment instanceof RevelryRoomFragment)) { + tempFragment = RevelryRoomFragment.Companion.newInstance(); + } + break; + case RoomInfo.ROOMTYPE_19_ROOM: + if (!(tempFragment instanceof Room19Fragment)) { + tempFragment = Room19Fragment.Companion.newInstance(); + } + break; + case RoomInfo.ROOMTYPE_20_ROOM: + if (!(tempFragment instanceof Room20Fragment)) { + tempFragment = Room20Fragment.Companion.newInstance(); + } + break; + default: + if (tempFragment == null || !(tempFragment.getClass().getSimpleName().equals(HomePartyRoomFragment.class.getSimpleName()))) { + tempFragment = HomePartyRoomFragment.newInstance(); + } + break; + } + if (tempFragment != roomFragment) { + roomFragment = tempFragment; + getChildFragmentManager() + .beginTransaction() + .replace(R.id.container, roomFragment) + .commitAllowingStateLoss(); + } + setRoomBg(currentRoomInfo); + gameMainBinding.setRoomInfo(currentRoomInfo); + updateHasAnimationEffect(); + roomTitle.setText(RegexUtil.getPrintableString(currentRoomInfo.getTitle())); + ImageLoadUtilsV2.loadImage(gameMainBinding.ivRoomCover, currentRoomInfo.getAvatar()); + if (!StringUtil.isEmpty(currentRoomInfo.getRoomPwd())) { + roomTitle.setCompoundDrawablesWithIntrinsicBounds(null, null, + getResources().getDrawable(R.drawable.icon_room_lock), null); + } else { + roomTitle.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null); + } + + + ivFollowRoom.setVisibility(AvRoomDataManager.get().isRoomOwner() ? View.GONE : View.VISIBLE); + FOLLOW_ROOM_TYPE = AvRoomDataManager.get().isRoomFans ? "2" : "1"; + ivFollowRoom.setImageResource(AvRoomDataManager.get().isRoomFans ? R.drawable.room_ic_collect_yes : R.drawable.room_ic_collect_no); + + setIdOnlineData(); + + if (AvRoomDataManager.get().getRoomType() != RoomInfo.ROOMTYPE_GAME) { + gameMainBinding.ivRoomNotice.setVisibility(View.VISIBLE); + } else { + gameMainBinding.ivRoomNotice.setVisibility(View.GONE); + } + } + } + + public void updateHasAnimationEffect() { + if (!AvRoomDataManager.get().haveSelfChange && AvRoomDataManager.get().mCurrentRoomInfo != null) { + AvRoomDataManager.get().mIsNeedGiftEffect = AvRoomDataManager.get().mCurrentRoomInfo.isHasAnimationEffect(); + } + gameMainBinding.setHasAnimationEffect(AvRoomDataManager.get().mIsNeedGiftEffect); + } + + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.iv_room_notice: + showRoomIntroduction(AvRoomDataManager.get().isRoomOwner() || AvRoomDataManager.get().isRoomAdmin()); + break; + case R.id.room_more: + int gravity = Gravity.END; + if (UiUtils.INSTANCE.isRtl(requireContext())) { + gravity = Gravity.START; + } + ExitRoomPopupWindow.newInstance((AVRoomActivity) requireActivity()) + .showAtLocation(gameMainBinding.getRoot(), gravity, 0, 0); + break; + case R.id.iv_follow_room: + followRoom(); + break; + case R.id.iv_share_room: + ShareRoom(); + break; + case R.id.iv_back: + if (getActivity() instanceof AVRoomActivity) { + ((AVRoomActivity) getActivity()).onBackPressed(); + } + break; + default: + } + } + + public void dismissSendRedPackageDialog() { + if (roomFragment instanceof BaseRoomFragment) { + ((BaseRoomFragment) roomFragment).clearDialog(); + } + } + + /** + * 收藏房间 + */ + @SuppressLint("CheckResult") + private void followRoom() { + RoomInfo currentRoomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (currentRoomInfo == null) { + return; + } + CollectionRoomModel.get().followRoom(FOLLOW_ROOM_TYPE, currentRoomInfo.getUid()) + .compose(bindUntilEvent(FragmentEvent.DESTROY)) + .doOnError(throwable -> { + toast(throwable.getMessage()); + }) + .subscribe(s -> { + AvRoomDataManager.get().isRoomFans = !AvRoomDataManager.get().isRoomFans; + FOLLOW_ROOM_TYPE = AvRoomDataManager.get().isRoomFans ? "2" : "1"; + ivFollowRoom.setImageResource(AvRoomDataManager.get().isRoomFans ? R.drawable.room_ic_collect_yes : R.drawable.room_ic_collect_no); + if (AvRoomDataManager.get().isRoomFans) { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_fragment_homepartyfragment_010)); + PraiseModel.get().setFollowRoomSuccessRoomTip(currentRoomInfo.getUid()); + } + }); + + } + /** + * 分享房间 + */ + @SuppressLint("CheckResult") + private void ShareRoom() { + RoomInfo currentRoomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (currentRoomInfo == null) { + return; + } + + ShareManager.INSTANCE.shareRoomGen(this, AvRoomDataManager.get().getRoomUid(), link -> { + OtherExtKt.doLog(" 获取到的分享链接为 = "+link); + ClipboardManager cm = (ClipboardManager) mContext.getApplicationContext().getSystemService(Context.CLIPBOARD_SERVICE); + cm.setPrimaryClip(ClipData.newPlainText("text", link)); + OtherExtKt.doToast(R.string.copy_success); + ShareManager.INSTANCE.showShareAction(mContext,link); + return null; + }); + } + + + @Override + public void onDestroy() { + + RoomNotifyDialogManager.INSTANCE.clear(); + RoomBoomManager.INSTANCE.clear(); + + if (giftView != null) { + giftView.release(); + } + EventBus.getDefault().unregister(this); + gameMainBinding.giftComboBtn.cancel(); + super.onDestroy(); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + roomFragment.onActivityResult(requestCode, resultCode, data); + List fragments = getParentFragmentManager().getFragments(); + if (ListUtils.isNotEmpty(fragments)) { + for (Fragment fragment : fragments) { + if (fragment instanceof RoomBgSetDialog) { + fragment.onActivityResult(requestCode, resultCode, data); + } + } + } + + } + + public void onRoomOnlineNumberSuccess(int onlineNumber) { + updateOnlineNumberView(onlineNumber); + } + + + /** + * 普通 + */ + private void onReceiveGiftMsg(GiftReceiveInfo giftReceiveInfo) { + if (giftReceiveInfo == null || !isResumed()) return; + + gameMainBinding.giftComboLayout.onRoomCustomMsg(GiftToolbox.transformToGiftMultiReceiverInfo(giftReceiveInfo)); + if (giftReceiveInfo.getGift() != null && giftReceiveInfo.getGift().getNotifyFull() == 1) return; + //全服礼物 的 特效播放交给 onReceiveGiftMsgAllService() 35消息来处理 , 但是连击旧消息处理 + + if (giftView == null) { + giftView = (GiftV2View) mVsGift2View.inflate(); + } + giftView.onReceiveGiftMsg(giftReceiveInfo); + } + + /** + * 普通多人 + */ + private void onReceiveMultiGiftMsg(GiftMultiReceiverInfo giftMultiReceiverInfo) { + if (giftMultiReceiverInfo == null || !isResumed()) return; + + gameMainBinding.giftComboLayout.onRoomCustomMsg(giftMultiReceiverInfo); + if (giftMultiReceiverInfo.getGift() != null && giftMultiReceiverInfo.getGift().getNotifyFull() == 1) return; + //全服礼物 的 特效播放交给 onReceiveGiftMsgAllService() 35消息来处理 , 但是连击旧消息处理 + + if (giftView == null) { + giftView = (GiftV2View) mVsGift2View.inflate(); + } + giftView.onReceiveGiftToMultiMsg(giftMultiReceiverInfo); + giftMultiReceiverInfo.isMulti = true; + } + + /** + * 普通全麦 + */ + private void onReceiveAllMicGiftMsg(MultiGiftReceiveInfo multiGiftReceiveInfo) { + if (multiGiftReceiveInfo == null || !isResumed()) return; + + gameMainBinding.giftComboLayout.onRoomCustomMsg(GiftToolbox.transformToGiftMultiReceiverInfo(multiGiftReceiveInfo)); + if (multiGiftReceiveInfo.getGift() != null && multiGiftReceiveInfo.getGift().getNotifyFull() == 1) return; + //全服礼物 的 特效播放交给 onReceiveGiftMsgAllService() 35消息来处理 , 但是连击旧消息处理 + + if (giftView == null) { + giftView = (GiftV2View) mVsGift2View.inflate(); + } + giftView.onReceiveMultiGiftMsg(multiGiftReceiveInfo); + } + + /** + * 全服礼物 + */ + private void onReceiveGiftMsgAllService(GiftReceiveInfo giftReceiveInfo) { + if (giftReceiveInfo == null || !isResumed()) return; + if (giftView == null) { + giftView = (GiftV2View) mVsGift2View.inflate(); + } + giftView.onReceiveGiftMsg(giftReceiveInfo); + // 35 是 全服, 是服务器发的, 服务器发送的不带本地连击数, 所以不处理这个 连击横幅view , 让31 处理 +// gameMainBinding.giftComboLayout.onRoomCustomMsg(GiftToolbox.transformToGiftMultiReceiverInfo(giftReceiveInfo)); + } + + /** + * 全服礼物-飘屏 + */ + private void onReceiveGiftMsgAllServiceNotify(Object anyData) { + if (anyData != null && anyData instanceof AllServiceGiftProtocol.DataBean) { + GlobalNotifyManager.INSTANCE.onReceiveGiftMsgAllServiceNotify(anyData); + } + } + + + private void onReceiveMagicMsg(MagicReceivedInfo magicReceivedInfo) { + if (magicReceivedInfo == null || !isResumed()) return; + if (giftView == null) { + giftView = (GiftV2View) mVsGift2View.inflate(); + } + giftView.onReceiveMagicMsg(magicReceivedInfo); + } + + + private void onReceiveMultiMagicMsg(MultiMagicReceivedInfo multiMagicReceivedInfo) { + if (multiMagicReceivedInfo == null || !isResumed()) return; + if (giftView == null) { + giftView = (GiftV2View) mVsGift2View.inflate(); + } + giftView.onReceiveMultiMagicMsg(multiMagicReceivedInfo); + } + + private void onReceiveFansTeamJoinMsg(ChatRoomMessage message) { + if (message == null || !isResumed()) + return; + if (giftView == null) { + giftView = (GiftV2View) mVsGift2View.inflate(); + } + giftView.onReceiveFansTeamOpenMsg(message); + } + + private void updateOnlineNumberView(int onlineNumber) { + if (!SuperAdminUtil.isSuperAdmin()) { + if (onlineNumber < 1) { + onlineNumber = 1; + } + } +// gameMainBinding.roomNums.setText(ResUtil.getString(R.string.avroom_fragment_homepartyfragment_013) + onlineNumber); + } + + public void showUserCardDialog(String uid) { + long id = JavaUtil.str2long(uid); + if (id == 0) { + return; + } + if (roomFragment instanceof GiftDialog.OnGiftDialogBtnClickListener) { + UserInfoDialog.showNewUserInfoDialog( + mContext, + id, + true, + true, + true, (GiftDialog.OnGiftDialogBtnClickListener) roomFragment + ); + } + + } + + private void showRoomIntroduction(Boolean modify) { + var isModify = modify; + RoomInfo info = AvRoomDataManager.get().mCurrentRoomInfo; + if (info == null) { + return; + } + if (SuperAdminUtil.isSuperAdmin()) { + isModify = false; + } + if (isModify) { + RoomTitleEditActivity.startForResult(getActivity(), info.getRoomDesc(), info.getIntroduction()); + } else { + DialogFragment dialogFragment = + RoomTitleDialogFragment.getInstance(info.getRoomDesc(), info.getIntroduction()); + dialogFragment.show(requireActivity().getSupportFragmentManager(), "roomTitle"); + } + } + + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onGiftComboEvent(GiftComboEvent event) { + if (event.getAction() == GiftComboEvent.Action.ACT_GIFT_BEGIN) { + if (gameMainBinding.giftComboBtn.isInCombo()) { + gameMainBinding.giftComboBtn.waitStart(); + } + } else if (event.getAction() == GiftComboEvent.Action.ACT_GIFT_SEND_SUCCESS) { + showComboBtn(event.getGiftNumber()); + } else if (event.getAction() == GiftComboEvent.Action.ACT_GIFT_COMBO_CANCEL) { + if (gameMainBinding.giftComboBtn.isInCombo()) { + gameMainBinding.giftComboBtn.cancel(); + } + } else if (event.getAction() == GiftComboEvent.Action.ACT_GIFT_POINT) { + ComboUtil.INSTANCE.setPoint(gameMainBinding.giftComboBtn.getSvgaView()); + } + } + + private void showComboBtn(int number) { + if (gameMainBinding.giftComboBtn.getOnGiftComboEndListener() == null) { + + //外部暂停连击点击事件 + gameMainBinding.giftComboBtn.setOnClickListener(v -> { + gameMainBinding.giftComboBtn.showView(false); + gameMainBinding.giftComboBtn.cancel(); + EventBus.getDefault().post(new GiftComboEvent(GiftComboEvent.Action.ACT_GIFT_DIALOG_SHOW)); + gameMainBinding.coinTips.setVisibility(View.GONE); + }); + + //连击点击事件 + gameMainBinding.giftComboBtn.setComboClick(v -> { + ComboUtil.INSTANCE.setPoint(gameMainBinding.giftComboBtn.getSvgaView()); + EventBus.getDefault().post(new GiftComboEvent(GiftComboEvent.Action.ACT_GIFT_COMBO_START)); + gameMainBinding.giftComboBtn.onBtnDown(); + }); + + + gameMainBinding.giftComboBtn.setOnGiftComboEndListener(new BonsellaJoinAttackButtonView.OnGiftComboEndListener() { + @Override + public void onGiftComboEnd() { + gameMainBinding.giftComboBtn.showView(false); + EventBus.getDefault().post(new GiftComboEvent(GiftComboEvent.Action.ACT_GIFT_DIALOG_SHOW)); + gameMainBinding.coinTips.setVisibility(View.GONE); + } + }); + } + + gameMainBinding.giftComboBtn.showView(true); + gameMainBinding.giftComboBtn.start(); + gameMainBinding.giftComboBtn.updateNumber(number); + gameMainBinding.coinTips.setVisibility(View.VISIBLE); + } + + + /** + * 幸运礼物 飘屏 跟 圆球提示 + */ + private void onLuckyGiftMsg(RoomEvent roomEvent) { + MsgSuperLuckyGift msgSuperLuckyGift = roomEvent.getMsgSuperLuckyGift(); + if (msgSuperLuckyGift != null) { + if (msgSuperLuckyGift.luckyGiftMsgAllBean != null) { + RoomNotifyDialogManager.INSTANCE.addDialog(new RoomNotifyDialogBean( + CustomAttachment.CUSTOM_MSG_SUPER_LUCKY_GIFT_TEMPLATE, + CustomAttachment.CUSTOM_MSG_SUPER_LUCKY_GIFT_ROOM, + msgSuperLuckyGift.luckyGiftMsgAllBean + )); + } + + if (msgSuperLuckyGift.luckyGiftMsgSelfBean != null) { + if (msgSuperLuckyGift.luckyGiftMsgSelfBean.getUid() != AuthModel.get().getCurrentUid()) return; + if (msgSuperLuckyGift.luckyGiftMsgSelfBean.getRoomId() != AvRoomDataManager.get().getRoomId()) return; + if (msgSuperLuckyGift.luckyGiftMsgSelfBean.getRoomUid() != AvRoomDataManager.get().getRoomUid()) return; + RoomNotifyDialogManager.INSTANCE.showLuckyGiftTipsNotify(gameMainBinding.flLuckyGiftNotifyLayout,msgSuperLuckyGift.luckyGiftMsgSelfBean); + gameMainBinding.coinTips.showView(String.valueOf(msgSuperLuckyGift.luckyGiftMsgSelfBean.getCoins()),true,false); + } + } + + } + + /** + * cp 礼物 + */ + private void onCpAboutMsg(RoomEvent roomEvent) { + //xxx 校验数据是否异常 + CpMsgBean cpMsgBean = roomEvent.getCpMsgBean(); + if (cpMsgBean != null) { + RoomNotifyDialogManager.INSTANCE.addDialog(new RoomNotifyDialogBean( + CustomAttachment.CP_FIRST, + cpMsgBean.getSecond(), + cpMsgBean + )); + } + } + + /** + * 更新房间背景消息 + */ + private void onRoomBgChange(RoomEvent roomEvent) { + RoomBgChangeBean changeBean = roomEvent.getRoomBgChangeBean(); + if (changeBean != null) { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo != null) { + roomInfo.setBackPic(changeBean.url); + setRoomBg(roomInfo); + } + } + } + + /** + * 更新房间等级消息 + */ + private void onRoomLevelChange(RoomEvent roomEvent) { + Object anyData = roomEvent.getAnyData(); + if (anyData instanceof RoomLevelChangeBean ){ + + Object roomLevel = gameMainBinding.roomLevelIcon.getTag(); + if (roomLevel != null && roomLevel instanceof Integer) { + if ((Integer) roomLevel > ((RoomLevelChangeBean) anyData).roomLevel) return; + } + + gameMainBinding.roomLevelIcon.setTag(((RoomLevelChangeBean) anyData).roomLevel); + OtherExtKt.setVis(gameMainBinding.roomLevelIcon,OtherExtKt.isVerify(((RoomLevelChangeBean) anyData).getRoomLevelIcon()),false); + ImageLoadKt.loadImage(gameMainBinding.roomLevelIcon,((RoomLevelChangeBean) anyData).getRoomLevelIcon()); + } + } + + //超级幸运礼物飘屏 + private void onBravoNotify(RoomEvent roomEvent) { + Object data = roomEvent.getAnyData(); + if (data != null && data instanceof BravoGiftMsgNotifyBean) { + RoomNotifyDialogManager.INSTANCE.addDialog(new RoomNotifyDialogBean(CustomAttachment.CUSTOM_MSG_SUPER_LUCKY_GIFT_TEMPLATE,CustomAttachment.CUSTOM_MSG_SUPER_BRAVO_GIFT_NOTIFY,data)); + } + } + + //超级幸运礼物中奖和主播收益 + private void onBravoReward(RoomEvent roomEvent) { + Object data = roomEvent.getAnyData(); + if (data != null && data instanceof BravoGiftRewardBean) { + RoomNotifyDialogManager.INSTANCE.showBravoGiftTipsNotify(gameMainBinding.flLuckyGiftNotifyLayout, (BravoGiftRewardBean) data,gameMainBinding.coinTips); + } + } + + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onFollowRoomEvent(FollowRoomEvent event) { + ivFollowRoom.setImageResource(AvRoomDataManager.get().isRoomFans ? R.drawable.room_ic_collect_yes : R.drawable.room_ic_collect_no); + } + + /** + * 更新特效开关提示 + */ + @Subscribe(threadMode = ThreadMode.MAIN) + public void updateHasAnimation(HasAnimationEffect event) { + updateHasAnimationEffect(); + } + + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/fragment/HomePartyRoomFragment.java b/app/src/main/java/com/chwl/app/avroom/fragment/HomePartyRoomFragment.java new file mode 100644 index 0000000..7ca15ec --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/fragment/HomePartyRoomFragment.java @@ -0,0 +1,1063 @@ +package com.chwl.app.avroom.fragment; + +import android.annotation.SuppressLint; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; + +import androidx.databinding.DataBindingUtil; + +import com.chwl.app.R; +import com.chwl.app.avroom.activity.AVRoomActivity; +import com.chwl.app.avroom.adapter.BaseMicroViewAdapter; +import com.chwl.app.avroom.adapter.CpMicroViewAdapter; +import com.chwl.app.avroom.adapter.DatingMicroViewAdapter; +import com.chwl.app.avroom.adapter.MicroViewAdapter; +import com.chwl.app.avroom.anotherroompk.RoomPkFinishDialog; +import com.chwl.app.avroom.anotherroompk.RoomPkForceFinishDialog; +import com.chwl.app.avroom.anotherroompk.RoomPkReceivedDialog; +import com.chwl.app.avroom.dialog.MicQueueDialog; +import com.chwl.app.avroom.dialog.PKMicQueueDialog; +import com.chwl.app.avroom.dialog.RoomTeamPKResultDialog; +import com.chwl.app.avroom.dialog.RoomTeamPkDialog; +import com.chwl.app.avroom.giftvalue.GiftValueDialogUiHelper; +import com.chwl.app.avroom.headline.RoomHeadlineWidget; +import com.chwl.app.avroom.online.RoomOnlineWidget; +import com.chwl.app.avroom.presenter.HomePartyPresenter; +import com.chwl.app.avroom.rank.RoomRankNumberWidget; +import com.chwl.app.avroom.view.IHomePartyView; +import com.chwl.app.base.BaseMvpActivity; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.app.databinding.FragmentAvRoomGameBinding; +import com.chwl.app.ui.webview.DatingRuleWebViewActivity; +import com.chwl.app.ui.webview.DialogWebViewActivity; +import com.chwl.app.utils.UserUtils; +import com.chwl.core.Constants; +import com.chwl.core.UriProvider; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.home.event.ShareRoomEvent; +import com.chwl.core.im.custom.bean.RoomPKAttachment; +import com.chwl.core.im.custom.bean.RoomPkBean; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.manager.RoomEvent; +import com.chwl.core.market_verify.MarketVerifyModel; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.core.room.event.DatingSelectUserEvent; +import com.chwl.core.room.face.DynamicFaceModel; +import com.chwl.core.room.face.FaceInfo; +import com.chwl.core.room.model.AvRoomModel; +import com.chwl.core.room.model.MicQueueModel; +import com.chwl.core.room.pk.bean.PKRespQueuingMicListInfo; +import com.chwl.core.room.pk.bean.RoomPkData; +import com.chwl.core.room.pk.event.PKDataUpdateEvent; +import com.chwl.core.room.pk.event.PKStateEvent; +import com.chwl.core.room.pk.model.PkModel; +import com.chwl.core.room.queuing_mic.bean.RespQueuingMicListInfo; +import com.chwl.core.room.queuing_mic.event.QueuingMicEmptyEvent; +import com.chwl.core.room.queuing_mic.event.QueuingMicNotEmptyEvent; +import com.chwl.core.super_admin.util.SuperAdminUtil; +import com.chwl.core.utils.CurrentTimeUtils; +import com.chwl.library.base.factory.CreatePresenter; +import com.chwl.library.common.util.OtherExtKt; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; +import com.chwl.library.utils.TimeUtils; +import com.chwl.library.utils.UIUtils; +import com.netease.nim.uikit.common.util.log.LogUtil; +import com.trello.rxlifecycle3.android.FragmentEvent; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +import io.reactivex.Observable; +import io.reactivex.Single; +import io.reactivex.SingleObserver; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; + +/** + * 轰趴房间 + * + * @author chenran + * @date 2017/7/26 + */ +@CreatePresenter(HomePartyPresenter.class) +public class HomePartyRoomFragment extends BaseRoomFragment implements + IHomePartyView, RoomTeamPkDialog.OnActionListener { + + private long myUid; + private RoomTeamPkDialog teamPkDialog; + private Disposable mDisposable; + private FragmentAvRoomGameBinding gameBinding; + /** + * 排麦弹框 + */ + private MicQueueDialog micQueueDialog; + private PKMicQueueDialog pkMicQueueDialog; + private Disposable roomPkOrderDisposable; + + public static HomePartyRoomFragment newInstance() { + HomePartyRoomFragment roomFragment = new HomePartyRoomFragment(); + Bundle bundle = new Bundle(); + roomFragment.setArguments(bundle); + return roomFragment; + } + + @Override + public int getRootLayoutId() { + return R.layout.fragment_av_room_game; + } + + @Override + public void onFindViews() { + super.onFindViews(); + gameBinding = DataBindingUtil.bind(mView); + gameBinding.setLifecycleOwner(this); + gameBinding.setClick(this); + gameBinding.setKtvModel(false); + gameBinding.playTogether.setVisibility(View.GONE); + microView = mView.findViewById(R.id.micro_view); + if (AvRoomDataManager.get().isHomeParty()) { + OtherExtKt.setMargin(microView,null,30,null,null,true); + } + } + + @Override + public void onSetListener() { + super.onSetListener(); + bottomView.setBottomViewListener(new PartyRoomBottomViewWrapper()); + } + + @Override + public void initWidget() { + super.initWidget(); + registerWidget(RoomOnlineWidget.class.getSimpleName(), gameBinding.onlineWidget); + registerWidget(RoomHeadlineWidget.class.getSimpleName(), gameBinding.headlineWidget); + registerWidget(RoomRankNumberWidget.class.getSimpleName(), gameBinding.rankNumberWidget); + } + + @SuppressLint("CheckResult") + @Override + public void initiate() { + super.initiate(); + myUid = AuthModel.get().getCurrentUid(); + gameBinding.setRoomInfo(AvRoomDataManager.get().mCurrentRoomInfo); + hideKtvRelaView(); + updateQueuingMicBtn(); + updatePkScoreBoard(); + initRoomPkOrder(AvRoomDataManager.get().showPkBeginTime, AvRoomDataManager.get().pkBeginTime); + } + + @Override + public void onReceiveRoomEvent(RoomEvent roomEvent) { + super.onReceiveRoomEvent(roomEvent); + if (roomEvent == null) return; + int event = roomEvent.getEvent(); + switch (event) { + case RoomEvent.DOWN_CROWDED_MIC: + if (AvRoomDataManager.get().isOwner(roomEvent.getAccount())) { + cleanDragonBar(); + } + break; + case RoomEvent.ROOM_MANAGER_ADD: + gameBinding.setRoomInfo(AvRoomDataManager.get().mCurrentRoomInfo); + updatePkScoreBoard(); + //如果自己被设置为管理员,移除自己的排麦队列 + if (AvRoomDataManager.get().isOwner(roomEvent.getAccount())) { + cancelMyQueue(); + if (AvRoomDataManager.get().isQueuingMicro() + && !AvRoomDataManager.get().myIsInQueue + && isMicQueueDialogShowing()) { + micQueueDialog.refreshData(); + } + + if (AvRoomDataManager.get().isOpenPKMode() + && !AvRoomDataManager.get().myIsInQueue + && isPKMicQueueDialogShowing()) { + pkMicQueueDialog.refreshData(); + } + } + break; + case RoomEvent.ROOM_MANAGER_REMOVE: + gameBinding.setRoomInfo(AvRoomDataManager.get().mCurrentRoomInfo); + updatePkScoreBoard(); + if (AvRoomDataManager.get().isOwner(roomEvent.getAccount()) + && isMicQueueDialogShowing()) { + micQueueDialog.refreshData(); + } + if (AvRoomDataManager.get().isOwner(roomEvent.getAccount()) + && isPKMicQueueDialogShowing()) { + pkMicQueueDialog.refreshData(); + } + break; + case RoomEvent.ROOM_INFO_UPDATE: + gameBinding.setRoomInfo(AvRoomDataManager.get().mCurrentRoomInfo); + updateQueuingMicBtn(); + updatePkScoreBoard(); + getMvpPresenter().updateLeaveMode(); + break; + case RoomEvent.ENTER_ROOM: + cpRoomAutoUpMic(); + getMvpPresenter().leaveModeCheck(); + gameBinding.setRoomInfo(AvRoomDataManager.get().mCurrentRoomInfo); + updateQueuingMicBtn(); + updatePkScoreBoard(); + initRoomPkOrder(AvRoomDataManager.get().showPkBeginTime, AvRoomDataManager.get().pkBeginTime); + break; + case RoomEvent.KICK_DOWN_MIC_BY_S_ADMIN: + case RoomEvent.KICK_DOWN_MIC: + cleanDragonBar(); + break; + case RoomEvent.DOWN_MIC: + addOrRemoveMatchPool(); + break; + case RoomEvent.UP_MIC: // 上麦 + getMvpPresenter().closeLeaveMode(roomEvent.getMicPosition(), roomEvent.getAccount()); + addOrRemoveMatchPool(); + if (pkMicQueueDialog != null && pkMicQueueDialog.isShowing()) { + String account = roomEvent.getAccount(); + pkMicQueueDialog.onUpMicro(account); + } + break; + case RoomEvent.INVITE_UP_MIC: + if (!AvRoomDataManager.get().isOwner(roomEvent.getAccount())) { + //如果不是自己的消息,将这上麦的这个人,从排麦列表,静态移除 + removeOtherFromMicQueue(roomEvent.getAccount()); + } + break; + case RoomEvent.KICK_OUT_ROOM: + if (isMicQueueDialogShowing()) { + micQueueDialog.dismiss(); + } + if (AvRoomDataManager.get().isQueuingMicro() && AvRoomDataManager.get().myIsInQueue) { + MicQueueModel.get().cancelApplyForQueuing(AvRoomDataManager.get().getRoomUid(), + AuthModel.get().getCurrentUid()).subscribe(); + } + break; + case RoomEvent.ON_QUEUE_MEMBER_INFO_UPDATE: + // 用户的贵族字段过期或者开通贵族,可以实时地监听ext字段变化,显示头饰,光晕等 + microView.getAdapter().notifyDataSetChanged(); + break; + case RoomEvent.PK_INFO_UPDATE: + updatePkScoreBoard(); + updateQueuingMicBtn(); + break; + case RoomEvent.PK_INVITE_IN_TEAM: + if (AvRoomDataManager.get().isOwner(roomEvent.getAccount())) { + //自己的消息 + onInviteInTeam(roomEvent.getMicPosition()); + } else { + //如果不是自己的消息,将这上麦的这个人,从排麦列表,静态移除 + removeOtherFromMicQueue(roomEvent.getAccount()); + } + break; + case RoomEvent.PK_START: + //PK 开始弹出大记分板 + if (PkModel.get().getCurPkInfo() != null + && PkModel.get().getCurPkInfo().getPkStatus() == RoomPkData.PK_STATUS_IN_PK) { + showTeamPkDialog(); + } + break; + case RoomEvent.PK_CREATE: + if (PkModel.get().getCurPkInfo() != null) { + showTeamPkDialog(); + } + break; + case RoomEvent.ROOM_PK_INVITE: + RoomPkReceivedDialog.newInstance( + ((RoomPKAttachment) roomEvent.getChatRoomMessage().getAttachment()) + .getRoomPkBean()) + .show(mContext); + break; + case RoomEvent.ROOM_PK_FINISH: + RoomPkBean roomPkBean = ((RoomPKAttachment) roomEvent.getChatRoomMessage().getAttachment()).getRoomPkBean(); + if (roomPkBean.isForce()) { + RoomPkForceFinishDialog.newInstance(roomPkBean).show(mContext); + } else { + RoomPkFinishDialog.newInstance(roomPkBean).show(mContext); + } + break; + case RoomEvent.ROOM_PK_ORDER: + RoomPkBean roomPkOrder = ((RoomPKAttachment) roomEvent.getChatRoomMessage().getAttachment()).getRoomPkBean(); + initRoomPkOrder(true, roomPkOrder.getBeginTime()); + break; + default: + break; + } + } + + private void initRoomPkOrder(boolean isShowPkBeginTime, long pkBeginTime) { + if (roomPkOrderDisposable != null && !roomPkOrderDisposable.isDisposed()) return; + long residueSeconds = (pkBeginTime - CurrentTimeUtils.getCurrentTime()) / 1000; + if (isShowPkBeginTime && residueSeconds > 0) { + gameBinding.llRoomPkOrder.setVisibility(View.VISIBLE); + roomPkOrderDisposable = Observable.intervalRange(0, residueSeconds, 1, 1, TimeUnit.SECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .compose(bindUntilEvent(FragmentEvent.DESTROY_VIEW)) + .doOnComplete(() -> gameBinding.llRoomPkOrder.setVisibility(View.GONE)) + .subscribe(aLong -> gameBinding.tvRoomPkOrderTime.setText(TimeUtils.getFormatTimeString((residueSeconds - aLong) * 1000, "min:sec"))); + } else { + gameBinding.llRoomPkOrder.setVisibility(View.GONE); + } + } + + /** + * cp房自动上麦 + */ + private void cpRoomAutoUpMic() { + if (AvRoomDataManager.get().isCpRoom()) { + + // 超管进cp房不上麦 + if (SuperAdminUtil.isSuperAdmin()) { + return; + } + + int freePosition = AvRoomDataManager.get().findFreePosition(); + if (freePosition == Integer.MIN_VALUE) { + return; + } + if (AvRoomDataManager.get().isRoomOwner()) { + getMvpPresenter().upMicroPhone(-1, AuthModel.get().getCurrentUid() + "", false); + } else { + int freePositionNoOwner = AvRoomDataManager.get().findFreePositionNoOwner(); + if (freePositionNoOwner == 0) { + getMvpPresenter().upMicroPhone(freePositionNoOwner, AuthModel.get().getCurrentUid() + "", false); + } else if (freePosition == -1) { + getMvpPresenter().upMicroPhone(freePosition, AuthModel.get().getCurrentUid() + "", false); + } + } + } + } + + /** + * 抱上队伍 + * + * @param micPosition + */ + private void onInviteInTeam(int micPosition) { + if (UIUtils.isTopActivity(getBaseActivity())) { + ((BaseMvpActivity) getActivity()).getDialogManager() + .showOkWithTitleDialog(getString(R.string.embrace_on_mic), true); + } + //被人抱上麦 + //自己取消报名 + cancelMyQueue(); + } + + private void updatePkScoreBoard() { + if (AvRoomDataManager.get().isOpenPKMode()) { + + if (ivTeamPk.getVisibility() == View.GONE) { + // 通知更新背景 + PKStateEvent pkStateEvent = new PKStateEvent(); + pkStateEvent.setCreate(true); + EventBus.getDefault().post(pkStateEvent); + showTeamPkDialog(); + } + ivTeamPk.setVisibility(View.VISIBLE); + //这里通过接口获取PK 详情 更新pk 记分板 + if (PkModel.get().getCurPkInfo() == null) { + PkModel.get().loadPKDataByRoomId( + AvRoomDataManager.get().getRoomUid() + ) + .subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) { + mCompositeDisposable.add(d); + } + + @Override + public void onSuccess(RoomPkData roomPkData) { + if (teamPkDialog != null) { + teamPkDialog.updateView(); + } + } + + @Override + public void onError(Throwable e) { + toast(e.getMessage()); + } + }); + } else { + if (teamPkDialog != null) { + teamPkDialog.updateView(); + } + } + //取消掉正在进行的龙珠 + if (AvRoomDataManager.get().haveStartDragon) { + ((AVRoomActivity) getActivity()).giveUpDragonBar().subscribe(s -> { + gameBinding.playDragon.setVisibility(View.INVISIBLE); + gameBinding.cancelDragon.setVisibility(View.INVISIBLE); + getMvpPresenter().cancelDragon(); + }); + } + + } else { + if (ivTeamPk != null) { + if (ivTeamPk.getVisibility() == View.VISIBLE) { + // 通知更新bg + PKStateEvent pkStateEvent = new PKStateEvent(); + pkStateEvent.setCreate(false); + EventBus.getDefault().post(pkStateEvent); + } + ivTeamPk.setVisibility(View.GONE); + } + dismissTeamPkDialog(); + } + + //龙珠相关界面设置 + setDragonView(); + } + + private void showTeamPkDialog() { + if (getActivity() == null) { + return; + } + if (teamPkDialog != null) { + if (teamPkDialog.isResumed()) { + return; + } + dismissTeamPkDialog(); + } + teamPkDialog = new RoomTeamPkDialog(); + teamPkDialog.setOnActionListener(this); + teamPkDialog.safeShow(requireActivity().getSupportFragmentManager(), this, null); + } + + private void dismissTeamPkDialog() { + if (teamPkDialog != null) { + teamPkDialog.safeDismiss(); + teamPkDialog = null; + } + } + + private void cleanDragonBar() { + LogUtil.e("cleanDragonBar"); + if (AvRoomDataManager.get().haveStartDragon) { + AvRoomDataManager.get().haveStartDragon = false; + ((AVRoomActivity) getActivity()).giveUpDragonBar().subscribe(s -> { + gameBinding.playDragon.setVisibility(View.INVISIBLE); + gameBinding.cancelDragon.setVisibility(View.INVISIBLE); + }); + } + } + + public void updateView() { + super.updateView(); + // 是否可以显示一起玩的骰子活动 + gameBinding.playTogether.setVisibility( + (!MarketVerifyModel.get().isMarketChecking() && + AvRoomDataManager.get().isAllowedToPlayTogether() && + (AvRoomDataManager.get().isRoomAdmin() || AvRoomDataManager.get().isRoomOwner())) && + (!AvRoomDataManager.get().isOpenKTV()) && !AvRoomDataManager.get().isCpRoom() ? + View.VISIBLE : + View.GONE); + + if (AvRoomDataManager.get().isDatingMode()) { + switchToDatingMode(); + } else { + closeDatingMode(); + } + + if ((AvRoomDataManager.get().isDatingMode() || AvRoomDataManager.get().isOpenPKMode()) && !AvRoomDataManager.get().isManager()) { + mIvQueuingMicro.setVisibility(View.VISIBLE); + mIvQueuingMicro.setImageResource(AvRoomDataManager.get().isDatingMode() ? + R.drawable.ic_dating_queuing_micro : R.drawable.ic_pk_queuing_micro); + } else { + mIvQueuingMicro.setVisibility(View.GONE); + gameBinding.bottomView.updateQueuingMicButton(); + } + updateMicroView(); + changeModelShowView(); + refreshDatingNextStatus(); + } + + protected void updateMicroView(){ + String microType = microView.getAdapter() == null ? BaseMicroViewAdapter.MICRO_TYPE_NULL : microView.getAdapter().microType(); + if (AvRoomDataManager.get().isCpRoom()) { + if (!microType.equals(BaseMicroViewAdapter.MICRO_TYPE_CP)) { + microView.bindAdapter(new CpMicroViewAdapter(mContext)); + } + } else if (AvRoomDataManager.get().isDatingMode()) { + if (!microType.equals(BaseMicroViewAdapter.MICRO_TYPE_DATING)) { + microView.bindAdapter(new DatingMicroViewAdapter(mContext)); + } + } else { + if (!microType.equals(BaseMicroViewAdapter.MICRO_TYPE_NORMAL)) { + microView.bindAdapter(new MicroViewAdapter(mContext)); + } + } + if (microView.getAdapter() != null) { + microView.getAdapter().notifyDataSetChanged(); + } + } + + public void updateMicBtn() { + super.updateMicBtn(); + refreshDatingNextStatus(); + } + + + + private void updateQueuingMicBtn() { + if (AvRoomDataManager.get().mCurrentRoomInfo != null) { + bottomView.updateQueuingMicButton(); + + if (!AvRoomDataManager.get().isQueuingMicro()) { + if (isMicQueueDialogShowing()) { + micQueueDialog.dismiss(); + } + } + + if (!AvRoomDataManager.get().isOpenPKMode()) { + if (isPKMicQueueDialogShowing()) { + pkMicQueueDialog.dismiss(); + } + } + } + } + + private synchronized void refreshDatingNextStatus() { + RoomInfo currentRoomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (currentRoomInfo == null) return; + String hintText = ResUtil.getString(R.string.avroom_fragment_homepartyroomfragment_01); + if (!TextUtils.isEmpty(currentRoomInfo.getBlindDateState())) { + switch (currentRoomInfo.getBlindDateState()) { + case RoomInfo.DATING_STATE_FLOW: + gameBinding.tvDatingNext.setText(ResUtil.getString(R.string.avroom_fragment_homepartyroomfragment_02)); + gameBinding.tvDatingStep.setText(ResUtil.getString(R.string.avroom_fragment_homepartyroomfragment_03)); + hintText = ResUtil.getString(R.string.avroom_fragment_homepartyroomfragment_04); + break; + case RoomInfo.DATING_STATE_SELECT: + gameBinding.tvDatingNext.setText(ResUtil.getString(R.string.avroom_fragment_homepartyroomfragment_05)); + gameBinding.tvDatingStep.setText(ResUtil.getString(R.string.avroom_fragment_homepartyroomfragment_06)); + hintText = ResUtil.getString(R.string.avroom_fragment_homepartyroomfragment_07); + break; + case RoomInfo.DATING_STATE_PUBLISH: + gameBinding.tvDatingNext.setText(ResUtil.getString(R.string.avroom_fragment_homepartyroomfragment_08)); + gameBinding.tvDatingStep.setText(ResUtil.getString(R.string.avroom_fragment_homepartyroomfragment_09)); + hintText = ResUtil.getString(R.string.avroom_fragment_homepartyroomfragment_010); + break; + } + //只有主持自己能改变这个状态,所以理论上来说只有再次调用refreshDatingNextStatus()文案才可能会改变了,就不再写次switch了 + String finalHintText = hintText; + gameBinding.tvDatingNext.setOnClickListener(v -> + getDialogManager().showOkCancelDialog(finalHintText, true, () -> getMvpPresenter().datingNext())); + } + if (AvRoomDataManager.get().isPreside(UserUtils.getUserUid())) { + gameBinding.tvDatingNext.setVisibility(View.VISIBLE); + } else { + gameBinding.tvDatingNext.setVisibility(View.GONE); + } + } + + @Override + public void onDestroy() { + if (mDisposable != null) { + mDisposable.dispose(); + mDisposable = null; + } + dismissTeamPkDialog(); + super.onDestroy(); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onDatingSelectUserEvent(DatingSelectUserEvent event) { + if (getMvpPresenter() != null) { + getMvpPresenter().datingSelect(event.getChosenUserId()); + } + } + + /** + * 排麦模式从有人到无人 + * + * @param event + */ + @Subscribe(threadMode = ThreadMode.MAIN) + public void displayEmptyQueuingMic(QueuingMicEmptyEvent event) { + bottomView.setQueuingMicButtonBackground(true); + } + + /** + * 排麦模式从无人到有人 + * + * @param event + */ + @Subscribe(threadMode = ThreadMode.MAIN) + public void displayNotEmptyQueuingMic(QueuingMicNotEmptyEvent event) { + bottomView.setQueuingMicButtonBackground(false); + } + + @Override + public void onClick(View v) { + super.onClick(v); + switch (v.getId()) { + case R.id.iv_team_pk: + showTeamPkDialog(); + break; + case R.id.play_together: + if (!DynamicFaceModel.get().isShowingFace()) { + FaceInfo faceInfo = DynamicFaceModel.get().getPlayTogetherFace(); + if (faceInfo != null) { + DynamicFaceModel.get().sendAllFace(faceInfo); + } else { + toast(ResUtil.getString(R.string.avroom_fragment_homepartyroomfragment_011)); + } + } + break; + case R.id.iv_queuing_micro: + gameBinding.bottomView.onClick(v); + break; + case R.id.iv_dragon_start_button: + if (AvRoomDataManager.get().haveStartDragon) { + return; + } + playDragon(); + break; + case R.id.play_dragon: + playDragon(); + break; + case R.id.cancel_dragon: + ((AVRoomActivity) requireActivity()).giveUpDragonBar().subscribe(s -> { + gameBinding.playDragon.setVisibility(View.INVISIBLE); + gameBinding.cancelDragon.setVisibility(View.INVISIBLE); + getMvpPresenter().cancelDragon(); + }); + break; + case R.id.layout_hour_rank: + DialogWebViewActivity.start( + mContext, + UriProvider.getRoomHourRankUrl(AvRoomDataManager.get().getRoomUid()) + ); + break; + default: + break; + } + } + + @SuppressLint("CheckResult") + private void playDragon() { + List faceInfos = DynamicFaceModel.get().getFaceInfos(); + if (faceInfos == null) { + toast(ResUtil.getString(R.string.avroom_fragment_homepartyroomfragment_012)); + return; + } + FaceInfo info = null; + for (FaceInfo faceInfo : faceInfos) { + if (faceInfo.getId() == Constants.DRAGON_BAR_ID) { + info = faceInfo; + } + } + if (info == null) return; + if (AvRoomDataManager.get().haveStartDragon) { + getMvpPresenter().clearDragonBar().subscribe((s, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + } + gameBinding.playDragon.setVisibility(View.INVISIBLE); + gameBinding.cancelDragon.setVisibility(View.INVISIBLE); + }); + } else { + getMvpPresenter().getDragonBar(info).subscribe(s -> { + gameBinding.playDragon.setVisibility(View.VISIBLE); + gameBinding.cancelDragon.setVisibility(View.VISIBLE); + }); + } + } + + + @Override + public void onInviteUpMic(final int micPosition) { + super.onInviteUpMic(micPosition); + //被人抱上麦 + //自己取消报名 + cancelMyQueue(); + } + + private void addOrRemoveMatchPool() { + if (AvRoomDataManager.get().isCpRoom() && AvRoomDataManager.get().isRoomOwner()) { + if (AvRoomDataManager.get().findFreePosition() > 0) { + AvRoomModel.get().removeIsomerism().subscribe(); + } else if (TextUtils.isEmpty(AvRoomDataManager.get().mCurrentRoomInfo.getLimitType()) + && TextUtils.isEmpty(AvRoomDataManager.get().mCurrentRoomInfo.getRoomPwd())) { + AvRoomModel.get().addIsomerism().subscribe(); + } + } + } + + @Override + public void onBeginPK() { + if (!AvRoomDataManager.get().isManager()) { + return; + } + Single stringSingle; + String hintText = ResUtil.getString(R.string.avroom_fragment_homepartyroomfragment_013); + if (PkModel.get().getCurPkInfo() != null + && PkModel.get().getCurPkInfo().getPkStatus() == RoomPkData.PK_STATUS_AFTER_PK) { + hintText = ResUtil.getString(R.string.avroom_fragment_homepartyroomfragment_014); + stringSingle = PkModel.get().toPKAgain(); + } else { + stringSingle = PkModel.get().beginPK(); + } + getDialogManager().showOkCancelWithTitleDialog(hintText, () -> { + stringSingle.subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) { + mCompositeDisposable.add(d); + } + + @Override + public void onSuccess(String s) { + toast(s); + } + + @Override + public void onError(Throwable e) { + toast(e.getMessage()); + } + }); + }); + + } + + @Override + public void onShowPKMicQueueDialog() { + if (PkModel.get().isFighting()) { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_fragment_homepartyroomfragment_015)); + return; + } + pkMicQueueDialog = new PKMicQueueDialog(mContext); + pkMicQueueDialog.setActionListener(new PKMicQueueDialog.OnActionListener() { + @Override + public void onShareRoom(PKMicQueueDialog micQueueDialog) { + micQueueDialog.dismiss(); + EventBus.getDefault().post(new ShareRoomEvent()); + } + + @Override + public void onApplyMicQueue(PKMicQueueDialog micQueueDialog, int teamId) { + long myUid = AuthModel.get().getCurrentUid(); + if (AvRoomDataManager.get().isOnMic(myUid)) { + toast(ResUtil.getString(R.string.avroom_fragment_homepartyroomfragment_016)); + return; + } + //加入排队 + PkModel.get().joinPKMicQueue( + teamId + ) + .subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) { + micQueueDialog.addDisposable(d); + } + + @Override + public void onSuccess(PKRespQueuingMicListInfo info) { + micQueueDialog.updateQueueInfo(info); + } + + @Override + public void onError(Throwable e) { + toast(e.getMessage()); + } + }); + } + + @Override + public void onCancelMicQueue(PKMicQueueDialog micQueueDialog) { + getDialogManager().showOkCancelDialog( + ResUtil.getString(R.string.avroom_fragment_homepartyroomfragment_017), + true, + new DialogManager.OkCancelDialogListener() { + @Override + public void onCancel() { + + } + + @Override + public void onOk() { + PkModel.get().leavePKMicQueue() + .subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) { + micQueueDialog.addDisposable(d); + } + + @Override + public void onSuccess(PKRespQueuingMicListInfo info) { + micQueueDialog.updateQueueInfo(info); + } + + @Override + public void onError(Throwable e) { + toast(e.getMessage()); + } + }); + } + }); + } + }); + pkMicQueueDialog.show(); + } + + private void hideKtvRelaView() { + gameBinding.setKtvModel(false); +// gameBinding.contributeList.setVisibility(View.VISIBLE); + changeModelShowView(); + gameBinding.bottomView.showKtvBottom(false); + } + + @SuppressLint("CheckResult") + private void changeModelShowView() { + if (AvRoomDataManager.get().mCurrentRoomInfo == null) { + return; + } + if (AvRoomDataManager.get().mCurrentRoomInfo.getIsPermitRoom() == 1) { + gameBinding.layoutHourRank.setVisibility(View.VISIBLE); + } else { + gameBinding.layoutHourRank.setVisibility(View.GONE); + } + setDragonView(); + } + + private void switchToDatingMode() { + if (isDatingMode) return; + isDatingMode = true; + if (AvRoomDataManager.get().isPreside(UserUtils.getUserUid())) { + gameBinding.tvDatingNext.setVisibility(View.VISIBLE); + } else { + gameBinding.tvDatingNext.setVisibility(View.GONE); + } + gameBinding.llDatingStep.setVisibility(View.VISIBLE); + gameBinding.llDatingStep.setOnClickListener(v -> DatingRuleWebViewActivity.start(mContext, UriProvider.getDatingRule())); + } + + private void closeDatingMode() { + if (!isDatingMode) return; + isDatingMode = false; + gameBinding.tvDatingNext.setVisibility(View.GONE); + gameBinding.llDatingStep.setVisibility(View.GONE); + } + + /** + * 设置龙珠的状态 + */ + private void setDragonView() { + boolean isOnMic = AvRoomDataManager.get().isOnMic(myUid); + if (AvRoomDataManager.get().hasDragonGame() && + isOnMic && + !MarketVerifyModel.get().isMarketChecking() && + !AvRoomDataManager.get().isOpenPKMode() && + !AvRoomDataManager.get().isCpRoom()) { +// gameBinding.layoutDragon.setVisibility(View.VISIBLE); + if (AvRoomDataManager.get().haveStartDragon) { + gameBinding.playDragon.setVisibility(View.VISIBLE); + gameBinding.cancelDragon.setVisibility(View.VISIBLE); + } else { + gameBinding.playDragon.setVisibility(View.INVISIBLE); + gameBinding.cancelDragon.setVisibility(View.INVISIBLE); + } + return; + } + gameBinding.layoutDragon.setVisibility(View.GONE); + } + + @Override + public void onDragonBarChangeMic(int micPosition, String uId, boolean isInviteUpMic, RoomInfo roomInfo) { + getDialogManager().showOkCancelDialog(ResUtil.getString(R.string.avroom_fragment_homepartyroomfragment_018), false, new DialogManager.OkCancelDialogListener() { + @Override + public void onCancel() { + } + + @Override + public void onOk() { + ((AVRoomActivity) getActivity()).giveUpDragonBar().subscribe(s -> { + getMvpPresenter().cancelDragon(); + }); + getMvpPresenter().upMicroPhone(micPosition, uId, isInviteUpMic, roomInfo); + } + }); + } + + /** + * 礼物值模式下换麦 + */ + @Override + public void onGiftValueChangeMic(int micPosition, String uId, boolean isInviteUpMic, RoomInfo roomInfo) { + if (!GiftValueDialogUiHelper.get().isNeedChangeMicDialog()) { + getMvpPresenter().upMicroPhone(micPosition, uId, isInviteUpMic, roomInfo); + return; + } + GiftValueDialogUiHelper.get().showGiftValueDialog(mContext, getDialogManager(), + GiftValueDialogUiHelper.TYPE_CHANGE_MIC, + () -> getMvpPresenter().upMicroPhone(micPosition, uId, isInviteUpMic, roomInfo)); + } + + /** + * 静态移除这个人出队列 + * + * @param account 需要移除的人 + */ + private void removeOtherFromMicQueue(String account) { + if (TextUtils.isEmpty(account)) { + return; + } + if (AvRoomDataManager.get().isQueuingMicro() && isMicQueueDialogShowing()) { + micQueueDialog.removeQueueMember(account); + } + + if (AvRoomDataManager.get().isOpenPKMode() && isPKMicQueueDialogShowing()) { + pkMicQueueDialog.removeQueueMember(account); + } + } + + /** + * 取消我的报名,如果我已经报名的话 + */ + @SuppressLint("CheckResult") + private void cancelMyQueue() { + if (AvRoomDataManager.get().isQueuingMicro() && AvRoomDataManager.get().myIsInQueue) { + MicQueueModel.get().cancelApplyForQueuing(AvRoomDataManager.get().getRoomUid(), + AuthModel.get().getCurrentUid()) + .compose(bindUntilEvent(FragmentEvent.DESTROY)) + .subscribe(info -> { + if (isMicQueueDialogShowing()) { + micQueueDialog.updateQueueInfo(info); + } else { + AvRoomDataManager.get().myIsInQueue = false; + } + }); + } + + if (AvRoomDataManager.get().isOpenPKMode() && AvRoomDataManager.get().myIsInQueue) { + PkModel.get().leavePKMicQueue() + .compose(bindUntilEvent(FragmentEvent.DESTROY)) + .subscribe(info -> { + if (isMicQueueDialogShowing()) { + pkMicQueueDialog.updateQueueInfo(info); + } else { + AvRoomDataManager.get().myIsInQueue = false; + } + }); + } + } + + private boolean isMicQueueDialogShowing() { + return micQueueDialog != null && micQueueDialog.isShowing(); + } + + private boolean isPKMicQueueDialogShowing() { + return pkMicQueueDialog != null && pkMicQueueDialog.isShowing(); + } + + /** + * 底部按钮点击处理 + */ + private class PartyRoomBottomViewWrapper extends BaseRoomBottomViewWrapper { + + /** + * 点击排麦按钮 + */ + @Override + public void onMicQueueClick() { + if (AvRoomDataManager.get().isOpenPKMode()) { + onShowPKMicQueueDialog(); + } else { + micQueueDialog = new MicQueueDialog(mContext); + micQueueDialog.setActionListener(new MicQueueDialog.OnActionListener() { + @Override + public void onShareRoom(MicQueueDialog micQueueDialog) { + EventBus.getDefault().post(new ShareRoomEvent()); + } + + @Override + public void onApplyMicQueue(final MicQueueDialog micQueueDialog, int groupType) { + long myUid = AuthModel.get().getCurrentUid(); + if (AvRoomDataManager.get().isOnMic(myUid)) { + toast(ResUtil.getString(R.string.avroom_fragment_homepartyroomfragment_019)); + return; + } + //加入排队 + MicQueueModel.get().applyForQueuing(AvRoomDataManager.get().getRoomUid(), + AuthModel.get().getCurrentUid(), + groupType + ) + .subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) { + micQueueDialog.addDisposable(d); + } + + @Override + public void onSuccess(RespQueuingMicListInfo info) { + micQueueDialog.updateQueueInfo(info); + } + + @Override + public void onError(Throwable e) { + toast(e.getMessage()); + } + }); + + } + + @Override + public void onCancelMicQueue(final MicQueueDialog micQueueDialog) { + //取消排队 + getDialogManager().showOkCancelDialog( + ResUtil.getString(R.string.avroom_fragment_homepartyroomfragment_020), + true, + new DialogManager.OkCancelDialogListener() { + @Override + public void onCancel() { + + } + + @Override + public void onOk() { + MicQueueModel.get().cancelApplyForQueuing( + AvRoomDataManager.get().getRoomUid(), + AuthModel.get().getCurrentUid()) + .subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) { + micQueueDialog.addDisposable(d); + } + + @Override + public void onSuccess(RespQueuingMicListInfo info) { + micQueueDialog.updateQueueInfo(info); + } + + @Override + public void onError(Throwable e) { + toast(e.getMessage()); + } + }); + } + }); + } + }); + micQueueDialog.show(); + } + } + } + + + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onPKDataUpdateEvent(PKDataUpdateEvent event) { + RoomPkData data = PkModel.get().getCurPkInfo(); + if (data == null) { + return; + } + if (event.getType() == PKDataUpdateEvent.TYPE_RESULT && data.getPkStatus() == RoomPkData.PK_STATUS_AFTER_PK) { + RoomTeamPKResultDialog teamPkResultDialog = new RoomTeamPKResultDialog(getContext(), PkModel.get().getCurPkInfo()); + teamPkResultDialog.show(); + } + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/fragment/IRoomRankDialogChangePageListener.java b/app/src/main/java/com/chwl/app/avroom/fragment/IRoomRankDialogChangePageListener.java new file mode 100644 index 0000000..8b8d587 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/fragment/IRoomRankDialogChangePageListener.java @@ -0,0 +1,5 @@ +package com.chwl.app.avroom.fragment; + +public interface IRoomRankDialogChangePageListener { + void onChangePage(int pos); +} diff --git a/app/src/main/java/com/chwl/app/avroom/fragment/IRoomRankDialogDismissListener.java b/app/src/main/java/com/chwl/app/avroom/fragment/IRoomRankDialogDismissListener.java new file mode 100644 index 0000000..38668d8 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/fragment/IRoomRankDialogDismissListener.java @@ -0,0 +1,5 @@ +package com.chwl.app.avroom.fragment; + +public interface IRoomRankDialogDismissListener { + void onDismiss(); +} diff --git a/app/src/main/java/com/chwl/app/avroom/fragment/IRoomRankHalfHourView.java b/app/src/main/java/com/chwl/app/avroom/fragment/IRoomRankHalfHourView.java new file mode 100644 index 0000000..1f09760 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/fragment/IRoomRankHalfHourView.java @@ -0,0 +1,18 @@ +package com.chwl.app.avroom.fragment; + +import com.chwl.core.room.bean.RoomRankHalfHourMeInfo; +import com.chwl.core.room.bean.RoomRankHalfHourRankInfo; +import com.chwl.core.room.bean.RoomRankMultiItem; +import com.chwl.library.base.IMvpBaseView; + +import java.util.List; + +public interface IRoomRankHalfHourView extends IMvpBaseView { + void showMeInfo(RoomRankHalfHourMeInfo dataInfo/*, int progress, String onListTip*/); + + void showTop3Info(List dataInfoList); + + void showRankListInfo(List dataList); + + void loadDataFailure(); +} diff --git a/app/src/main/java/com/chwl/app/avroom/fragment/InputPwdDialogFragment.java b/app/src/main/java/com/chwl/app/avroom/fragment/InputPwdDialogFragment.java new file mode 100644 index 0000000..649e511 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/fragment/InputPwdDialogFragment.java @@ -0,0 +1,122 @@ +package com.chwl.app.avroom.fragment; + +import android.os.Bundle; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; +import android.widget.TextView; + +import androidx.annotation.Nullable; +import androidx.fragment.app.DialogFragment; + +import com.chwl.app.R; +import com.chwl.library.utils.codec.DESUtils; + +/** + *

密码框输入

+ * + * @author Administrator + * @date 2017/12/1 + */ +public class InputPwdDialogFragment extends DialogFragment implements View.OnClickListener { + private View mRootView; + private TextView mTvTitle; + private EditText mInputText; + private TextView mFailText; + private TextView mConfirmText; + private TextView mCancelText; + + private String mTitle; + private String mOk; + private String mCancel; + private String mResultCode; + + public static InputPwdDialogFragment newInstance(String title, String okLabel, String cancelLabel, String resultCode) { + InputPwdDialogFragment fragment = new InputPwdDialogFragment(); + Bundle bundle = new Bundle(); + bundle.putString("title", title); + bundle.putString("okLabel", okLabel); + bundle.putString("cancelLabel", cancelLabel); + bundle.putString("resultCode", resultCode); + fragment.setArguments(bundle); + return fragment; + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Bundle arguments = getArguments(); + if (arguments != null) { + mTitle = arguments.getString("title"); + mOk = arguments.getString("okLabel"); + mCancel = arguments.getString("cancelLabel"); + mResultCode = arguments.getString("resultCode"); + } + + setCancelable(false); + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + mRootView = inflater.inflate(R.layout.layout_pic_login_dialog, container); + mTvTitle = (TextView) mRootView.findViewById(R.id.pic_login_title); + mInputText = (EditText) mRootView.findViewById(R.id.pic_login_input); + mFailText = (TextView) mRootView.findViewById(R.id.pic_login_fail_msg); + mConfirmText = (TextView) mRootView.findViewById(R.id.btn_confirm); + mCancelText = (TextView) mRootView.findViewById(R.id.btn_cancel); + return mRootView; + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + mInputText.requestFocus(); + + mTvTitle.setText(mTitle); + mCancelText.setText(mCancel); + mConfirmText.setText(mOk); + + mConfirmText.setOnClickListener(this); + mCancelText.setOnClickListener(this); + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.btn_confirm: + if (!TextUtils.isEmpty(mResultCode)) { + if (mResultCode.equals(DESUtils.DESAndBase64(mInputText.getText().toString()))) { + if (mOnDialogBtnClickListener != null) { + mOnDialogBtnClickListener.onBtnConfirm(); + } + } else { + mFailText.setVisibility(View.VISIBLE); + } + } else { + mFailText.setVisibility(View.VISIBLE); + } + break; + case R.id.btn_cancel: + if (mOnDialogBtnClickListener != null) { + mOnDialogBtnClickListener.onBtnCancel(); + } + break; + default: + } + } + + private OnDialogBtnClickListener mOnDialogBtnClickListener; + + public void setOnDialogBtnClickListener(OnDialogBtnClickListener onDialogBtnClickListener) { + mOnDialogBtnClickListener = onDialogBtnClickListener; + } + + public interface OnDialogBtnClickListener { + void onBtnConfirm(); + + void onBtnCancel(); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/fragment/OnlineUserFragment.java b/app/src/main/java/com/chwl/app/avroom/fragment/OnlineUserFragment.java new file mode 100644 index 0000000..3b5d8f7 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/fragment/OnlineUserFragment.java @@ -0,0 +1,183 @@ +package com.chwl.app.avroom.fragment; + +import android.view.View; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chwl.app.R; +import com.chwl.app.avroom.adapter.OnlineUserAdapter; +import com.chwl.app.avroom.presenter.HomePartyUserListPresenter; +import com.chwl.app.avroom.view.IHomePartyUserListView; +import com.chwl.app.base.BaseMvpFragment; +import com.chwl.app.ui.widget.UserInfoDialog; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.room.bean.OnlineChatMember; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.core.room.bean.RoomOnlineUserBean; +import com.chwl.library.base.factory.CreatePresenter; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; +import com.netease.nim.uikit.common.util.sys.NetworkUtil; +import com.orhanobut.logger.Logger; +import com.scwang.smart.refresh.layout.SmartRefreshLayout; +import com.scwang.smart.refresh.layout.api.RefreshLayout; +import com.scwang.smart.refresh.layout.listener.OnRefreshListener; + +import java.util.Iterator; +import java.util.List; + +; + +/** + *

在线用户列表

+ * + * @author Administrator + * @date 2017/12/4 + */ +@CreatePresenter(HomePartyUserListPresenter.class) +public class OnlineUserFragment extends BaseMvpFragment + implements BaseQuickAdapter.OnItemClickListener, IHomePartyUserListView, OnlineUserAdapter.OnRoomOnlineNumberChangeListener { + private RecyclerView mRecyclerView; + private SmartRefreshLayout mRefreshLayout; + + private OnlineUserAdapter mOnlineUserAdapter; + private boolean isShowToUser = false; + + @Override + public void onDestroy() { + if (mOnlineUserAdapter != null) + mOnlineUserAdapter.release(); + super.onDestroy(); + } + + @Override + public void onFindViews() { + mRecyclerView = mView.findViewById(R.id.recycler_view); + mRefreshLayout = mView.findViewById(R.id.refresh_layout); + mRefreshLayout.setEnableLoadMore(false); + } + + @Override + public void onSetListener() { + mRefreshLayout.setOnRefreshListener(new OnRefreshListener() { + @Override + public void onRefresh(RefreshLayout refreshLayout) { + if (!NetworkUtil.isNetAvailable(mContext)) { + mRefreshLayout.finishRefresh(); + return; + } + firstLoad(); + } + }); + } + + @Override + public void initiate() { + mRecyclerView.setLayoutManager(new LinearLayoutManager(mContext)); + mOnlineUserAdapter = new OnlineUserAdapter(mContext, true); + mRecyclerView.setAdapter(mOnlineUserAdapter); + mOnlineUserAdapter.setOnItemClickListener(this); + mOnlineUserAdapter.setListener(this); + firstLoad(); + } + + + @Override + public int getRootLayoutId() { + return R.layout.common_refresh_recycler_view; + } + + + public void firstLoad() { + loadData(); + } + + private void loadData() { + getMvpPresenter().requestRoomOnlineList(AvRoomDataManager.get().getRoomUid()); + } + + + @Override + public void onRequestRoomOnlineListSuccess(List chatRoomMemberList) { + + Iterator iterator = chatRoomMemberList.iterator(); + while (iterator.hasNext()) { + RoomOnlineUserBean next = iterator.next(); + if (next.isSuperAdmin()) { + iterator.remove(); + } + } + + mOnlineUserAdapter.setNewData(chatRoomMemberList); + mRefreshLayout.finishRefresh(); + } + + @Override + public void onRequestChatMemberByPageFail(String errorStr, int page) { + Logger.i(ResUtil.getString(R.string.avroom_fragment_onlineuserfragment_01) + page); + mRefreshLayout.finishRefresh(); + } + + @Override + public void onMemberInRefresh() { +// if (!isResumed()) return; +// if (!isShowToUser()) return; +// firstLoad(); + } + + @Override + public void onItemClick(BaseQuickAdapter baseQuickAdapter, View view, int position) { + RoomInfo currentRoom = AvRoomDataManager.get().mCurrentRoomInfo; + if (currentRoom != null) { + List chatRoomMembers = mOnlineUserAdapter.getData(); + if (ListUtils.isListEmpty(chatRoomMembers)) return; + RoomOnlineUserBean onlineChatMember = chatRoomMembers.get(position); + if (onlineChatMember != null) { + if (onlineChatMember.getItemType() == OnlineChatMember.NOBLE) { + return; + } + UserInfoDialog.showNewUserInfoDialog(mContext, + onlineChatMember.getUid(), + true, + false, + true, + null); + } + } + } + + @Override + public void onMemberIn(String account) { +// if (!isResumed()) return; +// getMvpPresenter().onMemberInRefreshData(account, dataList, mPage); + } + + @Override + public void onMemberExit(String account) { +// if (!isResumed()) return; +// if (!isShowToUser()) return; +// firstLoad(); + } + + @Override + public void onMemberDownUpMic(String account, boolean isUpMic) { + } + + @Override + public void onUpdateMemberManager(String account, boolean isRemoveManager) { + } + + @Override + public void addMemberBlack() { + if (!isResumed()) return; + if (!isShowToUser()) return; + firstLoad(); + } + + public boolean isShowToUser() { + return isShowToUser; + } + +} diff --git a/app/src/main/java/com/chwl/app/avroom/fragment/PartyRoomFragment.kt b/app/src/main/java/com/chwl/app/avroom/fragment/PartyRoomFragment.kt new file mode 100644 index 0000000..e9501cd --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/fragment/PartyRoomFragment.kt @@ -0,0 +1,34 @@ +package com.chwl.app.avroom.fragment + +import com.chwl.app.avroom.adapter.BaseMicroViewAdapter +import com.chwl.app.avroom.adapter.PartyMicroViewAdapter +import com.example.lib_utils.UiUtils +import com.example.lib_utils.ktx.setMargin + +/** + * 聚会房 + */ +class PartyRoomFragment : HomePartyRoomFragment() { + + companion object { + fun newInstance(): PartyRoomFragment { + return PartyRoomFragment() + } + } + + override fun onFindViews() { + super.onFindViews() + microView.setMargin(0,UiUtils.dip2px(30f),0,0) + } + + override fun updateMicroView() { + val microType = + if (microView.adapter == null) BaseMicroViewAdapter.MICRO_TYPE_NULL else microView.adapter.microType() + if (microType != BaseMicroViewAdapter.MICRO_TYPE_PARTY) { + microView.bindAdapter(PartyMicroViewAdapter(mContext)) + } + if (microView.adapter != null) { + microView.adapter.notifyDataSetChanged() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/fragment/RevelryRoomFragment.kt b/app/src/main/java/com/chwl/app/avroom/fragment/RevelryRoomFragment.kt new file mode 100644 index 0000000..916575f --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/fragment/RevelryRoomFragment.kt @@ -0,0 +1,34 @@ +package com.chwl.app.avroom.fragment + +import com.chwl.app.avroom.adapter.BaseMicroViewAdapter +import com.chwl.app.avroom.adapter.RevelryMicroViewAdapter +import com.example.lib_utils.UiUtils +import com.example.lib_utils.ktx.setMargin + +/** + * 狂欢房 + */ +class RevelryRoomFragment : HomePartyRoomFragment() { + + companion object { + fun newInstance(): RevelryRoomFragment { + return RevelryRoomFragment() + } + } + + override fun onFindViews() { + super.onFindViews() + microView.setMargin(0, UiUtils.dip2px(30f),0,0) + } + + override fun updateMicroView() { + val microType = + if (microView.adapter == null) BaseMicroViewAdapter.MICRO_TYPE_NULL else microView.adapter.microType() + if (microType != BaseMicroViewAdapter.MICRO_TYPE_REVELRY) { + microView.bindAdapter(RevelryMicroViewAdapter(mContext)) + } + if (microView.adapter != null) { + microView.adapter.notifyDataSetChanged() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/fragment/Room19Fragment.kt b/app/src/main/java/com/chwl/app/avroom/fragment/Room19Fragment.kt new file mode 100644 index 0000000..e383fc2 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/fragment/Room19Fragment.kt @@ -0,0 +1,33 @@ +package com.chwl.app.avroom.fragment + +import com.chwl.app.avroom.adapter.BaseMicroViewAdapter +import com.chwl.app.avroom.adapter.Mic19ViewAdapter +import com.example.lib_utils.UiUtils +import com.example.lib_utils.ktx.setMargin + +/** + * 十九麦房 + */ +class Room19Fragment : HomePartyRoomFragment() { + + companion object { + fun newInstance(): Room19Fragment { + return Room19Fragment() + } + } + + override fun onFindViews() { + super.onFindViews() + microView.setMargin(0, UiUtils.dip2px(30f),0,0) + } + + override fun updateMicroView() { + val microType = if (microView.adapter == null) BaseMicroViewAdapter.MICRO_TYPE_NULL else microView.adapter.microType() + if (microType != BaseMicroViewAdapter.MICRO_TYPE_REVELRY_19) { + microView.bindAdapter(Mic19ViewAdapter(mContext)) + } + if (microView.adapter != null) { + microView.adapter.notifyDataSetChanged() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/fragment/Room20Fragment.kt b/app/src/main/java/com/chwl/app/avroom/fragment/Room20Fragment.kt new file mode 100644 index 0000000..f0ae98b --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/fragment/Room20Fragment.kt @@ -0,0 +1,33 @@ +package com.chwl.app.avroom.fragment + +import com.chwl.app.avroom.adapter.BaseMicroViewAdapter +import com.chwl.app.avroom.adapter.Mic20ViewAdapter +import com.example.lib_utils.UiUtils +import com.example.lib_utils.ktx.setMargin + +/** + * 二十麦房 + */ +class Room20Fragment : HomePartyRoomFragment() { + + companion object { + fun newInstance(): Room20Fragment { + return Room20Fragment() + } + } + + override fun onFindViews() { + super.onFindViews() + microView.setMargin(0, UiUtils.dip2px(30f),0,0) + } + + override fun updateMicroView() { + val microType = if (microView.adapter == null) BaseMicroViewAdapter.MICRO_TYPE_NULL else microView.adapter.microType() + if (microType != BaseMicroViewAdapter.MICRO_TYPE_REVELRY_20) { + microView.bindAdapter(Mic20ViewAdapter(mContext)) + } + if (microView.adapter != null) { + microView.adapter.notifyDataSetChanged() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/fragment/RoomCharmListFragment.java b/app/src/main/java/com/chwl/app/avroom/fragment/RoomCharmListFragment.java new file mode 100644 index 0000000..cfa332f --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/fragment/RoomCharmListFragment.java @@ -0,0 +1,41 @@ +package com.chwl.app.avroom.fragment; + +import androidx.fragment.app.Fragment; + +import com.chwl.app.R; +import com.chwl.app.avroom.adapter.CommonVPAdapter; +import com.chwl.app.avroom.adapter.RoomContributeListAdapter; +import com.chwl.app.avroom.widget.RankNavigatorAdapter; +import com.chwl.app.base.BaseBindingFragment; +import com.chwl.app.databinding.FragmentRoomCharmListBinding; +import com.chwl.app.ui.widget.magicindicator.ViewPagerHelper; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.CommonNavigator; +import com.chwl.core.room.bean.RoomContributeDataInfo; +import com.chwl.library.annatation.ActLayoutRes; + +import java.util.ArrayList; + +@ActLayoutRes(R.layout.fragment_room_charm_list) +public class RoomCharmListFragment extends BaseBindingFragment { + + public static RoomCharmListFragment newInstance() { + return new RoomCharmListFragment(); + } + + @Override + public void initiate() { + ArrayList fragments = new ArrayList<>(2); + fragments.add(RoomCharmRankingListFragment.newInstance(RoomContributeDataInfo.TYPE_ROOM_DAY_RANKING)); + fragments.add(RoomCharmRankingListFragment.newInstance(RoomContributeDataInfo.TYPE_ROOM_WEEK_RANKING)); + mBinding.vpCharmRankings.setAdapter(new CommonVPAdapter(getChildFragmentManager(), getLifecycle(),fragments)); + CommonNavigator commonNavigator = new CommonNavigator(getActivity()); + commonNavigator.setAdjustMode(false); + + RankNavigatorAdapter indicator = new RankNavigatorAdapter(false); + indicator.setOnItemSelectListener(position -> mBinding.vpCharmRankings.setCurrentItem(position)); + commonNavigator.setAdapter(indicator); + mBinding.viewIndicator.setNavigator(commonNavigator); + ViewPagerHelper.bind(mBinding.viewIndicator, mBinding.vpCharmRankings); + } + +} diff --git a/app/src/main/java/com/chwl/app/avroom/fragment/RoomCharmRankingListFragment.java b/app/src/main/java/com/chwl/app/avroom/fragment/RoomCharmRankingListFragment.java new file mode 100644 index 0000000..57fe02e --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/fragment/RoomCharmRankingListFragment.java @@ -0,0 +1,176 @@ +package com.chwl.app.avroom.fragment; + +import android.os.Bundle; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; + +import androidx.fragment.app.Fragment; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chwl.app.R; +import com.chwl.app.avroom.adapter.RoomConsumerListAdapterTemp; +import com.chwl.app.avroom.presenter.RoomCharmRankingPresenter; +import com.chwl.app.avroom.view.IRoomCharmRankingListView; +import com.chwl.app.base.BaseMvpFragment; +import com.chwl.app.ui.widget.GiftDialog; +import com.chwl.app.ui.widget.UserInfoDialog; +import com.chwl.core.Constants; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.room.bean.RoomContributeUserInfo; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.core.room.bean.RoomRankMultiItem; +import com.chwl.library.base.factory.CreatePresenter; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; +import com.netease.nim.uikit.common.util.sys.NetworkUtil; +import com.scwang.smart.refresh.layout.SmartRefreshLayout; +import com.scwang.smart.refresh.layout.api.RefreshLayout; +import com.scwang.smart.refresh.layout.listener.OnRefreshLoadMoreListener; + +import java.util.List; + +; +; + +@CreatePresenter(RoomCharmRankingPresenter.class) +public class RoomCharmRankingListFragment extends BaseMvpFragment + implements IRoomCharmRankingListView, BaseQuickAdapter.OnItemClickListener, RoomConsumerListAdapterTemp.RoomConsumerTopThreeListener { + public static final String KEY_TYPE = "type"; + + private RoomConsumerListAdapterTemp mConsumeListAdapter; + private RecyclerView mRecyclerView; + private SmartRefreshLayout mRefreshLayout; + + private View mEmptyView; + private int page = 1; + private boolean isLoadMore = false; + + public static Fragment newInstance(String type) { + Fragment fragment = new RoomCharmRankingListFragment(); + Bundle bundle = new Bundle(); + bundle.putString(KEY_TYPE, type); + fragment.setArguments(bundle); + return fragment; + } + + @Override + public void onFindViews() { + mEmptyView = LayoutInflater.from(mContext).inflate(R.layout.list_item_room_consume_list_empty, null, false); + mRecyclerView = mView.findViewById(R.id.recycler_view); + mRefreshLayout = mView.findViewById(R.id.refresh_layout); + } + + @Override + public void onSetListener() { + mRefreshLayout.setEnableLoadMore(true); + mRefreshLayout.setOnRefreshLoadMoreListener(new OnRefreshLoadMoreListener() { + @Override + public void onLoadMore(RefreshLayout refreshLayout) { + if (!NetworkUtil.isNetAvailable(mContext)) { + mRefreshLayout.finishLoadMore(); + return; + } + List data = mConsumeListAdapter.getData(); + if (ListUtils.isListEmpty(data)) { + mRefreshLayout.finishLoadMore(); + return; + } + page++; + isLoadMore = true; + loadData(); + } + + @Override + public void onRefresh(RefreshLayout refreshLayout) { + if (!NetworkUtil.isNetAvailable(mContext)) { + mRefreshLayout.finishRefresh(); + return; + } + firstLoad(); + } + }); + } + + public void firstLoad() { + isLoadMore = false; + page = Constants.PAGE_START; + loadData(); + } + + @Override + public void initiate() { + mRecyclerView.setLayoutManager(new LinearLayoutManager(mContext)); + mConsumeListAdapter = new RoomConsumerListAdapterTemp(mContext); + mConsumeListAdapter.setmRoomConsumerTopThreeListener(this); + mRecyclerView.setAdapter(mConsumeListAdapter); + mConsumeListAdapter.setOnItemClickListener(this); + mRefreshLayout.setEnableRefresh(true); + mRefreshLayout.setEnableLoadMore(true); + mRefreshLayout.autoRefresh(100); + } + + + @Override + public void onItemClick(BaseQuickAdapter baseQuickAdapter, View view, int i) { + List list = mConsumeListAdapter.getData(); + if (ListUtils.isListEmpty(list)) { + return; + } + RoomRankMultiItem item = list.get(i); + if (item != null && item.getItemType() != RoomContributeUserInfo.TYPE_GRID) { + RoomContributeUserInfo info = (RoomContributeUserInfo) item.getData(); + if (info == null) return; + if (info.isHide()) return; + if (info.isEmptyBean()) return; + showUserInfoDialog(info.getUid()); + } + } + + private void showUserInfoDialog(long uid) { + + GiftDialog.GIFT_DIALOG_FROM = ResUtil.getString(R.string.avroom_fragment_roomcharmrankinglistfragment_01); + UserInfoDialog.showNewUserInfoDialog(mContext, uid); + } + + private void loadData(){ + String type = getArguments().getString(KEY_TYPE); + RoomInfo mCurrentRoomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (mCurrentRoomInfo == null){ + mRefreshLayout.finishRefresh(); + return; + } + + getMvpPresenter().getRoomCharmList(page, type); + } + + @Override + public void topThreeListener(long uid) { + showUserInfoDialog(uid); + } + + @Override + public int getRootLayoutId() { + return R.layout.common_refresh_recycler_view; + } + + @Override + public void roomCharmListSuccess(List list) { + if (isLoadMore){ + mRefreshLayout.finishLoadMore(); + mConsumeListAdapter.addData(list); + }else { + mRefreshLayout.finishRefresh(); + mConsumeListAdapter.setNewData(list); + } + } + + @Override + public void roomCharListFail(String message) { + mRefreshLayout.finishRefresh(); + if (!TextUtils.isEmpty(message)) + toast(message); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/fragment/RoomContributeFragment.java b/app/src/main/java/com/chwl/app/avroom/fragment/RoomContributeFragment.java new file mode 100644 index 0000000..5ea00ca --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/fragment/RoomContributeFragment.java @@ -0,0 +1,206 @@ +package com.chwl.app.avroom.fragment; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chwl.app.R; +import com.chwl.app.avroom.adapter.RoomConsumerListAdapterTemp; +import com.chwl.app.avroom.presenter.RoomContributeListPresenter; +import com.chwl.app.avroom.view.IRoomContributeListView; +import com.chwl.app.base.BaseMvpFragment; +import com.chwl.app.ui.widget.UserInfoDialog; +import com.chwl.core.Constants; +import com.chwl.core.room.bean.RoomContributeDataInfo; +import com.chwl.core.room.bean.RoomContributeUserInfo; +import com.chwl.core.room.bean.RoomRankMultiItem; +import com.chwl.library.base.factory.CreatePresenter; +import com.chwl.library.utils.ListUtils; +import com.netease.nim.uikit.common.util.sys.NetworkUtil; +import com.scwang.smart.refresh.layout.SmartRefreshLayout; +import com.scwang.smart.refresh.layout.api.RefreshLayout; +import com.scwang.smart.refresh.layout.listener.OnRefreshLoadMoreListener; + +import java.util.ArrayList; +import java.util.List; + +; +; + +/** + *

房间贡献榜用户列表

+ * + * @author Administrator + * @date 2017/12/4 + */ +@CreatePresenter(RoomContributeListPresenter.class) +public class RoomContributeFragment extends BaseMvpFragment + implements IRoomContributeListView, BaseQuickAdapter.OnItemClickListener, RoomConsumerListAdapterTemp.RoomConsumerTopThreeListener { + + public static final String KEY_TYPE = "type"; + + private String type; + private List dataInfoList; + private RecyclerView mRecyclerView; + private SmartRefreshLayout mRefreshLayout; + private RoomConsumerListAdapterTemp mConsumeListAdapter; + private View mEmptyView; + private int page = 1; + + public static RoomContributeFragment newInstance(String type) { + RoomContributeFragment roomContributeFragment = new RoomContributeFragment(); + Bundle bundle = new Bundle(); + bundle.putString(KEY_TYPE, type); + roomContributeFragment.setArguments(bundle); + return roomContributeFragment; + } + + @Override + protected void onInitArguments(Bundle bundle) { + type = bundle.getString(KEY_TYPE); + } + + @Override + public void onFindViews() { + mRecyclerView = mView.findViewById(R.id.recycler_view); + mRefreshLayout = mView.findViewById(R.id.refresh_layout); + } + + @Override + public void onSetListener() { + mRefreshLayout.setEnableLoadMore(true); + mRefreshLayout.setOnRefreshLoadMoreListener(new OnRefreshLoadMoreListener() { + @Override + public void onLoadMore(RefreshLayout refreshLayout) { + if (!NetworkUtil.isNetAvailable(mContext)) { + mRefreshLayout.finishLoadMore(); + return; + } + List data = mConsumeListAdapter.getData(); + if (ListUtils.isListEmpty(data)) { + mRefreshLayout.finishLoadMore(); + return; + } + loadData(); + } + + @Override + public void onRefresh(RefreshLayout refreshLayout) { + if (!NetworkUtil.isNetAvailable(mContext)) { + mRefreshLayout.finishRefresh(); + return; + } + firstLoad(); + } + }); + } + + @Override + public void initiate() { + mEmptyView = LayoutInflater.from(mContext).inflate(R.layout.list_item_room_consume_list_empty, null, false); + mRecyclerView.setLayoutManager(new LinearLayoutManager(mContext)); + mConsumeListAdapter = new RoomConsumerListAdapterTemp(mContext); + mConsumeListAdapter.setmRoomConsumerTopThreeListener(this); + mRecyclerView.setAdapter(mConsumeListAdapter); + mConsumeListAdapter.setOnItemClickListener(this); + + mRefreshLayout.autoRefresh(100); + } + + @Override + public int getRootLayoutId() { + return R.layout.common_refresh_recycler_view; + } + + public void firstLoad() { + page = Constants.PAGE_START; + loadData(); + } + + public void loadData() { + getMvpPresenter().getSingleRoomRanking(page, type); + } + + @Override + public void onItemClick(BaseQuickAdapter baseQuickAdapter, View view, int i) { + List list = mConsumeListAdapter.getData(); + if (ListUtils.isListEmpty(list)) { + return; + } + RoomRankMultiItem item = list.get(i); + if (item != null && item.getItemType() != RoomContributeUserInfo.TYPE_GRID) { + RoomContributeUserInfo info = (RoomContributeUserInfo) item.getData(); + if (info == null) return; + if (info.isHide()) return; + if (info.isEmptyBean()) return; + showUserInfoDialog(info.getUid()); + } + } + + private void showUserInfoDialog(long uid) { + UserInfoDialog.showNewUserInfoDialog(mContext, uid); + } + + @Override + public void getSingleRankingSuccess(RoomContributeDataInfo roomContributeDataInfo) { + List list = roomContributeDataInfo.getRankings(); + if (!ListUtils.isListEmpty(list)) { + if (page == Constants.PAGE_START) { + dataInfoList = roomContributeDataInfo.getRankings(); + setContributeDataView(roomContributeDataInfo); + mRefreshLayout.finishRefresh(); + } else { + dataInfoList.addAll(list); + addRoomContributeData(list); + mRefreshLayout.finishLoadMore(0); + } + page++; + } else { + if (page == Constants.PAGE_START) { + dataInfoList = null; + mRefreshLayout.finishRefresh(); + setContributeDataView(roomContributeDataInfo); + } else { + mRefreshLayout.finishLoadMore(0); + } + } + } + + private void setContributeDataView(RoomContributeDataInfo roomContributeDataInfo) { + List list = roomContributeDataInfo.getRankings(); + if (list == null) { + list = new ArrayList<>(); + } + + mConsumeListAdapter.setNewData(getMvpPresenter().handleList(list)); + } + + private void addRoomContributeData(List list) { + + for (RoomContributeUserInfo info : list) { + RoomRankMultiItem item = new RoomRankMultiItem(); + item.setData(info); + item.setItemType(RoomRankMultiItem.TYPE_LINEAR); + mConsumeListAdapter.addData(item); + } + + } + + @Override + public void getSingleRakingFail(int errorCode, String errorMsg) { + if (page == Constants.PAGE_START) { + mRefreshLayout.finishRefresh(); + } else { + mRefreshLayout.finishLoadMore(0); + } + } + + @Override + public void topThreeListener(long uid) { + showUserInfoDialog(uid); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/fragment/RoomContributeListFragment.java b/app/src/main/java/com/chwl/app/avroom/fragment/RoomContributeListFragment.java new file mode 100644 index 0000000..cb9d164 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/fragment/RoomContributeListFragment.java @@ -0,0 +1,63 @@ +package com.chwl.app.avroom.fragment; + +import androidx.fragment.app.Fragment; +import androidx.viewpager.widget.ViewPager; +import androidx.viewpager2.widget.ViewPager2; + +import com.chwl.app.R; +import com.chwl.app.avroom.adapter.CommonVPAdapter; +import com.chwl.app.avroom.adapter.RoomContributeListAdapter; +import com.chwl.app.avroom.widget.RankNavigatorAdapter; +import com.chwl.app.base.BaseMvpFragment; +import com.chwl.app.ui.widget.magicindicator.MagicIndicator; +import com.chwl.app.ui.widget.magicindicator.ViewPagerHelper; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.CommonNavigator; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.room.bean.RoomContributeDataInfo; +import com.chwl.library.base.IMvpBaseView; + +import java.util.ArrayList; + +/** + * Created by MadisonRong on 25/04/2018. + */ +public class RoomContributeListFragment extends BaseMvpFragment implements IMvpBaseView { + + private ViewPager2 viewPager; + private MagicIndicator viewIndicator; + + @Override + public void onFindViews() { + viewIndicator = mView.findViewById(R.id.view_indicator); + viewPager = mView.findViewById(R.id.vp_contribute_rankings); + } + + @Override + public void onSetListener() { + + } + + @Override + public void initiate() { + ArrayList fragments = new ArrayList<>(2); + fragments.add(RoomContributeFragment.newInstance(RoomContributeDataInfo.TYPE_ROOM_DAY_RANKING)); + fragments.add(RoomContributeFragment.newInstance(RoomContributeDataInfo.TYPE_ROOM_WEEK_RANKING)); + if (AvRoomDataManager.get().isDatingMode()) { + fragments.add(RoomContributeFragment.newInstance(RoomContributeDataInfo.TYPE_ROOM_MONTH_RANKING)); + } + viewPager.setAdapter(new CommonVPAdapter(getChildFragmentManager(),getLifecycle(), fragments)); + CommonNavigator commonNavigator = new CommonNavigator(getActivity()); + commonNavigator.setAdjustMode(false); + RankNavigatorAdapter indicator = new RankNavigatorAdapter(AvRoomDataManager.get().isDatingMode()); + indicator.setOnItemSelectListener(position -> viewPager.setCurrentItem(position)); + commonNavigator.setAdapter(indicator); + viewIndicator.setNavigator(commonNavigator); + ViewPagerHelper.bind(viewIndicator, viewPager); + } + + @Override + public int getRootLayoutId() { + return R.layout.fragment_room_contribute; + } + +} diff --git a/app/src/main/java/com/chwl/app/avroom/fragment/RoomRankDialogFragment.java b/app/src/main/java/com/chwl/app/avroom/fragment/RoomRankDialogFragment.java new file mode 100644 index 0000000..209c04f --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/fragment/RoomRankDialogFragment.java @@ -0,0 +1,99 @@ +package com.chwl.app.avroom.fragment; + +import android.app.Dialog; +import android.os.Bundle; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatDialogFragment; +import androidx.fragment.app.Fragment; +import androidx.viewpager.widget.ViewPager; + +import com.chwl.app.R; +import com.chwl.app.avroom.adapter.RoomRankFragmentPageAdapter; + +import java.util.ArrayList; +import java.util.List; + +public class RoomRankDialogFragment extends AppCompatDialogFragment implements IRoomRankDialogDismissListener, IRoomRankDialogChangePageListener { + + private ViewPager mViewPager; + + + public static RoomRankDialogFragment newInstance() { + Bundle args = new Bundle(); + RoomRankDialogFragment fragment = new RoomRankDialogFragment(); + fragment.setArguments(args); + return fragment; + } + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + if (getActivity() != null) { + Dialog dialog = new Dialog(getActivity(), R.style.room_rank_dialog); + dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); + dialog.setContentView(R.layout.dialog_fragment_room_rank); + dialog.setCanceledOnTouchOutside(true); + + // 设置弹出框布局参数,宽度铺满全屏,底部。 + Window window = dialog.getWindow(); + if (window != null) { + WindowManager.LayoutParams wlp = window.getAttributes(); + wlp.gravity = Gravity.BOTTOM; + wlp.width = WindowManager.LayoutParams.MATCH_PARENT; + wlp.height = WindowManager.LayoutParams.WRAP_CONTENT; + window.setDimAmount(0.3f); + window.setAttributes(wlp); + window.setBackgroundDrawableResource(R.drawable.bg_room_rank); + return dialog; + } else { + return super.onCreateDialog(savedInstanceState); + } + } else { + return super.onCreateDialog(savedInstanceState); + } + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.dialog_fragment_room_rank, container, false); + mViewPager = view.findViewById(R.id.vp_room_rank); + List fragmentList = new ArrayList<>(); + if (getChildFragmentManager().getFragments() != null && getChildFragmentManager().getFragments().size() != 0) { + fragmentList = getChildFragmentManager().getFragments(); + } else { + RoomRankListFragment roomInsideFragment = RoomRankListFragment.newInstance(); + roomInsideFragment.setDismissListener(this); + roomInsideFragment.setChangePageListener(this); + fragmentList.add(roomInsideFragment); + } + mViewPager.setAdapter(new RoomRankFragmentPageAdapter(getChildFragmentManager(), fragmentList)); + mViewPager.setOffscreenPageLimit(fragmentList.size()); + mViewPager.setCurrentItem(0, false); + return view; + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setCancelable(true); + } + + @Override + public void onDismiss() { + dismiss(); + } + + @Override + public void onChangePage(int pos) { + mViewPager.setCurrentItem(pos, false); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/fragment/RoomRankDialogUtils.java b/app/src/main/java/com/chwl/app/avroom/fragment/RoomRankDialogUtils.java new file mode 100644 index 0000000..85694a4 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/fragment/RoomRankDialogUtils.java @@ -0,0 +1,65 @@ +package com.chwl.app.avroom.fragment; + +import com.chwl.app.R; +import com.chwl.library.utils.ResUtil; + +import java.math.BigDecimal; + +public class RoomRankDialogUtils { + public static String getRoomRankValueText(int value) { + if (value >= 10000) { + BigDecimal bigDecimal = new BigDecimal(value / 10000.0); + double doubleValue = bigDecimal.setScale(1, BigDecimal.ROUND_HALF_UP).doubleValue(); + return String.valueOf(doubleValue) + ResUtil.getString(R.string.avroom_fragment_roomrankdialogutils_01); + } else { + return String.valueOf(value); + } + } + + public static int getNumberImage(int number) { + switch (number) { + case 1: + return R.drawable.ic_rank_1; + case 2: + return R.drawable.ic_rank_2; + case 3: + return R.drawable.ic_rank_3; + case 4: + return R.drawable.ic_rank_4; + case 5: + return R.drawable.ic_rank_5; + case 6: + return R.drawable.ic_rank_6; + case 7: + return R.drawable.ic_rank_7; + case 8: + return R.drawable.ic_rank_8; + case 9: + return R.drawable.ic_rank_9; + case 10: + return R.drawable.ic_rank_10; + case 11: + return R.drawable.ic_rank_11; + case 12: + return R.drawable.ic_rank_12; + case 13: + return R.drawable.ic_rank_13; + case 14: + return R.drawable.ic_rank_14; + case 15: + return R.drawable.ic_rank_15; + case 16: + return R.drawable.ic_rank_16; + case 17: + return R.drawable.ic_rank_17; + case 18: + return R.drawable.ic_rank_18; + case 19: + return R.drawable.ic_rank_19; + case 20: + return R.drawable.ic_rank_20; + default: + return 0; + } + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/fragment/RoomRankListFragment.java b/app/src/main/java/com/chwl/app/avroom/fragment/RoomRankListFragment.java new file mode 100644 index 0000000..cf07c46 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/fragment/RoomRankListFragment.java @@ -0,0 +1,81 @@ +package com.chwl.app.avroom.fragment; + +import android.view.View; + +import androidx.fragment.app.Fragment; + +import com.chwl.app.R; +import com.chwl.app.avroom.adapter.CommonVPAdapter; +import com.chwl.app.avroom.adapter.RoomContributeListAdapter; +import com.chwl.app.avroom.widget.RoomRankNavigatorAdapter; +import com.chwl.app.base.BaseBindingFragment; +import com.chwl.app.databinding.FragmentRoomRankListBinding; +import com.chwl.app.ui.widget.magicindicator.ViewPagerHelper; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.CommonNavigator; +import com.chwl.library.annatation.ActLayoutRes; + +import java.util.ArrayList; +import java.util.List; + +@ActLayoutRes(R.layout.fragment_room_rank_list) +public class RoomRankListFragment extends BaseBindingFragment implements View.OnClickListener, IRoomRankDialogDismissListener{ + + public static RoomRankListFragment newInstance() { + return new RoomRankListFragment(); + } + + @Override + public void initiate() { + mBinding.setClick(this); + List list = new ArrayList<>(2); + list.add(new RoomContributeListFragment()); + list.add(RoomCharmListFragment.newInstance()); + mBinding.viewPager.setAdapter(new CommonVPAdapter(getChildFragmentManager(), getLifecycle(), list)); + + CommonNavigator commonNavigator = new CommonNavigator(getActivity()); + commonNavigator.setAdjustMode(true); + + RoomRankNavigatorAdapter indicator = new RoomRankNavigatorAdapter(); + indicator.setOnItemSelectListener(position -> mBinding.viewPager.setCurrentItem(position)); + commonNavigator.setAdapter(indicator); + mBinding.miRoomRank.setNavigator(commonNavigator); + ViewPagerHelper.bind(mBinding.miRoomRank, mBinding.viewPager); + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.tv_room_rank_half_hour_tab: + goToChangePage(0); + break; + + case R.id.tv_room_rank_in_room_tab: + goToChangePage(1); + break; + } + } + + private IRoomRankDialogDismissListener dismissListener; + private IRoomRankDialogChangePageListener changePageListener; + @Override + public void onDismiss() { + if (dismissListener != null) { + dismissListener.onDismiss(); + } + } + public void setDismissListener(IRoomRankDialogDismissListener dismissListener) { + this.dismissListener = dismissListener; + } + /** + * 修改最外层Dialog的显示页面 + */ + private void goToChangePage(int pos) { + if (changePageListener != null) { + changePageListener.onChangePage(pos); + } + } + + public void setChangePageListener(IRoomRankDialogChangePageListener changePageListener) { + this.changePageListener = changePageListener; + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/fragment/RoomTitleDialogFragment.java b/app/src/main/java/com/chwl/app/avroom/fragment/RoomTitleDialogFragment.java new file mode 100644 index 0000000..ca2e014 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/fragment/RoomTitleDialogFragment.java @@ -0,0 +1,82 @@ +package com.chwl.app.avroom.fragment; + +import android.os.Bundle; +import android.text.TextUtils; +import android.text.method.ScrollingMovementMethod; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.DialogFragment; + +import com.chwl.app.R; +import com.chwl.library.utils.ResUtil; + +public class RoomTitleDialogFragment extends DialogFragment { + + public static DialogFragment getInstance(String title, String desc) { + DialogFragment dialogFragment = new RoomTitleDialogFragment(); + Bundle bundle = new Bundle(); + bundle.putString("title", title); + bundle.putString("desc", desc); + dialogFragment.setArguments(bundle); + return dialogFragment; + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setStyle(DialogFragment.STYLE_NO_TITLE, R.style.DialogFragment); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View root = inflater.inflate(R.layout.fragment_dialog_room_title, container); + + TextView tvTitle = root.findViewById(R.id.tv_title); + + TextView textView = root.findViewById(R.id.tv_dialog_desc); + textView.setMovementMethod(ScrollingMovementMethod.getInstance()); + + String title = null; + String desc = null; + Bundle bundle = getArguments(); + if (bundle != null) { + title = bundle.getString("title", ""); + desc = bundle.getString("desc", ""); + } + + if (TextUtils.isEmpty(title)) + title = ResUtil.getString(R.string.avroom_fragment_roomtitledialogfragment_01); + + if (TextUtils.isEmpty(desc)) + desc = ResUtil.getString(R.string.avroom_fragment_roomtitledialogfragment_02); + + tvTitle.setText(title); + textView.setText(desc); + + root.findViewById(R.id.tv_close).setOnClickListener(v -> { + dismiss(); + }); + + return root; + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + Window window = getDialog().getWindow(); + if (window != null) { + window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + window.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT); + } + + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/fragment/SingleRoomFragment.kt b/app/src/main/java/com/chwl/app/avroom/fragment/SingleRoomFragment.kt new file mode 100644 index 0000000..9a23a4e --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/fragment/SingleRoomFragment.kt @@ -0,0 +1,245 @@ +package com.chwl.app.avroom.fragment + +import android.annotation.SuppressLint +import android.os.Bundle +import android.view.View +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.view.isVisible +import androidx.core.view.updateLayoutParams +import androidx.databinding.DataBindingUtil +import androidx.fragment.app.viewModels +import com.chwl.app.R +import com.chwl.app.avroom.adapter.OnMicroItemClickListener +import com.chwl.app.avroom.adapter.SingleAnchorMicroViewAdapter +import com.chwl.app.avroom.adapter.SingleRoomPKMicroViewAdapter +import com.chwl.app.avroom.dialog.RequestUpMicDialog +import com.chwl.app.avroom.headline.RoomHeadlineWidget +import com.chwl.app.avroom.online.RoomOnlineWidget +import com.chwl.app.avroom.presenter.SingleRoomPresenter +import com.chwl.app.avroom.rank.RoomRankNumberWidget +import com.chwl.app.avroom.singleroompk.SingleRoomPkFinishDialog +import com.chwl.app.avroom.singleroompk.SingleRoomPkForceFinishDialog +import com.chwl.app.avroom.singleroompk.SingleRoomPkReceivedDialog +import com.chwl.app.avroom.view.ISingleRoomView +import com.chwl.app.databinding.FragmentSingleRoomBinding +import com.chwl.app.fansteam.FansTeamJoinActivity +import com.chwl.app.fansteam.FansTeamJoinedActivity +import com.chwl.app.fansteam.FansTeamViewModel +import com.chwl.app.ui.webview.CommonWebViewActivity +import com.chwl.app.ui.webview.DialogWebViewActivity +import com.chwl.core.UriProvider +import com.chwl.core.auth.AuthModel +import com.chwl.core.fansteam.bean.FansTeamInitInfo +import com.chwl.core.im.custom.bean.FansTeamMsgAttachment +import com.chwl.core.im.custom.bean.RequestUpmicAttachment +import com.chwl.core.im.custom.bean.RoomPKAttachment +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.manager.RoomEvent +import com.chwl.core.user.bean.UserInfo +import com.chwl.library.base.factory.CreatePresenter +import com.netease.nim.uikit.common.util.sys.ScreenUtil + +/** + * 個播房間 + * + * @author chenran + * @date 2017/7/26 + */ +@CreatePresenter(SingleRoomPresenter::class) +class SingleRoomFragment : BaseRoomFragment(), + ISingleRoomView, OnMicroItemClickListener { + + companion object { + @JvmStatic + fun newInstance(): SingleRoomFragment { + val roomFragment = SingleRoomFragment() + val bundle = Bundle() + roomFragment.arguments = bundle + return roomFragment + } + } + + private lateinit var gameBinding: FragmentSingleRoomBinding + private lateinit var upMicDialog: RequestUpMicDialog + + + private val fansTeamViewModel: FansTeamViewModel by viewModels() + override fun getRootLayoutId(): Int { + return R.layout.fragment_single_room + } + + override fun onFindViews() { + super.onFindViews() + gameBinding = DataBindingUtil.bind(mView)!! + gameBinding.lifecycleOwner = this + gameBinding.click = this + } + + + @SuppressLint("CheckResult") + override fun initiate() { + super.initiate() + gameBinding.layoutHourRank.setOnClickListener { + DialogWebViewActivity.start( + mContext, + UriProvider.getSingleRoomHourRankUrl(AvRoomDataManager.get().roomUid) + ) + } + fansTeamViewModel.loadFansTeamInitInfo() + + fansTeamViewModel.fansTeamInitInfoLiveData.observe(viewLifecycleOwner) { + it?.let { + updateFansTeamInfo(it) + } + } + } + + override fun onReceiveRoomEvent(roomEvent: RoomEvent?) { + super.onReceiveRoomEvent(roomEvent) + if (roomEvent == null) return + when (roomEvent.event) { + RoomEvent.REQUEST_UP_MIC -> { + (roomEvent.chatRoomMessage?.attachment as? RequestUpmicAttachment)?.userInfo?.let { + showInviteDialog(it) + } + } + RoomEvent.ROOM_PK_INVITE -> + SingleRoomPkReceivedDialog.newInstance((roomEvent.chatRoomMessage.attachment as RoomPKAttachment).roomPkBean) + .show(mContext) + RoomEvent.ROOM_PK_FINISH -> { + val roomPkBean = + (roomEvent.chatRoomMessage.attachment as RoomPKAttachment).roomPkBean + if (roomPkBean.isForce) { + SingleRoomPkForceFinishDialog.newInstance(roomPkBean).show(mContext) + } else { + SingleRoomPkFinishDialog.newInstance(roomPkBean).show(mContext) + } + gameBinding.microView.adapter?.notifyDataSetChanged() + } + + RoomEvent.FANS_TEAM_OPEN_SUCCESS, + RoomEvent.FANS_TEAM_OPEN_FAILED, + RoomEvent.FANS_TEAM_JOIN, + RoomEvent.FANS_TEAM_EXIT -> { + (roomEvent.chatRoomMessage?.attachment as? FansTeamMsgAttachment)?.fansTeamMsgInfo?.let { + val currFansTeamInitInfo = fansTeamViewModel.fansTeamInitInfoLiveData.value + updateFansTeamInfo( + FansTeamInitInfo( + it.count, + currFansTeamInitInfo?.fansLevelSeq ?: 1, + roomEvent.event != RoomEvent.FANS_TEAM_OPEN_FAILED, + if (AuthModel.get().currentUid == it.uid) { + roomEvent.event == RoomEvent.FANS_TEAM_JOIN + } else { + currFansTeamInitInfo?.isAnchorFans ?: false + }, + AvRoomDataManager.get().isRoomOwner, + roomEvent.event == RoomEvent.FANS_TEAM_OPEN_FAILED + ) + ) + } + } + } + } + + @SuppressLint("SetTextI18n") + private fun updateFansTeamInfo(initInfo: FansTeamInitInfo) { + var clickListener: View.OnClickListener? = null + if (initInfo.hasFansTeamCurrentRoom) { + if (AvRoomDataManager.get().isRoomOwner) { + gameBinding.flFansTeamJoinTip.isVisible = false + gameBinding.tvFansTeamOpt.isVisible = true + gameBinding.tvFansTeamOpt.text = String.format(getString(R.string.fans_team_4),"${initInfo.anchorFansNum}") + clickListener = View.OnClickListener { + DialogWebViewActivity.start( + requireContext(), + UriProvider.getFansTeamMyFansUrl(AvRoomDataManager.get().roomUid) + ) + } + } else { + if (initInfo.isAnchorFans) { + gameBinding.flFansTeamJoinTip.isVisible = false + gameBinding.tvFansTeamOpt.isVisible = true + val level = if (initInfo.fansLevelSeq == 0) 1 else initInfo.fansLevelSeq + val levelStr = + String.format(requireContext().getString(R.string.fans_team_5), level.toString()) + gameBinding.tvFansTeamOpt.text = levelStr + clickListener = View.OnClickListener { + FansTeamJoinedActivity.start(requireContext()) + } + } else { + gameBinding.flFansTeamJoinTip.isVisible = true + gameBinding.tvFansTeamOpt.isVisible = false + clickListener = View.OnClickListener { + FansTeamJoinActivity.start(requireContext()) + } + } + } + } else { + if (AvRoomDataManager.get().isRoomOwner) { + gameBinding.flFansTeamJoinTip.isVisible = false + gameBinding.tvFansTeamOpt.isVisible = true + gameBinding.tvFansTeamOpt.text = getString(R.string.fans_team_6) + clickListener = View.OnClickListener { + CommonWebViewActivity.start( + requireContext(), + UriProvider.getFansTeamOpenUrl(AvRoomDataManager.get().roomUid) + ) + } + } else { + gameBinding.flFansTeamJoinTip.isVisible = false + gameBinding.tvFansTeamOpt.isVisible = true + gameBinding.tvFansTeamOpt.text = getString(R.string.layout_fragment_single_room_03) + } + } + gameBinding.flFansTeam.setOnClickListener(clickListener) + } + + //顯示請求上麥彈窗 + private fun showInviteDialog(userInfo: UserInfo) { + if (!this::upMicDialog.isInitialized) { + upMicDialog = RequestUpMicDialog(requireContext()) + } + if (!upMicDialog.isShowing) { + upMicDialog.openDialog() + upMicDialog.setUser(userInfo) + } + } + + override fun onSetListener() { + super.onSetListener() + bottomView.setBottomViewListener(BaseRoomBottomViewWrapper()) + } + + override fun onEnterRoom() { + super.onEnterRoom() + fansTeamViewModel.loadFansTeamInitInfo() + } + + override fun updateView() { + super.updateView() + if (AvRoomDataManager.get().isOpenAnotherPKMode && gameBinding.microView.adapter !is SingleRoomPKMicroViewAdapter) { + gameBinding.microView.bindAdapter(SingleRoomPKMicroViewAdapter(context)) + gameBinding.viewPkBoard.isVisible = true + gameBinding.microView.updateLayoutParams { + topMargin = ScreenUtil.dip2px(140f) + } + } else if (!AvRoomDataManager.get().isOpenAnotherPKMode && gameBinding.microView.adapter !is SingleAnchorMicroViewAdapter) { + gameBinding.microView.bindAdapter(SingleAnchorMicroViewAdapter(context)) + gameBinding.viewPkBoard.isVisible = false + gameBinding.microView.updateLayoutParams { + topMargin = ScreenUtil.dip2px(110f) + } + } else { + gameBinding.microView.adapter?.notifyDataSetChanged() + } + } + + override fun initWidget() { + super.initWidget() + registerWidget(RoomOnlineWidget::class.java.simpleName, gameBinding.onlineWidget) + registerWidget(RoomHeadlineWidget::class.java.simpleName, gameBinding.headlineWidget) + registerWidget(RoomRankNumberWidget::class.java.simpleName, gameBinding.rankNumberWidget) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/game/AppConfig.java b/app/src/main/java/com/chwl/app/avroom/game/AppConfig.java new file mode 100644 index 0000000..2031433 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/game/AppConfig.java @@ -0,0 +1,17 @@ +/* + Copyright © Sud.Tech + https://sud.tech + */ +package com.chwl.app.avroom.game; + + +import com.chwl.app.BuildConfig; + +public class AppConfig { + + public static final String APP_ID = "1578948593831571457"; + public static final String APP_KEY = "J9lHOXvFWkAZiTfl4SK7IGt0wDnW3fWd"; + public static boolean isTestEnv = BuildConfig.DEBUG; +// public static boolean isTestEnv = Env.getCurrentEnv() == Env.EnvType.Debug; + +} diff --git a/app/src/main/java/com/chwl/app/avroom/game/GameDelegate.kt b/app/src/main/java/com/chwl/app/avroom/game/GameDelegate.kt new file mode 100644 index 0000000..1fda79b --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/game/GameDelegate.kt @@ -0,0 +1,715 @@ +package com.chwl.app.avroom.game + +import android.annotation.SuppressLint +import android.app.Activity +import android.content.Context +import android.os.Handler +import android.os.Looper +import android.text.TextUtils +import android.util.Log +import android.view.View +import android.view.ViewTreeObserver.OnGlobalLayoutListener +import android.widget.FrameLayout +import com.google.gson.Gson +import com.chwl.app.R +import com.chwl.core.auth.AuthModel +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.room.game.bean.GameCfg +import com.chwl.core.room.game.GameModel +import com.chwl.core.room.game.GameStatus +import com.chwl.core.room.model.HomePartyModel +import com.chwl.core.sud.model.GameViewInfoModel.GameViewRectModel +import com.chwl.core.sud.state.SudMGPAPPState +import com.chwl.core.sud.state.SudMGPMGState +import com.chwl.core.user.UserModel +import com.chwl.core.utils.LogUtils +import com.chwl.core.utils.net.RxHelper +import com.chwl.library.language.LanguageHelper +import com.chwl.library.net.rxnet.callback.CallBack +import com.chwl.library.utils.ResUtil +import com.chwl.library.utils.SingleToastUtil +import okhttp3.* +import org.json.JSONException +import org.json.JSONObject +import tech.sud.mgp.core.* +import java.util.* + +class GameDelegate(val activity: Activity, val container: FrameLayout, var mgId: Long?) { + + private val TAG = "GameDelegate" + private var APP_CODE = "" + + private val mRoomID :String get() = AvRoomDataManager.get().roomUid.toString() + private var mLanguage = "zh-TW" //語言 + + //調用遊戲SDK的接口,成功加載遊戲後可用: + private var iSudFSTAPP: ISudFSTAPP? = null + + private val gson = Gson() + + //小遊戲ID + private var mMGID = 0L + + //通用狀態-遊戲,關鍵詞 + private var mKeyWord: String? = null + private val mUid = AuthModel.get().currentUid.toString() + + private val homePartyModel = HomePartyModel() + + private var onGameStatusChangeListener: OnGameStatusChangeListener? = null + + var gameViewRect: GameViewRectModel? = null + + fun setOnGameStatusChangeListener(onGameStatusChangeListener: OnGameStatusChangeListener) { + this.onGameStatusChangeListener = onGameStatusChangeListener + } + + private val loginCallback: AppLoginListener = + object : AppLoginListener { + override fun onLoginFailure(err: String?) { + SingleToastUtil.showToast(err) + } + + override fun onLoginSuccess(new_code: String, expire_Date: Long) { + APP_CODE = new_code + Handler(Looper.getMainLooper()).post { + //初始化遊戲SDK + initGameSDK( + activity, + AppConfig.APP_ID, + AppConfig.APP_KEY, + AppConfig.isTestEnv + ) + } + } + + } + + init { + mMGID = mgId ?: 0L + mLanguage = getGameLanguage() + login(loginCallback) + } + + fun updateGame(mgId: Long?) { + if (mgId == null || mgId == 0L) return + if (mgId == mMGID && iSudFSTAPP != null) { + return + } + mMGID = mgId + updateMyMicQueue(GameStatus.STATUS_NOT_JOIN) + loadMG(activity, mUid, mRoomID, APP_CODE, mMGID, mLanguage) + } + + fun exitGame() { + UserModel.get().cacheLoginUserInfo?.gameStatus = GameStatus.STATUS_NOT_JOIN + notifySelfPlayingState(false) + notifySelfInState(false) + } + + /** + * 例如"你畫我猜"遊戲的文字命中 + */ + fun hitTheMark(msg: String) { + mKeyWord?.let { + if (msg.contains(it)) { + notifySelfTextHit(it, msg) + } + } + } + + /** + * "接入方客戶端"登陸接口, 從"接入方服務端"獲得Code + * "接入方服務端"是通過"服務端接入SDK"獲得Code來返回給"接入方客戶端"的 + * @param listener + */ + @SuppressLint("CheckResult") + private fun login(listener: AppLoginListener) { + GameModel.getGameCode() + .compose(RxHelper.bindContext(activity)) + .subscribe({ + listener.onLoginSuccess(it.code, it.expireDate) + }, { + listener.onLoginFailure(it.message) + }) + + } + + /** + * 1,初始化遊戲SDK + * + * @param context 上下文 + * @param appID appID + * @param appKey appKey + * @param isTestEnv 是否是測試環境,true:測試環境,false:正式環境 + */ + private fun initGameSDK(context: Context, appID: String, appKey: String, isTestEnv: Boolean) { + SudMGP.initSDK(context, appID, appKey, isTestEnv, object : ISudListenerInitSDK { + override fun onSuccess() { + loadMG(activity, mUid, mRoomID, APP_CODE, mMGID, mLanguage) + } + + override fun onFailure(code: Int, errInfo: String) { + val msg = context.getString(R.string.game_failed_tips).format("$code-${errInfo}") + showToast(msg) + } + }) + + } + + /** + * 2,加載遊戲 + * + * @param activity 上下文Activity + * @param userID 用戶ID,業務系統保證每個用戶擁有唯一ID + * @param roomID 房間ID,進入同一房間內的 + * @param code 令牌 + * @param mgID 小遊戲ID + * @param language 遊戲語言 現支持,簡體:zh-CN 繁體:zh-TW 英語:en-US 馬來語:ms-MY + */ + private fun loadMG( + activity: Activity, + userID: String, + roomID: String, + code: String, + mgID: Long, + language: String + ) { + iSudFSTAPP?.destroyMG() + iSudFSTAPP = SudMGP.loadMG(activity, userID, roomID, code, mgID, language, mISudFSMMG) + iSudFSTAPP?.apply { + addGameView(gameView) + } + } + + /** + * 3,將遊戲view添加到我們的布局當中 + * + * @param gameView + */ + private fun addGameView(gameView: View) { + container.removeAllViews() + container.addView(gameView) + } + + private fun showToast(content: String?) { + SingleToastUtil.showToast(content) + } + + + /** + * 通知"文字命中狀態"到遊戲端 + * + * @param iSudFSTAPP + * @param keyWord + */ + private fun notifySelfTextHit(keyWord: String?, msg: String) { + LogUtils.d("notifySelfTextHit") + try { + //狀態名稱 + val state: String = SudMGPAPPState.APP_COMMON_SELF_TEXT_HIT + + //狀態數據 + val jsonObject = JSONObject() + jsonObject.put("isHit", true) // true 命中,false 未命中 + jsonObject.put("keyWord", keyWord) // true 命中,false 未命中 + jsonObject.put("text", msg) // 聊天原始內容,這裏的值只是一個示例,意指內容當中包含關鍵詞則命中,具體按業務規則定。 + val dataJson = jsonObject.toString() + //調用接口 + iSudFSTAPP?.notifyStateChange(state, dataJson, null) + } catch (e: Exception) { + e.printStackTrace() + } + } + + /** + * 設置當前關鍵詞 + * + * @param keyWord + */ + private fun setKeyWord(keyWord: String?) { + mKeyWord = keyWord + } + + private fun getGameLanguage(): String { + return when (LanguageHelper.getCurrentLanguageType()) { + LanguageHelper.ZH -> { + "zh-TW" + } + + LanguageHelper.AR -> { + "ar-SA" + } + + else -> { + "en-US" + } + } + } + + /** + * 遊戲SDK調用app的接口 + */ + private val mISudFSMMG: ISudFSMMG = object : ISudFSMMG { + + override fun onGameLog(p0: String?) { + LogUtils.d(p0) + } + + override fun onGameLoadingProgress(p0: Int, p1: Int, p2: Int) { + + } + + override fun onGameStarted() { + } + + override fun onGameDestroyed() { + } + + /** + * 回調此方法,表示令牌過期,此時需要刷新令牌並使用ISudFSMStateHandle回調 + * @param handle + * @param dataJson + */ + override fun onExpireCode(handle: ISudFSMStateHandle, dataJson: String) { + login(object : AppLoginListener { + override fun onLoginFailure(err: String?) { + + } + + override fun onLoginSuccess(new_code: String, expire_Date: Long) { + APP_CODE = new_code + try { + val jsonObject = JSONObject() + jsonObject.put("ret_code", 0) + jsonObject.put("ret_msg", "success") + handle.success(jsonObject.toString()) + } catch (e: JSONException) { + e.printStackTrace() + } + iSudFSTAPP?.updateCode(APP_CODE, null) + } + + }) + } + + /** + * 處理獲取遊戲視圖信息 + * @param handle + * @param dataJson + */ + override fun onGetGameViewInfo(handle: ISudFSMStateHandle, dataJson: String) { + //拿到遊戲View的寬高 + val gameViewWidth = container.measuredWidth + val gameViewHeight = container.measuredHeight + if (gameViewWidth > 0 && gameViewHeight > 0) { + notifyGameViewInfo(handle, gameViewWidth, gameViewHeight) + return + } + + //如果遊戲View未加載完成,則監聽加載完成時回調 + container.viewTreeObserver.addOnGlobalLayoutListener(object : OnGlobalLayoutListener { + override fun onGlobalLayout() { + container.viewTreeObserver.removeOnGlobalLayoutListener(this) + val width = container.measuredWidth + val height = container.measuredHeight + notifyGameViewInfo(handle, width, height) + } + }) + } + + override fun onGetGameCfg(handle: ISudFSMStateHandle?, p1: String?) { + handle?.success(gson.toJson(GameCfg())) + } + + /** + * 通知遊戲,遊戲視圖信息 + * @param handle + * @param gameViewWidth + * @param gameViewHeight + */ + private fun notifyGameViewInfo( + handle: ISudFSMStateHandle, + gameViewWidth: Int, + gameViewHeight: Int + ) { + try { + val jsonObject = JSONObject() + jsonObject.put("ret_code", 0) + jsonObject.put("ret_msg", "success") + + //遊戲View大小 + val viewSize = JSONObject() + viewSize.put("width", gameViewWidth) + viewSize.put("height", gameViewHeight) + jsonObject.put("view_size", viewSize) + + //遊戲安全操作區域 + val viewGameRect = JSONObject() + val viewRect = gameViewRect + if (viewRect != null) { + Log.d(TAG,"notifyGameViewInfo top:${viewRect.top} viewRect:${viewRect.bottom}") + viewGameRect.put("left", viewRect.left) + viewGameRect.put("top", viewRect.top) + viewGameRect.put("right", viewRect.right) + viewGameRect.put("bottom", viewRect.bottom) + } else { + viewGameRect.put("left", 0) + viewGameRect.put( + "top", + container.context.resources.getDimensionPixelOffset(R.dimen.dp_185) + ) + viewGameRect.put("right", 0) + viewGameRect.put( + "bottom", + container.context.resources.getDimensionPixelOffset(R.dimen.dp_180) + ) + } + jsonObject.put("view_game_rect", viewGameRect) + //通知遊戲 + val json = jsonObject.toString() + Log.d(TAG, "notifyGameViewInfo:$json") + handle.success(json) + } catch (e: JSONException) { + e.printStackTrace() + } + } + + /** + * 遊戲狀態變化 + * @param handle + * @param state 狀態名 + * @param dataJson 狀態數據,json字符串 + */ + override fun onGameStateChange( + handle: ISudFSMStateHandle, + state: String, + dataJson: String + ) { + Log.d(TAG, "onGameStateChange state:$state--dataJson:$dataJson") + when (state) { + //SudMGPMGState.MG_COMMON_PUBLIC_MESSAGE -> showToast("遊戲:公屏消息") + SudMGPMGState.MG_COMMON_KEY_WORD_TO_HIT -> { + if (TextUtils.isEmpty(dataJson)) { + setKeyWord(null) + } else { + try { + val jsonObject = JSONObject(dataJson) + if (jsonObject.isNull("word")) { + setKeyWord(null) + } else { + val keyWord = jsonObject.getString("word") + setKeyWord(keyWord) + } + } catch (e: Exception) { + e.printStackTrace() + } + } + } + SudMGPMGState.MG_COMMON_SELF_CLICK_JOIN_BTN -> { + + try { + val jsonObject = JSONObject(dataJson) + val seatIndex = jsonObject.optInt("seatIndex", -1) + updateMyMicQueue(GameStatus.STATUS_NOT_READY, true, seatIndex) + } catch (e: Exception) { + e.printStackTrace() + } + + } + SudMGPMGState.MG_COMMON_SELF_CLICK_START_BTN -> { + notifySelfPlayingState(true) + } + SudMGPMGState.MG_COMMON_GAME_STATE -> handleGameState(dataJson) + } + } + + /** + * 玩家狀態變化 + * @param handle + * @param userId 玩家用戶ID + * @param state 狀態名 + * @param dataJson 狀態數據,json字符串。參考文檔 + */ + override fun onPlayerStateChange( + handle: ISudFSMStateHandle, + userId: String, + state: String, + dataJson: String + ) { + Log.d(TAG, "onPlayerStateChange userId:$userId--state:$state--dataJson:$dataJson") + when (state) { + SudMGPMGState.MG_COMMON_PLAYER_IN -> handlePlayerIn(userId, dataJson) + SudMGPMGState.MG_COMMON_PLAYER_READY -> handlePlayerReady(userId, dataJson) + SudMGPMGState.MG_COMMON_PLAYER_CAPTAIN -> handlePlayerCaptain(dataJson) + SudMGPMGState.MG_COMMON_PLAYER_PLAYING -> handlePlayerPlaying(userId, dataJson) + } + } + } + + private fun handlePlayerIn(userId: String, dataJson: String) { + if (userId != mUid) return + try { + val jsonObject = JSONObject(dataJson) + val retCode = jsonObject.getInt("retCode") + val isIn = jsonObject.getBoolean("isIn") + if (retCode != 0) { + return + } + if (isIn) { // 已加入 + if (AvRoomDataManager.get().isRoomOwner) { + notifySelfCaptainState(mUid) + } + } else { // 未加入 + var reason = 0 + if (jsonObject.has("reason")) { + reason = jsonObject.getInt("reason") + } + if (reason == 0) { + updateMyMicQueue(GameStatus.STATUS_NOT_JOIN) + } else if (reason == 1) { + updateMyMicQueue(GameStatus.STATUS_NOT_JOIN) + } + } + } catch (e: Exception) { + e.printStackTrace() + } + } + + private fun updateMyMicQueue(gameStatus: Int, isJoin: Boolean = false, seatIndex: Int = -1) { + UserModel.get().cacheLoginUserInfo?.gameStatus = gameStatus + val position = AvRoomDataManager.get().getMicPosition(mUid) + if (position != AvRoomDataManager.POSITON_NOT_ON_MIC) { + if (isJoin) notifySelfInState(true, seatIndex) + homePartyModel.updateMyMicQueue( + position, + AvRoomDataManager.get().roomId.toString(), + UserModel.get().cacheLoginUserInfo + ).subscribe() + } else if (isJoin) { + val upPosition = AvRoomDataManager.get().findGamePosition() + if (upPosition == Int.MIN_VALUE) { + showToast(ResUtil.getString(R.string.room_game_number_full)) + } else { + UserModel.get().cacheLoginUserInfo?.gameStatus = 1 + homePartyModel.upMicroPhone(upPosition, + mUid, + AvRoomDataManager.get().roomId.toString(), + false, object : CallBack { + override fun onSuccess(data: String?) { + notifySelfInState(true, seatIndex) + } + + override fun onFail(code: Int, error: String?) { + showToast(error) + } + + }) + } + } + } + + private fun handlePlayerReady(userId: String, dataJson: String) { + if (userId != mUid) return + try { + val jsonObject = JSONObject(dataJson) + val retCode = jsonObject.getInt("retCode") + val isReady = jsonObject.getBoolean("isReady") + if (retCode != 0) { + return + } + updateMyMicQueue(if (isReady) GameStatus.STATUS_READY else GameStatus.STATUS_NOT_READY) + } catch (e: Exception) { + e.printStackTrace() + } + } + + private fun handlePlayerCaptain(dataJson: String) { + try { + val jsonObject = JSONObject(dataJson) + val retCode = jsonObject.getInt("retCode") + if (retCode != 0) { + return + } + + } catch (e: Exception) { + e.printStackTrace() + } + } + + private fun handleGameState(dataJson: String) { + try { + val jsonObject = JSONObject(dataJson) + val gameState = jsonObject.getInt("gameState") + if (gameState == 0) { + onGameStatusChangeListener?.onGameEnd() + } else if (gameState == 2) { + onGameStatusChangeListener?.onGameStart() + } + } catch (e: Exception) { + e.printStackTrace() + } + } + + private fun handlePlayerPlaying(userId: String, dataJson: String) { + if (userId != mUid) return + try { + val jsonObject = JSONObject(dataJson) + val retCode = jsonObject.getInt("retCode") + if (retCode != 0) { + return + } + val isPlaying = jsonObject.getBoolean("isPlaying") + if (isPlaying) { + updateMyMicQueue(GameStatus.STATUS_PLAYING) + } else { + updateMyMicQueue(GameStatus.STATUS_NOT_READY) + } + } catch (e: Exception) { + e.printStackTrace() + } + } + + private fun notifySelfInState(isIn: Boolean, seatIndex: Int = -1) { + try { + if (!isIn) { + notifySelfReadyState(false) + } + //狀態名稱 + val state = SudMGPAPPState.APP_COMMON_SELF_IN + //狀態數據 + val jsonObject = JSONObject() + jsonObject.put("isIn", isIn) // true 加入遊戲,false 退出遊戲 + if (seatIndex != -1) { + jsonObject.put("seatIndex", seatIndex) + } + jsonObject.put("teamId", 1) //哪一隊伍(2v2,4v4) + val dataJson = jsonObject.toString() + + //調用接口 + iSudFSTAPP?.notifyStateChange(state, dataJson, null) + } catch (e: Exception) { + e.printStackTrace() + } + } + + private fun notifySelfReadyState(isReady: Boolean) { + try { + //狀態名稱 + val state = SudMGPAPPState.APP_COMMON_SELF_READY + + //狀態數據 + val jsonObject = JSONObject() + jsonObject.put("isReady", isReady) // true 準備,false 取消準備 + val dataJson = jsonObject.toString() + + //調用接口 + iSudFSTAPP?.notifyStateChange(state, dataJson, null) + } catch (e: Exception) { + e.printStackTrace() + } + } + + private fun notifySelfPlayingState(isPlaying: Boolean) { + try { + //狀態名稱 + val state = SudMGPAPPState.APP_COMMON_SELF_PLAYING + + //狀態數據 + val jsonObject = JSONObject() + jsonObject.put("isPlaying", isPlaying) // true 開始遊戲,false 結束遊戲 + val dataJson = jsonObject.toString() + + //調用接口 + iSudFSTAPP?.notifyStateChange(state, dataJson, null) + } catch (e: Exception) { + e.printStackTrace() + } + } + + private fun notifySelfCaptainState(uid: String) { + try { + //狀態名稱 + val state = SudMGPAPPState.APP_COMMON_SELF_CAPTAIN + + //狀態數據 + val jsonObject = JSONObject() + jsonObject.put("curCaptainUID", uid) // 必填,指定隊長uid + val dataJson = jsonObject.toString() + + //調用接口 + iSudFSTAPP?.notifyStateChange(state, dataJson, null) + } catch (e: Exception) { + e.printStackTrace() + } + } + + private fun notifySelfKickState(uid: String) { + try { + //狀態名稱 + val state = SudMGPAPPState.APP_COMMON_SELF_KICK + + //狀態數據 + val jsonObject = JSONObject() + jsonObject.put("kickedUID", uid) // 被踢用戶uid + val dataJson = jsonObject.toString() + + //調用接口 + iSudFSTAPP?.notifyStateChange(state, dataJson, null) + } catch (e: Exception) { + e.printStackTrace() + } + } + + private fun notifySelfEndState() { + try { + //狀態名稱 + val state = SudMGPAPPState.APP_COMMON_SELF_END + + //狀態數據 + val jsonObject = JSONObject() + val dataJson = jsonObject.toString() + + //調用接口 + iSudFSTAPP?.notifyStateChange(state, dataJson, null) + } catch (e: Exception) { + e.printStackTrace() + } + } + + fun onStart() { + iSudFSTAPP?.startMG() //啟動遊戲 + } + + fun onResume() { + iSudFSTAPP?.playMG() //開始遊戲 + } + + fun onPause() { + iSudFSTAPP?.pauseMG() //暫停遊戲 + } + + fun onStop() { + iSudFSTAPP?.stopMG() //停止遊戲 + } + + fun onDestroy() { + updateMyMicQueue(GameStatus.STATUS_NOT_JOIN) + iSudFSTAPP?.destroyMG() + } + +} + +internal interface AppLoginListener { + /** + * App Server 登陸失敗, App Server 不能返回CODE + */ + fun onLoginFailure(err: String?) + + /** + * App Server 登陸成功, App Server調用服務端接入SDK的API獲取Code 返回給 App + * App 就要用CODE和自己生成的UserID去調用SDK的初始化函數,登陸小遊戲 + * 小遊戲登陸成功後,其UserID,就是App傳的UserID + */ + fun onLoginSuccess(new_code: String, expire_Date: Long) +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/game/OnGameStatusChangeListener.kt b/app/src/main/java/com/chwl/app/avroom/game/OnGameStatusChangeListener.kt new file mode 100644 index 0000000..0b5fc1e --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/game/OnGameStatusChangeListener.kt @@ -0,0 +1,13 @@ +package com.chwl.app.avroom.game + +interface OnGameStatusChangeListener { + /** + * 游戏开始 + */ + fun onGameStart() + + /** + * 游戏结束 + */ + fun onGameEnd() +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/gameplay/GameplayRecyclerView.kt b/app/src/main/java/com/chwl/app/avroom/gameplay/GameplayRecyclerView.kt new file mode 100644 index 0000000..3c34197 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/gameplay/GameplayRecyclerView.kt @@ -0,0 +1,22 @@ +package com.chwl.app.avroom.gameplay + +import android.content.Context +import android.util.AttributeSet +import android.view.MotionEvent +import androidx.recyclerview.widget.RecyclerView + + +class GameplayRecyclerView : RecyclerView { + constructor(context: Context) : super(context) + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) + + override fun onInterceptTouchEvent(e: MotionEvent?): Boolean { + parent.requestDisallowInterceptTouchEvent(true) + return super.onInterceptTouchEvent(e) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/gameplay/RoomGameplayListWidget.kt b/app/src/main/java/com/chwl/app/avroom/gameplay/RoomGameplayListWidget.kt new file mode 100644 index 0000000..9abf4a5 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/gameplay/RoomGameplayListWidget.kt @@ -0,0 +1,66 @@ +package com.chwl.app.avroom.gameplay + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.ViewConfiguration +import androidx.databinding.DataBindingUtil +import com.chwl.core.support.room.FrameLayoutRoomWidget +import com.chwl.app.R +import com.chwl.app.databinding.RoomGameplayListWidgetBinding +import com.chwl.core.room.bean.RoomIcon + +class RoomGameplayListWidget : FrameLayoutRoomWidget { + private val adapter = RoomPlayListAdapter() + private val binding: RoomGameplayListWidgetBinding = + DataBindingUtil.inflate( + LayoutInflater.from( + context + ), R.layout.room_gameplay_list_widget, this, true + ) + + constructor(context: Context) : super(context) + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) + + constructor( + context: Context, + attrs: AttributeSet?, + defStyleAttr: Int, + defStyleRes: Int + ) : super(context, attrs, defStyleAttr, defStyleRes) + + init { + binding.recyclerView.adapter = adapter + binding.ivSwitch.setOnClickListener { + getGameplayIconWidget()?.switchUI(false) + } + adapter.setOnItemClickListener { adapter, view, position -> + (adapter.getItem(position) as? RoomIcon)?.let { + getGameplayIconWidget()?.jump(it) + } + } + } + + private fun getGameplayIconWidget(): RoomGameplayWidget? { + return roomView?.findWidget( + RoomGameplayWidget::class.simpleName ?: "" + ) as? RoomGameplayWidget + } + + fun loadData(list: List) { + adapter.setNewData(list) + if (list.size > 6) { + binding.recyclerView.isScrollbarFadingEnabled = false + binding.recyclerView.scrollBarFadeDuration = 0 + } else { + binding.recyclerView.isScrollbarFadingEnabled = true + binding.recyclerView.scrollBarFadeDuration = + ViewConfiguration.getScrollBarFadeDuration() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/gameplay/RoomGameplayWidget.kt b/app/src/main/java/com/chwl/app/avroom/gameplay/RoomGameplayWidget.kt new file mode 100644 index 0000000..e42a498 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/gameplay/RoomGameplayWidget.kt @@ -0,0 +1,119 @@ +package com.chwl.app.avroom.gameplay + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View +import androidx.core.view.isVisible +import androidx.databinding.DataBindingUtil +import com.chwl.app.R +import com.chwl.app.databinding.RoomGameplayWidgetBinding +import com.chwl.app.treasure_box.widget.GoldBoxHelper +import com.chwl.app.ui.utils.load +import com.chwl.app.ui.webview.CommonWebViewActivity +import com.chwl.app.ui.webview.room_banner.RoomWebDialogActivity +import com.chwl.app.utils.CommonJumpHelper +import com.chwl.core.room.bean.RoomIcon +import com.chwl.core.room.model.AvRoomModel +import com.chwl.core.support.room.FrameLayoutRoomWidget +import com.chwl.core.support.room.RoomContext +import com.chwl.core.support.room.RoomView +import com.example.lib_utils.ktx.singleClick + + +class RoomGameplayWidget : FrameLayoutRoomWidget { + private val binding: RoomGameplayWidgetBinding = + DataBindingUtil.inflate( + LayoutInflater.from( + context + ), R.layout.room_gameplay_widget, this, true + ) + + private var isOpened = false + + private var list: List? = null + + constructor(context: Context) : super(context) + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) + + constructor( + context: Context, + attrs: AttributeSet?, + defStyleAttr: Int, + defStyleRes: Int + ) : super(context, attrs, defStyleAttr, defStyleRes) + + init { + binding.ivSwitch.setOnClickListener { + switchUI(!isOpened) + } + binding.ivIcon.singleClick { + list?.getOrNull(0)?.let { + jump(it) + } + } + } + + override fun onInitialize(roomView: RoomView, roomContext: RoomContext) { + super.onInitialize(roomView, roomContext) + refreshData() + } + + private fun refreshData() { + val disposable = AvRoomModel.get().roomGamePlayList + .subscribe { list: List -> + loadData(list) + } + getCompositeDisposable().add(disposable) + } + + fun switchUI(openListWidget: Boolean) { + this.isOpened = openListWidget + if (openListWidget) { + this.visibility = View.INVISIBLE + getGameplayListWidget()?.visibility = View.VISIBLE + } else { + this.visibility = View.VISIBLE + getGameplayListWidget()?.visibility = View.GONE + } + } + + private fun loadData(list: List) { + this.list = list + this.isVisible = list.isNotEmpty() + val listWidget = getGameplayListWidget() + if (list.isEmpty()) { + listWidget?.isVisible = false + } + listWidget?.loadData(list) + binding.ivIcon.load(list.firstOrNull()?.icon) + } + + fun jump(data: RoomIcon) { + if (data.isFindLove()) { + GoldBoxHelper.handleBoxClick(context) + } else { + val url = data.skipContent + if (data.skipType == 3 && !url.isNullOrEmpty()) { + if (data.showType == 2) { + RoomWebDialogActivity.start(context, url, false) + } else { + CommonWebViewActivity.start(context, url) + } + } else { + CommonJumpHelper.bannerJump(context, data) + } + } + } + + private fun getGameplayListWidget(): RoomGameplayListWidget? { + return roomView?.findWidget( + RoomGameplayListWidget::class.simpleName ?: "" + ) as? RoomGameplayListWidget + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/gameplay/RoomPlayListAdapter.kt b/app/src/main/java/com/chwl/app/avroom/gameplay/RoomPlayListAdapter.kt new file mode 100644 index 0000000..a2ef8fb --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/gameplay/RoomPlayListAdapter.kt @@ -0,0 +1,16 @@ +package com.chwl.app.avroom.gameplay + +import android.widget.ImageView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.ui.utils.load +import com.chwl.core.room.bean.RoomIcon + + +class RoomPlayListAdapter : + BaseQuickAdapter(R.layout.room_gameplay_item) { + override fun convert(helper: BaseViewHolder, item: RoomIcon?) { + helper.getView(R.id.iv_icon).load(item?.icon) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/giftvalue/GiftValueDialogUiHelper.java b/app/src/main/java/com/chwl/app/avroom/giftvalue/GiftValueDialogUiHelper.java new file mode 100644 index 0000000..802a16a --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/giftvalue/GiftValueDialogUiHelper.java @@ -0,0 +1,133 @@ +package com.chwl.app.avroom.giftvalue; + +import android.content.Context; + +import androidx.annotation.Nullable; + +import com.chwl.app.R; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.utils.ActivityUtil; +import com.chwl.core.utils.SharedPreferenceUtils; + +/** + * 礼物值的弹框处理 + * create by lvzebiao @2019/4/12 + */ +public class GiftValueDialogUiHelper { + + public final static int TYPE_CLOSE_SHOW_GIFT_VALUE = 1; + + /** + * 主动下麦 + */ + public final static int TYPE_DOWN_MIC = 2; + + /** + * 管理踢人下麦 + */ + public final static int TYPE_KICK_DOWN_MIC = 3; + + /** + * 换麦 + */ + public final static int TYPE_CHANGE_MIC = 4; + + /** + * 如果此key保留的值为ture,关闭礼物值模式的时候,需要弹框确认 + */ + public final static String KEY_NEED_DIALOG_WHEN_CLOSE_GIFT_VALUE_MODEL = + "need_dialog_when_close_gift_value_model"; + + /** + * 主动下麦的情况 + */ + public final static String KEY_DOWN_MIC_NEED_DIALOG_TIPS = "down_mic_need_dialog_tips"; + + /** + * 踢人下麦的情况 + */ + public final static String KEY_KICK_DOWN_MIC_NEED_DIALOG_TIPS = "kick_down_mic_need_dialog_tips"; + + /** + * 换麦 + */ + public final static String KEY_CHANGE_MIC_NEED_DIALOG_TIPS = "change_mic_need_dialog_tips"; + + public static GiftValueDialogUiHelper get() { + return Helper.INSTANCE; + } + + public boolean isNeedConfirmDialog(int type) { + if (type == TYPE_CLOSE_SHOW_GIFT_VALUE) { + Boolean value = (Boolean) SharedPreferenceUtils.get(KEY_NEED_DIALOG_WHEN_CLOSE_GIFT_VALUE_MODEL, false); + return value != null && value; + } else if (type == TYPE_DOWN_MIC) { + Boolean value = (Boolean) SharedPreferenceUtils.get(KEY_DOWN_MIC_NEED_DIALOG_TIPS, false); + return value != null && value; + } else if (type == TYPE_KICK_DOWN_MIC) { + Boolean value = (Boolean) SharedPreferenceUtils.get(KEY_KICK_DOWN_MIC_NEED_DIALOG_TIPS, false); + return value != null && value; + } else if (type == TYPE_CHANGE_MIC) { + Boolean value = (Boolean) SharedPreferenceUtils.get(KEY_CHANGE_MIC_NEED_DIALOG_TIPS, false); + return value != null && value; + } + return true; + } + + public boolean isNeedKickDownMicDialog() { + return AvRoomDataManager.get().isShowGiftValue() && isNeedConfirmDialog(TYPE_KICK_DOWN_MIC); + } + + /** + * 换麦时,是否需要弹窗提示 + */ + public boolean isNeedChangeMicDialog() { + return AvRoomDataManager.get().isShowGiftValue() && isNeedConfirmDialog(TYPE_CHANGE_MIC); + } + + public void showGiftValueDialog(Context context, @Nullable DialogManager dialogManager, int type, + DialogManager.OkCancelDialogListener l) { + if (!ActivityUtil.isValidContext(context)) { + return; + } + if (dialogManager == null) { + dialogManager = new DialogManager(context); + } + String message = ""; + if (type == TYPE_CLOSE_SHOW_GIFT_VALUE) { + message = context.getString(R.string.close_show_gift_value_tips); + } else if (type == TYPE_DOWN_MIC) { + message = context.getString(R.string.down_mic_tips); + } else if (type == TYPE_KICK_DOWN_MIC) { + message = context.getString(R.string.kick_down_mic_tips); + } else if (type == TYPE_CHANGE_MIC) { + message = context.getString(R.string.change_mic_tips); + } + final DialogManager finalDialogManager = dialogManager; + dialogManager.showOkCancelSwitchDialog(message, () -> { + if (l != null) { + l.onOk(); + } + boolean isTrue = finalDialogManager.isOpenSwitch(); + if (!isTrue) { + return; + } + if (type == TYPE_CLOSE_SHOW_GIFT_VALUE) { + SharedPreferenceUtils.put(KEY_NEED_DIALOG_WHEN_CLOSE_GIFT_VALUE_MODEL, false); + } else if (type == TYPE_DOWN_MIC) { + SharedPreferenceUtils.put(KEY_DOWN_MIC_NEED_DIALOG_TIPS, false); + } else if (type == TYPE_KICK_DOWN_MIC) { + SharedPreferenceUtils.put(KEY_KICK_DOWN_MIC_NEED_DIALOG_TIPS, false); + } else if (type == TYPE_CHANGE_MIC) { + SharedPreferenceUtils.put(KEY_CHANGE_MIC_NEED_DIALOG_TIPS, false); + } + }); + } + + private static final class Helper { + public static final GiftValueDialogUiHelper INSTANCE = new GiftValueDialogUiHelper(); + } + + +} diff --git a/app/src/main/java/com/chwl/app/avroom/headline/RoomHeadlineWidget.kt b/app/src/main/java/com/chwl/app/avroom/headline/RoomHeadlineWidget.kt new file mode 100644 index 0000000..b31a338 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/headline/RoomHeadlineWidget.kt @@ -0,0 +1,113 @@ +package com.chwl.app.avroom.headline + +import android.content.Context +import android.util.AttributeSet +import android.view.Gravity +import android.view.LayoutInflater +import androidx.core.view.isVisible +import androidx.databinding.DataBindingUtil +import com.chwl.app.R +import com.chwl.app.databinding.RoomHeadlineWidgetBinding +import com.chwl.app.public_chat.core.ChatRoomClient +import com.chwl.app.public_chat.core.ChatRoomClientManager +import com.chwl.app.ui.utils.loadAvatar +import com.chwl.core.im.custom.bean.CustomAttachment +import com.chwl.core.im.custom.bean.HeadlineChangedAttachment +import com.chwl.core.public_chat_hall.bean.HeadlineBean +import com.chwl.core.public_chat_hall.model.PublicChatModel +import com.chwl.core.support.room.FrameLayoutRoomWidget +import com.chwl.core.support.room.RoomView +import com.example.lib_utils.AppUtils +import com.example.lib_utils.UiUtils +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage +import com.netease.nimlib.sdk.msg.constant.MsgTypeEnum + +class RoomHeadlineWidget : FrameLayoutRoomWidget { + + private val binding: RoomHeadlineWidgetBinding = + DataBindingUtil.inflate( + LayoutInflater.from( + context + ), R.layout.room_headline_widget, this, true + ) + + private var chatRoomClient: ChatRoomClient? = null + + constructor(context: Context) : super(context) + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) + + constructor( + context: Context, + attrs: AttributeSet?, + defStyleAttr: Int, + defStyleRes: Int + ) : super(context, attrs, defStyleAttr, defStyleRes) + + init { + if (UiUtils.isRtl(AppUtils.getApp())) { + binding.tvHeadlineContent.gravity = Gravity.RIGHT + } + } + + override fun onStart(roomView: RoomView) { + super.onStart(roomView) + if (!isInEditMode) { + updateHeadline(null) + } + chatRoomClient = ChatRoomClientManager.getPublicChatClient() + chatRoomClient?.let { + initChatRoom(it) + } + requestCurrentHeadline() + } + + private fun onReceiveMessage(message: ChatRoomMessage) { + if (message.msgType == MsgTypeEnum.custom) { + val attachment: CustomAttachment = (message.attachment as? CustomAttachment) ?: return + when (attachment.first) { + CustomAttachment.CUSTOM_MSG_HEADLINE_CHANGED -> { + when (attachment.second) { + CustomAttachment.CUSTOM_MSG_HEADLINE_CHANGED_SUB -> { + val data = (attachment as? HeadlineChangedAttachment) ?: return + updateHeadline(data.headlineData) + } + } + } + } + } + } + + private fun initChatRoom(chatRoomClient: ChatRoomClient) { + // 登录流程:在PublicChatRoomMessageWidget中已经执行了 + getCompositeDisposable().add(chatRoomClient.messageObservable.subscribe { + it.forEach { message -> + onReceiveMessage(message) + } + }) + } + + private fun requestCurrentHeadline() { + safeLaunch { +// val data = PublicChatModel.getCurrentHeadline() +// updateHeadline(data) + } + } + + private fun updateHeadline(data: HeadlineBean?) { + binding.tvHeadlineContent.text = data?.content ?: "" + binding.ivAvatar.loadAvatar(data?.avatar) + binding.tvName.text = "${data?.nick ?: ""} :" + binding.tvMoney.text = data?.payMoneyNum?.toString() ?: "0" + this.isVisible = data?.isValid() == true && !data.content.isNullOrEmpty() + } + + override fun onStop() { + super.onStop() + chatRoomClient = null + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/helper/AnimHelper.java b/app/src/main/java/com/chwl/app/avroom/helper/AnimHelper.java new file mode 100644 index 0000000..2a82c61 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/helper/AnimHelper.java @@ -0,0 +1,111 @@ +package com.chwl.app.avroom.helper; + +import static com.chwl.core.XConstants.SELECT_ANIM_DURATION; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.Keyframe; +import android.animation.ObjectAnimator; +import android.animation.PropertyValuesHolder; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Point; +import android.text.TextUtils; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import androidx.annotation.Nullable; + +import com.bumptech.glide.load.DataSource; +import com.bumptech.glide.load.engine.GlideException; +import com.bumptech.glide.request.RequestListener; +import com.bumptech.glide.request.target.Target; +import com.coorchice.library.utils.LogUtils; +import com.netease.nim.uikit.common.util.sys.ScreenUtil; +import com.netease.nim.uikit.support.glide.GlideApp; +import com.opensource.svgaplayer.SVGADynamicEntity; +import com.chwl.app.R; +import com.chwl.app.application.App; + +public class AnimHelper { + + public static void showDatingSelectUserAnim(Context context, ViewGroup viewGroup, Point senderPoint, Point receivePoint) { + if (viewGroup == null || context == null || senderPoint == null || receivePoint == null) + return; + + final int width = ScreenUtil.dip2px(80); + final int height = ScreenUtil.dip2px(80); + final ImageView imageView = new ImageView(context); + FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(width, height); + layoutParams.leftMargin = senderPoint.x; + layoutParams.topMargin = senderPoint.y; + imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE); + imageView.setImageResource(R.drawable.ic_dating_like); + viewGroup.addView(imageView,layoutParams); + Keyframe kx0 = Keyframe.ofFloat(0f, 0f); + Keyframe kx1 = Keyframe.ofFloat(0.2f, 0f); + Keyframe kx2 = Keyframe.ofFloat(0.8f, receivePoint.x - senderPoint.x); + Keyframe kx3 = Keyframe.ofFloat(1f, receivePoint.x - senderPoint.x); + + Keyframe ky0 = Keyframe.ofFloat(0f, 0); + Keyframe ky1 = Keyframe.ofFloat(0.2f, 0); + Keyframe ky2 = Keyframe.ofFloat(0.8f, receivePoint.y - senderPoint.y); + Keyframe ky3 = Keyframe.ofFloat(1f, receivePoint.y - senderPoint.y); + + Keyframe ks0 = Keyframe.ofFloat(0f, 0f); + Keyframe ks1 = Keyframe.ofFloat(0.2f, 1f); + Keyframe ks2 = Keyframe.ofFloat(0.8f, 1f); + Keyframe ks3 = Keyframe.ofFloat(1f, 1.6f); + + Keyframe ka0 = Keyframe.ofFloat(0f, 0f); + Keyframe ka1 = Keyframe.ofFloat(0.2f, 1f); + Keyframe ka2 = Keyframe.ofFloat(0.8f, 1f); + Keyframe ka3 = Keyframe.ofFloat(1f, 0f); + + PropertyValuesHolder p0 = PropertyValuesHolder.ofKeyframe("translationX", kx0, kx1, kx2, kx3); + PropertyValuesHolder p1 = PropertyValuesHolder.ofKeyframe("translationY", ky0, ky1, ky2, ky3); + PropertyValuesHolder p2 = PropertyValuesHolder.ofKeyframe("scaleX", ks0, ks1, ks2, ks3); + PropertyValuesHolder p3 = PropertyValuesHolder.ofKeyframe("scaleY", ks0, ks1, ks2, ks3); + PropertyValuesHolder p4 = PropertyValuesHolder.ofKeyframe("alpha", ka0, ka1, ka2, ka3); + ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(imageView, p0, p1, p2, p3, p4); + objectAnimator.setDuration(SELECT_ANIM_DURATION); + objectAnimator.start(); + objectAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + ViewGroup viewGroup = (ViewGroup) imageView.getParent(); + viewGroup.removeView(imageView); + } + }); + } + + public static void addDynamicImage(View view, SVGADynamicEntity dynamicEntity, String url, String forKey) { + if (TextUtils.isEmpty(url) || TextUtils.isEmpty(forKey)) { + LogUtils.e("addDynamicImage: url or forKey is null or empty"); + return; + } + GlideApp.with(App.instance()) + .asBitmap() + .circleCrop() + .load(url) + .addListener(new RequestListener() { + @Override + public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { + view.post(() -> dynamicEntity.setDynamicImage(BitmapFactory.decodeResource(view.getResources(), R.drawable.default_avatar), forKey)); + return false; + } + + @Override + public boolean onResourceReady(Bitmap resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { + view.post(() -> dynamicEntity.setDynamicImage(resource, forKey)); + return false; + } + }) + .submit(); + } + +} diff --git a/app/src/main/java/com/chwl/app/avroom/helper/RoomViewModel.java b/app/src/main/java/com/chwl/app/avroom/helper/RoomViewModel.java new file mode 100644 index 0000000..391f07e --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/helper/RoomViewModel.java @@ -0,0 +1,30 @@ +package com.chwl.app.avroom.helper; + +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.ViewModel; + +import lombok.Getter; + +/** + * 房间数据的一些管理 + * Created by lvzebiao on 2018/11/16. + */ + +public class RoomViewModel extends ViewModel { + + @Getter + private final MutableLiveData isKtvModel = new MutableLiveData<>(); + + @Getter + private final MutableLiveData isGameModel = new MutableLiveData<>(); + + public void init() { + isKtvModel.setValue(false); + isGameModel.postValue(false); + } + + @Override + protected void onCleared() { + super.onCleared(); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/newuserchargegift/NewUserChargePrizeDialog.kt b/app/src/main/java/com/chwl/app/avroom/newuserchargegift/NewUserChargePrizeDialog.kt new file mode 100644 index 0000000..c05d4f7 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/newuserchargegift/NewUserChargePrizeDialog.kt @@ -0,0 +1,34 @@ +package com.chwl.app.avroom.newuserchargegift + +import android.content.Context +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.chwl.app.R +import com.chwl.app.databinding.DialogNewUserChargePrizeBinding +import com.chwl.app.base.BaseBindingDialog +import com.chwl.app.ui.utils.RVDelegate +import com.chwl.core.pay.bean.FirstChargeReward +import com.chwl.library.annatation.ActLayoutRes + +@ActLayoutRes(R.layout.dialog_new_user_charge_prize) +class NewUserChargePrizeDialog( + context: Context, + val title: String?, + private val firstChargeRewardList: List? +) : BaseBindingDialog(context) { + + private lateinit var rvDelegate: RVDelegate + + override fun init() { + rvDelegate = RVDelegate.Builder() + .setAdapter(RewardAdapter()) + .setLayoutManager(LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)) + .setRecyclerView(binding.recyclerView) + .build() + binding.ivKnow.setOnClickListener { + closeDialog() + } + rvDelegate.setNewData(firstChargeRewardList) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/newuserchargegift/RewardAdapter.kt b/app/src/main/java/com/chwl/app/avroom/newuserchargegift/RewardAdapter.kt new file mode 100644 index 0000000..50fc6f7 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/newuserchargegift/RewardAdapter.kt @@ -0,0 +1,21 @@ +package com.chwl.app.avroom.newuserchargegift + +import android.widget.ImageView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.ui.utils.load +import com.chwl.core.pay.bean.FirstChargeReward +import com.chwl.core.utils.CoreTextUtils + +class RewardAdapter : + BaseQuickAdapter(R.layout.item_new_user_charge_reward) { + override fun convert(helper: BaseViewHolder, item: FirstChargeReward) { + + helper.getView(R.id.iv_pic).load(item.showPir) + + helper.setText(R.id.tv_name, item.showText) + .setText(R.id.tv_time, "(${item.showTime})") + .setGone(R.id.tv_time, !CoreTextUtils.isEmptyText(item.showTime)) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/online/RoomOnlineAvatarAdapter.kt b/app/src/main/java/com/chwl/app/avroom/online/RoomOnlineAvatarAdapter.kt new file mode 100644 index 0000000..41e1672 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/online/RoomOnlineAvatarAdapter.kt @@ -0,0 +1,40 @@ +package com.chwl.app.avroom.online + +import android.widget.ImageView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chad.library.adapter.base.diff.BaseQuickDiffCallback +import com.chwl.app.R +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.app.ui.utils.loadAvatar + +class RoomOnlineAvatarAdapter : + BaseQuickAdapter, BaseViewHolder>(R.layout.room_online_widget_item_avatar) { + + override fun convert(helper: BaseViewHolder, item: Pair?) { + val avatarView = helper.getView(R.id.iv_avatar) + ImageLoadUtils.loadAvatar(item?.second,avatarView) + } + + fun updateData(list: List>?) { + val newList = ArrayList>() + if (list != null) { + newList.addAll(list) + } + setNewDiffData(object : BaseQuickDiffCallback>(newList) { + override fun areItemsTheSame( + oldItem: Pair, + newItem: Pair + ): Boolean { + return newItem.first == oldItem.first + } + + override fun areContentsTheSame( + oldItem: Pair, + newItem: Pair + ): Boolean { + return newItem.second == oldItem.second + } + }, true) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/online/RoomOnlineWidget.kt b/app/src/main/java/com/chwl/app/avroom/online/RoomOnlineWidget.kt new file mode 100644 index 0000000..64e9861 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/online/RoomOnlineWidget.kt @@ -0,0 +1,230 @@ +package com.chwl.app.avroom.online + +import android.content.Context +import android.graphics.Outline +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View +import android.view.ViewOutlineProvider +import androidx.databinding.DataBindingUtil +import com.chwl.app.R +import com.chwl.app.avroom.activity.RoomOnlineUserActivity +import com.chwl.app.databinding.RoomOnlineWidgetBinding +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil +import com.chwl.app.ui.widget.recyclerview.decoration.VerticalDecoration +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.manager.IMNetEaseManager +import com.chwl.core.manager.RoomEvent +import com.chwl.core.room.core.RoomDataService +import com.chwl.core.room.model.AvRoomModel +import com.chwl.core.support.room.FrameLayoutRoomWidget +import com.chwl.core.support.room.RoomContext +import com.chwl.core.support.room.RoomView +import com.chwl.core.support.room.RoomWidget +import com.chwl.core.user.bean.UserInfo +import com.example.lib_utils.UiUtils +import com.example.lib_utils.ktx.singleClick +import com.netease.nim.uikit.business.uinfo.UserInfoHelper +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessageExtension +import io.reactivex.Observable +import java.util.concurrent.TimeUnit + +class RoomOnlineWidget : FrameLayoutRoomWidget, RoomWidget { + + companion object { + const val MAX_DISPLAY_COUNT = 3 + private const val ONLINE_DISPLAY_LIST = "online_display_list" + private const val ONLINE_NUMBER = "online_number" + } + + private val binding: RoomOnlineWidgetBinding = + DataBindingUtil.inflate( + LayoutInflater.from( + context + ), R.layout.room_online_widget, this, true + ) + + private val adapter = RoomOnlineAvatarAdapter() + + private var dataList: MutableList>? = null + + private val dataService: RoomDataService? + get() = roomContext?.findAbility( + RoomDataService::class.java.simpleName + ) + + constructor(context: Context) : super(context) + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) + + constructor( + context: Context, + attrs: AttributeSet?, + defStyleAttr: Int, + defStyleRes: Int + ) : super(context, attrs, defStyleAttr, defStyleRes) + + init { + if (!isInEditMode) { + this.singleClick { + RoomOnlineUserActivity.start(context) + } + adapter.setOnItemClickListener { adapter, view, position -> + RoomOnlineUserActivity.start(context) + } + binding.recyclerView.adapter = adapter + binding.recyclerView.addItemDecoration( + VerticalDecoration( + UIUtil.dip2px(context, 4.5), + false, + false + ) + ) + val isRTL = UiUtils.isRtl(context) + binding.recyclerView.outlineProvider = object : ViewOutlineProvider() { + override fun getOutline(view: View?, outline: Outline?) { + if (isRTL) { + outline?.setRect( + UiUtils.dip2px(9f), + 0, + (view?.width ?: 0), + (view?.height ?: 0), + ) + } else { + outline?.setRect( + 0, + 0, + (view?.width ?: 0) - UiUtils.dip2px(9f), + (view?.height ?: 0), + ) + } + } + } + binding.recyclerView.clipToOutline = true + } + } + + override fun onInitialize(roomView: RoomView, roomContext: RoomContext) { + super.onInitialize(roomView, roomContext) + (dataService?.getData(ONLINE_NUMBER) as? Int)?.let { + updateCount(it) + } + (dataService?.getData(ONLINE_DISPLAY_LIST) as? MutableList>)?.let { + updateList(it) + } + startUpdateOnlineTask() + registerMemberChangedListener() + } + + override fun onUnbindContext() { + super.onUnbindContext() + updateList(null) + updateCount(0) + } + + private fun refreshData() { + val disposable = AvRoomModel.get() + .getRoomOnlineList(AvRoomDataManager.get().roomUid) + .subscribe({ + val newData = it.filter { user-> + !user.isSuperAdmin + } + updateList(newData.take(MAX_DISPLAY_COUNT).map { + Pair(it.uid.toString(), it.avatar) + }.toMutableList()) + updateCount(it.size) + }, { + it.printStackTrace() + }) + getCompositeDisposable().add(disposable) + } + + private fun updateCount(count: Int) { + dataService?.putData(ONLINE_NUMBER, count) + binding.tvNumber.text = count.toString() + } + + private fun updateList(list: MutableList>?) { + dataService?.putData(ONLINE_DISPLAY_LIST, list) + this.dataList = list + adapter.updateData(list) + } + + private fun startUpdateOnlineTask() { + getCompositeDisposable().add(Observable.interval( + 0, 60, TimeUnit.SECONDS + ).subscribe { + refreshData() + }) + } + + private fun registerMemberChangedListener() { + getCompositeDisposable().add(IMNetEaseManager.get().chatRoomEventObservable.subscribe { + when (it.event) { + RoomEvent.ROOM_MEMBER_IN -> { + updateOnlineCount(1) + toItem(it.account, it.chatRoomMessage)?.let { + tryUpdateList(it, true) + } + } + + RoomEvent.ROOM_MEMBER_EXIT -> { + updateOnlineCount(-1) + toItem(it.account, it.chatRoomMessage)?.let { + tryUpdateList(it, false) + } + } + } + }) + } + + private fun toItem(account: String?, message: ChatRoomMessage?): Pair? { + if (account == null) { + return null + } + if (message == null) { + return Pair(account, null) + } + val messageExtension: ChatRoomMessageExtension = message.chatRoomMessageExtension + var avatar = messageExtension.senderAvatar + val extensionData = messageExtension.senderExtension.get(account) as? Map + avatar = (extensionData?.getOrElse("avatar") { avatar } as? String) ?: avatar + + val chatRoomMessageUserInfo = UserInfoHelper.getChatRoomMessageUserInfo(message, account) + if (chatRoomMessageUserInfo != null) { + val isSuperAdmin = chatRoomMessageUserInfo[UserInfo.PLATFORM_ROLE] + if (isSuperAdmin == 1) return null + } + + return Pair(account, avatar) + } + + private fun tryUpdateList(item: Pair, enterOrExit: Boolean) { + val index = dataList?.indexOfFirst { + it.first == item.first + } ?: -1 + if (enterOrExit) { + if (index < 0 && (dataList?.size ?: 0) < MAX_DISPLAY_COUNT) { + dataList?.add(item) + updateList(dataList) + } + } else { + if (index >= 0) { + dataList?.removeAt(index) + updateList(dataList) + } + } + } + + private fun updateOnlineCount(addCount: Int) { + val number = binding.tvNumber.text.toString().toIntOrNull() + if (number != null) { + binding.tvNumber.text = (number + addCount).toString() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/presenter/AvRoomPresenter.java b/app/src/main/java/com/chwl/app/avroom/presenter/AvRoomPresenter.java new file mode 100644 index 0000000..fa0afe9 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/presenter/AvRoomPresenter.java @@ -0,0 +1,535 @@ +package com.chwl.app.avroom.presenter; + +import android.annotation.SuppressLint; +import android.os.Bundle; +import android.text.TextUtils; +import android.util.Log; +import android.util.SparseArray; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.chwl.app.R; +import com.chwl.app.avroom.activity.AVRoomActivity; +import com.chwl.app.avroom.view.IAvRoomView; +import com.chwl.app.base.BaseMvpPresenter; +import com.chwl.app.utils.RoomHelperManager; +import com.chwl.core.Constants; +import com.chwl.core.DemoCache; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.bean.RoomMicInfo; +import com.chwl.core.bean.RoomQueueInfo; +import com.chwl.core.bean.response.ServiceResult; +import com.chwl.core.channel_page.model.ChannelPageModel; +import com.chwl.core.manager.AudioEngineManager; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.manager.IMNetEaseManager; +import com.chwl.core.manager.RoomEvent; +import com.chwl.core.manager.RoomMicQueueModel; +import com.chwl.core.miniworld.event.AudioPartyOpenEvent; +import com.chwl.core.module_hall.hall.HallModel; +import com.chwl.core.monsterhunting.bean.MonsterInfo; +import com.chwl.core.monsterhunting.model.MonsterHuntingModel; +import com.chwl.core.patriarch.exception.PmRoomLimitException; +import com.chwl.core.room.anotherroompk.RoomPKModel; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.core.room.giftvalue.helper.GiftValueMrg; +import com.chwl.core.room.model.AvRoomModel; +import com.chwl.core.room.model.MicQueueModel; +import com.chwl.core.room.queuing_mic.bean.QueuingMicMemeberInfo; +import com.chwl.core.room.queuing_mic.event.QueuingMicNotEmptyEvent; +import com.chwl.core.super_admin.SuperAdminDataMrg; +import com.chwl.core.support.room.AudioRoomContext; +import com.chwl.core.user.UserModel; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.core.utils.LogUtils; +import com.chwl.core.utils.net.RxHelper; +import com.chwl.library.base.PresenterEvent; +import com.chwl.library.net.rxnet.callback.CallBack; +import com.chwl.library.threadmgr.ThreadPoolManager; +import com.chwl.library.utils.JavaUtil; +import com.chwl.library.utils.ResUtil; +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.reflect.TypeToken; +import com.netease.nimlib.sdk.chatroom.model.ChatRoomInfo; +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMember; +import com.netease.nimlib.sdk.chatroom.model.EnterChatRoomResultData; + +import org.greenrobot.eventbus.EventBus; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import io.reactivex.Observable; +import io.reactivex.ObservableSource; +import io.reactivex.Observer; +import io.reactivex.Single; +import io.reactivex.SingleSource; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.functions.Consumer; +import io.reactivex.functions.Function; +import io.reactivex.schedulers.Schedulers; + +/** + *

+ * + * @author jiahui + * @date 2017/12/11 + */ +public class AvRoomPresenter extends BaseMvpPresenter { + + private static final String TAG = "AvRoomPresenter"; + private static final String GET_ROOM_FROM_IMNET_ERROR = "-1101"; + private final AvRoomModel mAvRoomModel; + private final Gson mGson; + private Disposable mGetOnlineNumberDisposable; + + public AvRoomPresenter() { + mAvRoomModel = AvRoomModel.get(); + mGson = new Gson(); + } + + /** + * 进入云信聊天室回调 + */ + @SuppressLint("CheckResult") + public void enterRoom(@NonNull RoomInfo roomInfo, int fromType, String fromNick, String fromUid) { + + final RoomInfo currentRoom = AvRoomDataManager.get().mCurrentRoomInfo; + if (currentRoom != null) { + if (currentRoom.getUid() == roomInfo.getUid()) { + getMvpView().dismissLoadingDialog(); + return; + } + //进入新的房间需要先退出房间 + exitRoom(); + } + AvRoomDataManager.get().updateServiceRoomInfo(roomInfo); + mAvRoomModel.enterRoom(roomInfo.getRoomId(), 3, fromType, fromNick, fromUid) + .flatMap(this::dealServerMicInfo) + .flatMap((Function, ObservableSource>>) roomQueue -> RoomMicQueueModel.INSTANCE.queueMicQueue(roomInfo.getRoomId(),roomQueue)) + .compose(bindUntilEvent(PresenterEvent.DESTROY)) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(roomQueueInfoSparseArray -> { + // 11-11 房间背景自定义,发现 背景不一致,这里不大改怕处bug, 这里设置下最新的背景 + AvRoomDataManager.get().mCurrentRoomInfo.setBackPic(roomInfo.getBackPic()); + AvRoomDataManager.get().replaceMicQueue(roomQueueInfoSparseArray); + long uid = AuthModel.get().getCurrentUid(); + AudioEngineManager.get().startRtcEngine(uid, roomInfo.getAudioSdkType()); + // TODO 临时方案:后续逐步完善整个房间的RoomContext替换计划 + new AudioRoomContext(roomInfo.getUid()).run(); + if (getMvpView() != null) { + getMvpView().enterRoomSuccess(); + } + mAvRoomModel.userRoomIn( + String.valueOf(uid), + roomInfo.getUid(), + fromType == AVRoomActivity.FROM_TYPE_GAME_RECOMMEND ? 1 : 0, + fromType, + fromUid) + .subscribe((stringServiceResult) -> EventBus.getDefault().post(new AudioPartyOpenEvent())); + mAvRoomModel.loadMessageHistory(AvRoomDataManager.get().clearScreenTime); + IMNetEaseManager.get().joinAvRoom(); + initAnotherPKData(); + }, this::dealEnterRoomError); + } + + @SuppressLint("CheckResult") + private void initAnotherPKData() { + if (AvRoomDataManager.get().isOpenAnotherPKMode()) { + RoomPKModel.INSTANCE.getRoomPKData(AvRoomDataManager.get().getRoomUid()) + .compose(bindToLifecycle()) + .subscribe(roomPkBean -> { + AvRoomDataManager.get().roomPkLiveData.setValue(roomPkBean); + if (AvRoomDataManager.get().isSingleRoom()){ + AudioEngineManager.get().setRemoteMute(roomPkBean.getAUid(), roomPkBean.getAMicStatus() == 0); + if (AvRoomDataManager.get().isRoomOwner()) { + AudioEngineManager.get().connectOtherRoom(String.valueOf(roomPkBean.getARoomId()), roomPkBean.getAUid()); + } + } + }); + } + } + + private void dealEnterRoomError(Throwable throwable) { + throwable.printStackTrace(); + String roomUid = AvRoomDataManager.get().mCurrentRoomInfo != null ? + String.valueOf(AvRoomDataManager.get().mCurrentRoomInfo.getUid()) : ""; + String error = ""; + switch (throwable.getMessage()) { + case "414": + error = ResUtil.getString(R.string.avroom_presenter_avroompresenter_02); + if (getMvpView() != null) { + getMvpView().enterRoomFail(-1, error); + } + break; + case "404": + case "13002": + if (getMvpView() != null) + getMvpView().showFinishRoomView(AvRoomDataManager.get().getRoomUid()); + error = ResUtil.getString(R.string.avroom_presenter_avroompresenter_03); + break; + case "403": + error = ResUtil.getString(R.string.avroom_presenter_avroompresenter_04); + if (getMvpView() != null) { + getMvpView().enterRoomFail(-1, error); + } + break; + case "500": + error = ResUtil.getString(R.string.avroom_presenter_avroompresenter_05); + break; + case "13001": + error = ResUtil.getString(R.string.avroom_presenter_avroompresenter_06); + if (getMvpView() != null) { + getMvpView().enterRoomFail(-1, error); + } + break; + case "13003": + error = ResUtil.getString(R.string.avroom_presenter_avroompresenter_07); + if (getMvpView() != null) + getMvpView().showBlackEnterRoomView(); + break; + case GET_ROOM_FROM_IMNET_ERROR: + error = ResUtil.getString(R.string.avroom_presenter_avroompresenter_08); + exitRoom(); + if (getMvpView() != null) { + getMvpView().enterRoomFail(-1, ResUtil.getString(R.string.avroom_presenter_avroompresenter_09)); + } + break; + default: + error = ResUtil.getString(R.string.avroom_presenter_avroompresenter_010); + if (getMvpView() != null) { + getMvpView().enterRoomFail(-1, error); + } + break; + + } + + // 首页取消转圈圈 + IMNetEaseManager.get().getChatRoomEventObservable().onNext(new RoomEvent().setEvent(RoomEvent.ROOM_EXIT)); + } + + + /** + * 处理服务端坑位信息 + */ + @Nullable + private ObservableSource> dealServerMicInfo(EnterChatRoomResultData enterChatRoomResultData) { + AvRoomDataManager.get().mEnterChatRoomResultData = enterChatRoomResultData; + if (enterChatRoomResultData == null) + return Observable.error(new Throwable(GET_ROOM_FROM_IMNET_ERROR)); + else { + final ChatRoomInfo roomInfo = enterChatRoomResultData.getRoomInfo(); + if (roomInfo == null) { + return Observable.error(new Throwable(GET_ROOM_FROM_IMNET_ERROR)); + } + AvRoomDataManager.get().mCurrentRoomInfo.onlineNum = roomInfo.getOnlineUserCount(); + Map extension = roomInfo.getExtension(); + if (extension != null) { + String roomInfoStr = (String) extension.get(Constants.KEY_CHAT_ROOM_INFO_ROOM); + if (!TextUtils.isEmpty(roomInfoStr)) { + RoomInfo extRoomInfo = mGson.fromJson(roomInfoStr, RoomInfo.class); + extRoomInfo.setRoomId(Long.parseLong(roomInfo.getRoomId())); + extRoomInfo.setServerRedEnvelopeSwitch(AvRoomDataManager.get().mCurrentRoomInfo.serverRedEnvelopeSwitch); + extRoomInfo.onlineNum = AvRoomDataManager.get().mCurrentRoomInfo.onlineNum; + //云信服务端信息 + AvRoomDataManager.get().mCurrentRoomInfo = extRoomInfo; + } + //获取云信麦序相关信息 + String roomMicStr = (String) extension.get(Constants.KEY_CHAT_ROOM_INFO_MIC); + LogUtils.d(roomMicStr); + if (!TextUtils.isEmpty(roomMicStr)) { + //清除魅力值(重新进房会触发退房,已经清除过了) + GiftValueMrg.get().clearObsever(); + //初始化所有坑位 + Map micMapStr = mGson.fromJson(roomMicStr, new TypeToken>() { + }.getType()); + SparseArray queue = new SparseArray<>(); + for (Map.Entry entry : micMapStr.entrySet()) { + queue.put(Integer.valueOf(entry.getKey()), + new RoomQueueInfo(mGson.fromJson(entry.getValue(), RoomMicInfo.class), null)); + } + return Observable.just(queue); + } + } + return Observable.error(new Throwable(GET_ROOM_FROM_IMNET_ERROR)); + } + } + + public void exitRoom() { + mAvRoomModel.exitRoom(new CallBack() { + @Override + public void onSuccess(RoomInfo data) { + if (getMvpView() != null) { + getMvpView().exitRoom(data); + RoomHelperManager.INSTANCE.setRoomUid(0L); + } + } + + @Override + public void onFail(int code, String error) { + + } + }); + } + + @SuppressLint("CheckResult") + public void requestRoomInfoFromService(String uId) { + if (TextUtils.isEmpty(uId)) { + return; + } + mAvRoomModel.requestRoomResult(uId, 0) + .compose(bindUntilEvent(PresenterEvent.DESTROY)) + .doOnError(throwable -> { + if (getMvpView() != null) { + getMvpView().requestRoomInfoFailView(throwable); + } + }) + .doOnSuccess(roomResult -> { + if (roomResult == null) { + if (getMvpView() != null) { + getMvpView().requestRoomInfoFailView(new Throwable(ResUtil.getString(R.string.avroom_presenter_avroompresenter_011))); + } + return; + } + if (roomResult.isSuccess()) { + RoomInfo data = roomResult.getData(); + if (data == null || data.getRoomId() == 0 || !data.isValid()) { + if (getMvpView() != null) { + getMvpView().showFinishRoomView(JavaUtil.str2long(uId)); + } + return; + } + // 如果当前是排麦模式,就自己去拉一次排麦列表 + if (AvRoomDataManager.get().isRoomInQueuingMicMode(data)) { + //noinspection ResultOfMethodCallIgnored + MicQueueModel.get() + .loadMicQueueList(data.getUid(), 1, Constants.PAGE_SIZE) + .subscribe((respQueuingMicListInfo, throwable) -> { + if (throwable == null) { + List queue = respQueuingMicListInfo.getQueue(); + if (queue != null) { + if (queue.size() > 0) { + EventBus.getDefault().post(new QueuingMicNotEmptyEvent()); + } + } + } + }); + } + if (getMvpView() != null) { + getMvpView().requestRoomInfoSuccessView(data); + } + + return; + } + //进房失败 + if (getMvpView() != null) { + getMvpView().requestRoomInfoFailView(RxHelper.createThrowable(roomResult)); + } + }) + .subscribe(); + } + + /** + * 获取房间内固定成员列表 + */ + public void getNormalChatMember() { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) { + return; + } + long currentUid = AuthModel.get().getCurrentUid(); + mAvRoomModel.getNormalChatMember(String.valueOf(roomInfo.getRoomId()), currentUid); + } + + /** + * 获取房间内固定成员列表 + */ + @SuppressLint("CheckResult") + public void getSuperAdminList() { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) { + return; + } + HallModel.get().getRoomSuperAdminList(roomInfo.getUid()) + .compose(bindToLifecycle()) + .toObservable() + .flatMap(Observable::fromIterable) + .map(superAdminInfo -> { + ChatRoomMember chatRoomMember = new ChatRoomMember(); + chatRoomMember.setAccount(String.valueOf(superAdminInfo.getUid())); + chatRoomMember.setAvatar(superAdminInfo.getAvatar()); + chatRoomMember.setNick(superAdminInfo.getNick()); + return chatRoomMember; + }) + .toList() + .subscribe(chatRoomMembers -> AvRoomDataManager.get().setAllRoomSuperAdminList(chatRoomMembers)); + } + + /** + * 检查是否需要显示新用户打招呼消息弹窗 + */ + @SuppressLint("CheckResult") + public void checkHelloMessage() { + + if (AvRoomDataManager.get().mCurrentRoomInfo == null) return; + + Single.timer(5, TimeUnit.SECONDS) + .flatMap(aLong -> ChannelPageModel.get().checkHelloMessage()) + .compose(bindToLifecycle()) + .subscribe(helloMessageInfo -> { + if (getMvpView() != null && helloMessageInfo.getRoomPopup()) { + getMvpView().showHelloMessageDialog(helloMessageInfo); + } + }); + + } + + /** + * 检查是否需要显示新用户礼弹窗 + */ + @SuppressLint("CheckResult") + public void checkNewUserGift() { + + if (AvRoomDataManager.get().isRoomOwner() || + !DemoCache.readNewUserGift()) + return; + + Single.timer(3, TimeUnit.SECONDS) + .flatMap(aLong -> AvRoomModel.get().getNewUserGift()) + .compose(bindToLifecycle()) + .subscribe(giftInfo -> { + DemoCache.saveNewUserGift(false); + if (getMvpView() != null && !TextUtils.isEmpty(giftInfo.getGiftUrl())) { + getMvpView().showNewUserDialog(giftInfo); + } + }); + + } + + /** + * 检查是否需要显示首充弹窗 + */ + @SuppressLint("CheckResult") + public void checkFirstCharge() { + } + + /** + * 更新首充弹窗显示 + */ + @SuppressLint("CheckResult") + public void postFirstCharge() { + if (AvRoomDataManager.get().isRoomOwner()) return; + AvRoomModel.get().postFirstCharge() + .compose(bindToLifecycle()) + .subscribe(); + } + + private void startGetOnlineMemberNumberJob() { + Observable.interval(1, 10, TimeUnit.SECONDS, Schedulers.from(ThreadPoolManager.instance().getScheduleExecutor())) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + mGetOnlineNumberDisposable = d; + } + + @Override + public void onNext(Long aLong) { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) return; + Log.d(TAG, "onNext: has login in IM: " + AuthModel.get().isImLogin()); + Disposable subscribe = mAvRoomModel.startGetOnlineMemberNumberJob(roomInfo.getRoomId()) + .observeOn(AndroidSchedulers.mainThread()) + .compose(AvRoomPresenter.this.bindUntilEvent(PresenterEvent.DESTROY)) + .subscribe(new Consumer() { + @Override + public void accept(ChatRoomInfo chatRoomInfo) throws Exception { + if (chatRoomInfo == null) return; + int onlineUserCount = chatRoomInfo.getOnlineUserCount(); + if (onlineUserCount <= SuperAdminDataMrg.OFFSET_COUNT) { + //减去超管的人数 + onlineUserCount = onlineUserCount - SuperAdminDataMrg.get().getSAdminList().size(); + if (onlineUserCount < 0) { + onlineUserCount = 0; + } + } + if (AvRoomDataManager.get().mCurrentRoomInfo != null) + AvRoomDataManager.get().mCurrentRoomInfo.onlineNum = onlineUserCount; + if (getMvpView() != null) { + getMvpView().onRoomOnlineNumberSuccess(onlineUserCount); + } + SuperAdminDataMrg.get().updateList(onlineUserCount); + } + }, new Consumer() { + @Override + public void accept(Throwable throwable) throws Exception { + throwable.printStackTrace(); + } + }); + } + + @Override + public void onError(Throwable e) { + } + + @Override + public void onComplete() { + } + }); + + } + + public void getMonster() { + MonsterHuntingModel.get().getRoomMonsterList() + .compose(bindToLifecycle()) + .subscribe((monsterInfoServiceResult, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + // TODO: 16/04/2018 不知道为何,就是有异常 +// getMvpView().getMonsterInfoFail(ResUtil.getString(R.string.avroom_presenter_avroompresenter_012)); + } else if (monsterInfoServiceResult.isSuccess()) { + MonsterInfo monsterInfo = monsterInfoServiceResult.getData(); + if (monsterInfo != null) { + getMvpView().getMonsterInfoSuccess(monsterInfo); + } + } else if (!monsterInfoServiceResult.isSuccess()) { + getMvpView().getMonsterInfoFail(monsterInfoServiceResult.getError()); + } + }); + } + + + @Override + public void onDestroyPresenter() { + super.onDestroyPresenter(); + if (mGetOnlineNumberDisposable != null) { + mGetOnlineNumberDisposable.dispose(); + mGetOnlineNumberDisposable = null; + } + } + + @Override + public void onCreatePresenter(@Nullable Bundle saveState) { + super.onCreatePresenter(saveState); + startGetOnlineMemberNumberJob(); + } + + public void judgeIsLimitEnter() { + UserModel.get().getCurrentUserInfo() + .filter(UserInfo::isParentMode) + .flatMapSingle((Function>>) + userInfo -> AvRoomModel.get().getLimitRoomInfo()) + .doOnError(throwable -> { + if (throwable instanceof PmRoomLimitException) { + if (getMvpView() != null) { + getMvpView().recoverRoomMinWhenPmLimit(throwable); + } + } + }) + .subscribe(); + } + +} diff --git a/app/src/main/java/com/chwl/app/avroom/presenter/BaseRoomPresenter.java b/app/src/main/java/com/chwl/app/avroom/presenter/BaseRoomPresenter.java new file mode 100644 index 0000000..da96df6 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/presenter/BaseRoomPresenter.java @@ -0,0 +1,607 @@ +package com.chwl.app.avroom.presenter; + +import android.annotation.SuppressLint; +import android.text.TextUtils; +import android.util.Log; + +import androidx.annotation.Nullable; + +import com.chwl.app.R; +import com.chwl.app.avroom.view.IBaseRoomView; +import com.chwl.app.base.BaseMvpPresenter; +import com.chwl.app.public_chat.core.ChatRoomClient; +import com.chwl.app.public_chat.core.ChatRoomClientManager; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.bean.RoomQueueInfo; +import com.chwl.core.gift.GiftModel; +import com.chwl.core.helper.AtProxy; +import com.chwl.core.im.custom.bean.CustomAttachment; +import com.chwl.core.im.custom.bean.RequestUpmicAttachment; +import com.chwl.core.im.custom.bean.RoomInfoAttachment; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.manager.IMNetEaseManager; +import com.chwl.core.praise.PraiseModel; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.core.room.exception.AntiSpamHitException; +import com.chwl.core.room.game.GameStatus; +import com.chwl.core.room.giftvalue.helper.GiftValueMrg; +import com.chwl.core.room.model.AvRoomModel; +import com.chwl.core.room.model.HomePartyModel; +import com.chwl.core.room.model.RoomBaseModel; +import com.chwl.core.room.queue.bean.MicMemberInfo; +import com.chwl.core.super_admin.model.SuperAdminModel; +import com.chwl.core.super_admin.util.SuperAdminUtil; +import com.chwl.core.user.UserModel; +import com.chwl.core.user.bean.BaseInfo; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.core.utils.net.DontWarnObserver; +import com.chwl.core.utils.net.RxHelper; +import com.chwl.library.base.PresenterEvent; +import com.chwl.library.common.util.OtherExtKt; +import com.chwl.library.net.rxnet.callback.CallBack; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.netease.nimlib.sdk.chatroom.ChatRoomMessageBuilder; +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage; +import com.netease.nimlib.sdk.util.Entry; +import com.orhanobut.logger.Logger; + +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +import io.reactivex.Single; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.functions.BiConsumer; +import io.reactivex.functions.Consumer; + + +/** + *

+ * + * @author jiahui + * @date 2017/12/8 + */ +public class BaseRoomPresenter extends BaseMvpPresenter { + + /** + * 顯示關註房主的時間 + */ + public static final int SHOW_FOLLOW_TIME = 3 * 60 * 1000; + public final Gson gson = new Gson(); + public final HomePartyModel mHomePartyMode; + public final AvRoomModel mAvRoomModel; + public final SuperAdminModel mSuperAdminModel; + public final RoomBaseModel mRoomBaseModel ; + /** + * 判斷所坑服務端是否響應回來了 + */ + private boolean mIsLockMicPosResultSuccess = true; + private boolean mIsUnLockMicPosResultSuccess = true; + + public BaseRoomPresenter() { + mHomePartyMode = new HomePartyModel(); + mAvRoomModel = AvRoomModel.get(); + mSuperAdminModel = new SuperAdminModel(); + mRoomBaseModel = new RoomBaseModel(); + } + + /** + * 麥坑點擊處理,麥上沒人的時候 + * + * @param micPosition 麥序位置 + * @param chatRoomMember 坑上的用戶 + */ + @SuppressLint("CheckResult") + public void microPhonePositionClick(final int micPosition, MicMemberInfo chatRoomMember) { + final RoomInfo currentRoom = AvRoomDataManager.get().mCurrentRoomInfo; + if (currentRoom == null) { + return; + } + if (AvRoomDataManager.get().isSelfGamePlaying()) { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_presenter_baseroompresenter_01)); + return; + } + if (UserModel.get().getCacheLoginUserInfo() != null) { + UserModel.get().getCacheLoginUserInfo().setGameStatus(GameStatus.STATUS_NOT_JOIN); + } + final String currentUid = String.valueOf(AuthModel.get().getCurrentUid()); + if (AvRoomDataManager.get().isRoomOwner(currentUid) || AvRoomDataManager.get().isRoomAdmin(currentUid) || SuperAdminUtil.isSuperAdmin()) { + if (AvRoomDataManager.get().isRoomOwner(currentUid) && + currentRoom.isLeaveMode() && + !AvRoomDataManager.get().isSingleRoom()) { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_presenter_baseroompresenter_02)); + return; + } + onOwnerUpMicroClick(micPosition, Long.parseLong(currentUid)); + } else { + + if (AvRoomDataManager.get().isSingleRoom()) { + if (AvRoomDataManager.get().isOwnerOnMic()) { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_presenter_baseroompresenter_03)); + } else { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_presenter_baseroompresenter_04)); + UserModel.get() + .getCurrentUserInfo() + .subscribe(this::requestUpMic, Throwable::printStackTrace); + } + return; + } + RoomQueueInfo roomQueueInfo = AvRoomDataManager.get().getRoomQueueMemberInfoByMicPosition(micPosition); + if (roomQueueInfo != null && roomQueueInfo.mRoomMicInfo.isMicLock()) { + if (AvRoomDataManager.get().isQueuingMicro()) { + String msg; + if (AvRoomDataManager.get().isOnMic(AuthModel.get().getCurrentUid())) { + msg = ResUtil.getString(R.string.avroom_presenter_baseroompresenter_05); + } else { + msg = ResUtil.getString(R.string.avroom_presenter_baseroompresenter_06); + } + SingleToastUtil.showToast(msg); + } + return; + } + if (AvRoomDataManager.get().isQueuingMicro() && AvRoomDataManager.get().myIsInQueue) { + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_presenter_baseroompresenter_07)); + return; + } + getMvpView().toUpMicroPhone(micPosition, currentUid, false); + + } + } + + //發送雲信消息,請求上麥 + private void requestUpMic(UserInfo userInfo) { + RequestUpmicAttachment attachment = new RequestUpmicAttachment(0); + attachment.setUserInfo(userInfo); + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + ChatRoomMessage message = ChatRoomMessageBuilder.createChatRoomCustomMessage( + roomInfo.getRoomId() + "", + attachment + ); + IMNetEaseManager.get().sendChatRoomMessage(message, false).subscribe(); + } + + + private void onOwnerUpMicroClick(final int micPosition, final long currentUid) { + RoomQueueInfo roomQueueInfo = AvRoomDataManager.get().getRoomQueueMemberInfoByMicPosition(micPosition); + if (roomQueueInfo == null) return; + if (getMvpView() != null) + getMvpView().showOwnerClickDialog(roomQueueInfo.mRoomMicInfo, micPosition, currentUid); + } + + public void lockMicroPhone(int micPosition) { + if (!mIsLockMicPosResultSuccess) { + return; + } + mIsLockMicPosResultSuccess = false; + RoomInfo currentRoom = AvRoomDataManager.get().mCurrentRoomInfo; + if (currentRoom == null) { + return; + } + final String currentUid = String.valueOf(currentRoom.getUid()); + mHomePartyMode.lockMicroPhone(micPosition, currentUid, AuthModel.get().getTicket()) + .doOnSuccess(data -> { + Logger.i("用戶%1$s鎖坑成功: %2$s", String.valueOf(currentUid), data); + mIsLockMicPosResultSuccess = true; + }) + .doOnError(throwable -> { + Logger.i("用戶%1$s鎖坑失敗: %2$s", String.valueOf(currentUid), + RxHelper.getNotEmptyError(throwable)); + mIsLockMicPosResultSuccess = true; + }) + .subscribe(); + } + + /** + * 坑位釋放鎖 + */ + public void unLockMicroPhone(int micPosition) { + if (!mIsUnLockMicPosResultSuccess) { + return; + } + mIsUnLockMicPosResultSuccess = false; + RoomInfo currentRoom = AvRoomDataManager.get().mCurrentRoomInfo; + if (currentRoom == null) { + return; + } + final String currentUid = String.valueOf(currentRoom.getUid()); + if (AvRoomDataManager.get().isRoomAdmin() || AvRoomDataManager.get().isRoomOwner(currentUid)) { + mHomePartyMode.unLockMicroPhone(micPosition, currentUid, AuthModel.get().getTicket()) + .subscribe(new Consumer() { + @Override + public void accept(String data) throws Exception { + Logger.i("用戶%1$s解麥成功: %2$s", String.valueOf(currentUid), data); + mIsUnLockMicPosResultSuccess = true; + } + }, new Consumer() { + @Override + public void accept(Throwable throwable) throws Exception { + Logger.i("用戶%1$s解麥失敗: %2$s", String.valueOf(currentUid), throwable.getMessage()); + mIsUnLockMicPosResultSuccess = true; + } + }); + } + } + + /** + * 下麥 + * + * @param micPosition + * @param isKick 是否是主動的 + */ + public void downMicroPhone(int micPosition, final boolean isKick) { + final RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) { + return; + } + final String currentUid = String.valueOf(AuthModel.get()); + mHomePartyMode.downMicroPhone(micPosition, new CallBack() { + @Override + public void onSuccess(String data) { + Logger.i("用戶%1$s下麥成功:%2$s", currentUid, data); + if (!isKick) { + //被踢了 + if (getMvpView() != null) { + getMvpView().kickDownMicroPhoneSuccess(); + } + } + } + + @Override + public void onFail(int code, String error) { + Logger.i("用戶%1$s下麥失敗:%2$s----", currentUid, error); + } + }); + } + + /** + * 上麥 + * + * @param micPosition + * @param uId + * @param isInviteUpMic 是否是主動的,false:主動 + * @param isReconnect 是否需要清除禮物值,普通情況下上麥傳false,斷網重連傳ture + */ + public void upMicroPhone(final int micPosition, final String uId, boolean isInviteUpMic, boolean isReconnect) { + final RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) { + return; + } + if (!isInviteUpMic) { + upMicroPhone(micPosition, uId, isInviteUpMic, roomInfo, isReconnect); + } else { + AvRoomDataManager.get().haveStartDragon = false; + upMicroPhone(micPosition, uId, isInviteUpMic, roomInfo, isReconnect); + } + } + + public void upMicroPhone(final int micPosition, final String uId, boolean isInviteUpMic) { + upMicroPhone(micPosition, uId, isInviteUpMic, false); + } + + + public void upMicroPhone(int micPosition, String uId, boolean isInviteUpMic, RoomInfo roomInfo, boolean isReconnect) { + mHomePartyMode.upMicroPhone(micPosition, uId, String.valueOf(roomInfo.getRoomId()), + isInviteUpMic, new CallBack() { + @Override + public void onSuccess(String data) { + Logger.i("用戶%1$s上麥成功:%2$s", uId, data); + if (!isReconnect) { + GiftValueMrg.get().requestUpMic(micPosition, uId); + } else { + GiftValueMrg.get().handleReconnect(true); + } + } + + @Override + public void onFail(int code, String error) { + if (code == RoomBaseModel.CODE_UPDATE_MIC) { + if (getMvpView() != null) { + getMvpView().updateMicView(); + } + } + Logger.i("用戶%1$s上麥失敗:%2$s----", uId, error); + } + }); + } + + /** + * 邀請用戶上麥 + * + * @param micInfo 要邀請的用戶 + * @param position 坑位 + */ + public void inviteMicroPhone(final BaseInfo micInfo, final int position) { + final long micUid = micInfo.getUid(); + if (AvRoomDataManager.get().isOnMic(micUid)) { + return; + } + //如果點擊的就是自己,那這裏就是自己上麥 + if (AvRoomDataManager.get().isOwner(micUid)) { + upMicroPhone(position, String.valueOf(micUid), true); + return; + } + long roomUid = AvRoomDataManager.get().getRoomUid(); + if (roomUid > 0) { + + } + if (AvRoomDataManager.get().is19Room() && AvRoomDataManager.get().is19RoomBoosItemPos(position)) { + mRoomBaseModel.getRoomBossMicUp(roomUid, micUid,true) + .doOnSuccess(s -> { + doInviteMicroPhone(micInfo, position, micUid); + }).doOnError(throwable -> { + if (throwable != null) { + OtherExtKt.doToast(throwable.getMessage()); + } + Logger.i("邀請用戶%d上麥失敗!!!" + micUid); + }).subscribe(); + } else { + doInviteMicroPhone(micInfo, position, micUid); + } + } + + /** + * 执行 : 邀請用戶上麥 + */ + private void doInviteMicroPhone(final BaseInfo micInfo, final int position,final long micUid) { + mHomePartyMode.inviteMicroPhone(micInfo, position) + .compose(bindUntilEvent(PresenterEvent.DESTROY)) + .doOnSuccess(chatRoomMessage -> { + Logger.i("邀請用戶%d上麥成功!!!" + micUid); + }) + .doOnError(throwable -> { + Logger.i("邀請用戶%d上麥失敗!!!" + micUid); + }) + .subscribe(); + + } + + + /** + * 開麥 + * + * @param micPosition + */ + public void openMicroPhone(int micPosition) { + final RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) { + return; + } + mHomePartyMode.openMicroPhone(micPosition, roomInfo.getUid()) + .subscribe(new DontWarnObserver() { + @Override + public void accept(String data, String error) { + super.accept(data, error); + if (error != null) { + Logger.i("用戶%1$s開麥失敗: %2$s", String.valueOf(roomInfo.getUid()), error); + } else { + Logger.i("用戶%1$s開麥成功: %2$s", String.valueOf(roomInfo.getUid()), data); + } + } + }); + } + + /** + * 閉麥 + * + * @param micPosition + */ + public void closeMicroPhone(int micPosition) { + final RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) { + return; + } + mHomePartyMode.closeMicroPhone(micPosition, roomInfo.getUid()) + .doOnSuccess(data -> { + Logger.i("用戶%1$s閉麥成功: %2$s", String.valueOf(roomInfo.getUid()), data); + }) + .doOnError(throwable -> { + Logger.i("用戶%1$s閉麥失敗: %2$s", String.valueOf(roomInfo.getUid()), + RxHelper.getNotEmptyError(throwable)); + }) + .subscribe(); + } + + public void roomOperate(int operate) { + mSuperAdminModel.roomOperate(operate) + .subscribe(); + } + + @SuppressLint("CheckResult") + public void chatRoomReConnect(final RoomQueueInfo queueInfo) { + final RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) return; + mHomePartyMode.queryRoomMicInfo(String.valueOf(roomInfo.getRoomId())) + .delay(1, TimeUnit.SECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(entries -> { + if (!ListUtils.isListEmpty(entries)) { + JsonParser jsonParser = new JsonParser(); + MicMemberInfo chatRoomMember; + for (Entry entry : entries) { + RoomQueueInfo roomQueueInfo = AvRoomDataManager.get().mMicQueueMemberMap.get(Integer.parseInt(entry.key)); + if (roomQueueInfo != null) { + JsonObject valueJsonObj = jsonParser.parse(entry.value).getAsJsonObject(); + if (valueJsonObj != null) { + chatRoomMember = gson.fromJson(valueJsonObj, MicMemberInfo.class); + roomQueueInfo.mChatRoomMember = chatRoomMember; + } + AvRoomDataManager.get().addRoomQueueInfo(entry.key, roomQueueInfo); + } + } + } else { + //麥上都沒有人 + AvRoomDataManager.get().resetMicMembers(); + } + if (getMvpView() != null) + getMvpView().chatRoomReConnectView(); + //之前在麥上 + if (queueInfo != null && queueInfo.mChatRoomMember != null && queueInfo.mRoomMicInfo != null) { + RoomQueueInfo roomQueueInfo = AvRoomDataManager.get() + .getRoomQueueMemberInfoByMicPosition(queueInfo.mRoomMicInfo.getPosition()); + //麥上沒人 + String account = queueInfo.mChatRoomMember.getAccount(); + if (roomQueueInfo != null && (roomQueueInfo.mChatRoomMember == null || + Objects.equals(account, roomQueueInfo.mChatRoomMember.getAccount()))) { + roomQueueInfo.mChatRoomMember = null; + //斷網重連,不要清除麥上的禮物值 + upMicroPhone(queueInfo.mRoomMicInfo.getPosition(), account, true, true); + } + } + IMNetEaseManager.get().mCacheRoomQueueInfo = null; + Logger.i("斷網重連獲取隊列信息成功...." + entries); + }, new Consumer() { + @Override + public void accept(Throwable throwable) throws Exception { + throwable.printStackTrace(); + Logger.i("斷網重連獲取隊列信息失敗...."); + } + }); + } + + public void userRoomIn() { + final RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) return; + long currentUid = AuthModel.get().getCurrentUid(); + mAvRoomModel.userRoomIn(String.valueOf(currentUid), roomInfo.getUid(), 0,0, "") + .delay(1, TimeUnit.SECONDS) + .observeOn(AndroidSchedulers.mainThread()).subscribe(); + } + + public void updateScreen(boolean isCloseScreen) { + String contentText; + if (isCloseScreen) { + ChatRoomMessage firstMsg = IMNetEaseManager.get().getFirstMessageContent(); + IMNetEaseManager.get().addCloseScreenMessages(firstMsg); + if (AvRoomDataManager.get().closeScreenBySAdmin()) { + contentText = ResUtil.getString(R.string.avroom_fragment_homepartyfragment_015); + } else { + contentText = ResUtil.getString(R.string.avroom_fragment_homepartyfragment_06); + } + } else { + contentText = ResUtil.getString(R.string.avroom_fragment_homepartyfragment_014); + } + RoomInfoAttachment attachment = new RoomInfoAttachment(CustomAttachment.CUSTOM_MSG_UPDATE_ROOM_INFO, + CustomAttachment.CUSTOM_MSG_UPDATE_ROOM_INFO_CLOSE_SCREEN); + ChatRoomMessage screenMsg = ChatRoomMessageBuilder.createChatRoomCustomMessage( + String.valueOf(AvRoomDataManager.get().getRoomId()), + attachment + ); + screenMsg.setContent(contentText); + IMNetEaseManager.get().addCloseScreenMessages(screenMsg); + } + + + /** + * 檢查是否關註了這個用戶 + * + * @param uid + */ + @SuppressLint("CheckResult") + public void checkFollow(long uid) { + Single.timer(SHOW_FOLLOW_TIME, TimeUnit.MILLISECONDS) + .compose(bindUntilEvent(PresenterEvent.DESTROY)) + .flatMap(s -> PraiseModel.get().isPraised(AuthModel.get().getCurrentUid(), uid)) + .toObservable() + .takeWhile(aBoolean -> !aBoolean && getMvpView() != null) + .doOnNext(aBoolean -> getMvpView().noFollow()) + //個人主播房新加的關註提醒彈窗,以後還會不會有呢??? + .takeWhile(aBoolean -> !AvRoomDataManager.get().isSingleRoom()) + .delay(4, TimeUnit.MINUTES) + .single(false) + .flatMap(aBoolean -> PraiseModel.get().isPraised(AuthModel.get().getCurrentUid(), uid)) + .toObservable() + .takeWhile(aBoolean -> !aBoolean && getMvpView() != null) + .doOnNext(aBoolean -> getMvpView().showAttentionDialog()) + .subscribe(); + +// Observable.interval(1, 5, TimeUnit.MINUTES) +// .compose(bindUntilEvent(PresenterEvent.DESTROY)) +// .takeWhile(aLong -> !AvRoomDataManager.get().isRoomFans && getMvpView() != null) +// .subscribe(aLong -> getMvpView().noFollow2()); + } + + /** + * 關註房主 + * + * @param position + * @param ownerUid + */ + @SuppressLint("CheckResult") + public void followOwner(int position, long ownerUid) { + PraiseModel.get().praise(ownerUid, true).subscribe(new BiConsumer() { + @Override + public void accept(String s, Throwable throwable) throws Exception { + if (getMvpView() == null) { + return; + } + if (throwable == null) { + getMvpView().onFollowSuccess(position); + } else { + getMvpView().onFollowFail(throwable.getMessage()); + } + } + }); + } + + /*** + * 發送房間消息 + * @param message + */ + @SuppressLint("CheckResult") + public void sendTextMsg(String message, @Nullable AtProxy atProxy) { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null || TextUtils.isEmpty(message)) return; + IMNetEaseManager.get().sendTextMsg(roomInfo.getRoomId(), message, atProxy) + .subscribe(new BiConsumer() { + @Override + public void accept(ChatRoomMessage chatRoomMessage, + Throwable throwable) throws Exception { + if (throwable != null) { + if (throwable instanceof AntiSpamHitException) { + Log.e("sendTextMsg", throwable.getMessage()); + } else { + Logger.i("發送房間信息失敗:" + throwable.getMessage()); + } + } else { + getMvpView().onSendMsgSuccess(message); + IMNetEaseManager.get().addMessagesImmediately(chatRoomMessage); + Logger.i("發送房間信息成功:" + chatRoomMessage.getUuid()); + } + } + }); + } + + /** + * 请求免费礼物 + */ + public void queryFreeFlower() { + GiftModel.get().getFreeGift(false) + .compose(bindToLifecycle()) + .subscribe(); + } + + @SuppressLint("CheckResult") + public void sendPublicChatTextMessage(String message) { + if (TextUtils.isEmpty(message)) return; + ChatRoomClient client = ChatRoomClientManager.INSTANCE.getPublicChatClient(); + if (client == null) { + SingleToastUtil.showToast(R.string.public_chat_not_found); + return; + } + ChatRoomMessage textMessage = ChatRoomMessageBuilder.createChatRoomTextMessage(client.getSessionId(), message); + client.sendMessage(textMessage).compose(bindToLifecycle()).subscribe(new BiConsumer() { + @Override + public void accept(Object o, Throwable throwable) throws Exception { + if (throwable != null) { + SingleToastUtil.showToast(throwable.getMessage()); + } else { + getMvpView().onSendPublicChatMsgSuccess(textMessage); + } + } + }); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/presenter/BaseRoomRankPresenter.java b/app/src/main/java/com/chwl/app/avroom/presenter/BaseRoomRankPresenter.java new file mode 100644 index 0000000..c736470 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/presenter/BaseRoomRankPresenter.java @@ -0,0 +1,84 @@ +package com.chwl.app.avroom.presenter; + +import android.os.Bundle; + +import androidx.annotation.Nullable; + +import com.chwl.app.avroom.adapter.RoomConsumerListAdapterTemp; +import com.chwl.app.base.BaseMvpPresenter; +import com.chwl.core.room.bean.RoomContributeUserInfo; +import com.chwl.core.room.bean.RoomRankMultiItem; +import com.chwl.library.base.IMvpBaseView; + +import java.util.ArrayList; +import java.util.List; + +public class BaseRoomRankPresenter extends BaseMvpPresenter { + + @Override + public void onCreatePresenter(@Nullable Bundle saveState) { + super.onCreatePresenter(saveState); + } + + @Override + public void onDestroyPresenter() { + super.onDestroyPresenter(); + } + + public List handleList(List dataInfoList) { + List list = new ArrayList<>(); + if (dataInfoList == null) { + dataInfoList = new ArrayList<>(); + } + + List topThree = new ArrayList<>(); + int count = 0; + while (count < 3 && dataInfoList.size() > 0) { + RoomContributeUserInfo info = dataInfoList.remove(0); + topThree.add(info); + count++; + } + + RoomRankMultiItem topItem = completeTopThree(topThree); + + list.add(topItem); + + if (dataInfoList.size() == 0) { + RoomRankMultiItem item = new RoomRankMultiItem(); + item.setItemType(RoomConsumerListAdapterTemp.TYPE_EMPTY); + list.add(item); + } else { + for (RoomContributeUserInfo info : dataInfoList) { + RoomRankMultiItem item = new RoomRankMultiItem(); + item.setData(info); + item.setItemType(RoomRankMultiItem.TYPE_LINEAR); + list.add(item); + } + } + return list; + } + + public List handleNormalList(List dataInfoList){ + List list = new ArrayList<>(); + if (dataInfoList == null) { + dataInfoList = new ArrayList<>(); + } + for (RoomContributeUserInfo info : dataInfoList) { + RoomRankMultiItem item = new RoomRankMultiItem(); + item.setData(info); + item.setItemType(RoomRankMultiItem.TYPE_LINEAR); + list.add(item); + } + return list; + } + + public RoomRankMultiItem completeTopThree(List topThree) { + while (topThree.size() < 3) { + topThree.add(new RoomContributeUserInfo(true)); + } + RoomRankMultiItem topItem = new RoomRankMultiItem(); + topItem.setData(topThree); + topItem.setItemType(RoomContributeUserInfo.TYPE_GRID); + return topItem; + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/presenter/CreatePKPresenter.java b/app/src/main/java/com/chwl/app/avroom/presenter/CreatePKPresenter.java new file mode 100644 index 0000000..c123835 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/presenter/CreatePKPresenter.java @@ -0,0 +1,100 @@ +package com.chwl.app.avroom.presenter; + +import com.chwl.app.R; +import com.chwl.app.avroom.view.ICreatePKView; +import com.chwl.app.base.BaseMvpPresenter; +import com.chwl.core.room.pk.model.PkModel; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.library.utils.ResUtil; + +import java.util.List; + +import io.reactivex.Single; +import io.reactivex.SingleSource; +import io.reactivex.functions.Function; + +/** + * @author jack + * @Description + * @Date 2018/12/28 + */ +public class CreatePKPresenter extends BaseMvpPresenter { + private int pkMode = -1; + private int pkVoteMode = -1; + private long pkDuration = -1; + + public int getPkMode() { + return pkMode; + } + + public void setPkMode(int pkMode) { + this.pkMode = pkMode; + } + + public int getPkVoteMode() { + return pkVoteMode; + } + + public void setPkVoteMode(int pkVoteMode) { + this.pkVoteMode = pkVoteMode; + } + + public long getPkDuration() { + return pkDuration; + } + + public void setPkDuration(long pkDuration) { + this.pkDuration = pkDuration; + } + + /** + * 创建 PK + * + * @param redTeamMember + * @param blueTeamMember + * @return + */ + public Single createPK(List redTeamMember, List blueTeamMember) { + if (pkMode == -1) { + return Single.error(new Throwable(ResUtil.getString(R.string.avroom_presenter_createpkpresenter_01))); + } + if (pkVoteMode == -1) { + return Single.error(new Throwable(ResUtil.getString(R.string.avroom_presenter_createpkpresenter_02))); + } + if (pkDuration == -1) { + return Single.error(new Throwable(ResUtil.getString(R.string.avroom_presenter_createpkpresenter_03))); + } + + return PkModel.get().openPKMode( + + ) + .flatMap(new Function>() { + @Override + public SingleSource apply(String s) throws Exception { + return PkModel.get().createPK( + pkMode, + pkVoteMode, + pkDuration, + redTeamMember, + blueTeamMember + ) + ; + } + }); + } + + public Single closePkMode() { + return PkModel.get().closePKMode(); + } + + + public Single createPKAgain(List redTeamMember, List blueTeamMember) { + return PkModel.get().createPK( + pkMode, + pkVoteMode, + pkDuration, + redTeamMember, + blueTeamMember + ); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/presenter/GameRoomPresenter.java b/app/src/main/java/com/chwl/app/avroom/presenter/GameRoomPresenter.java new file mode 100644 index 0000000..a65eee0 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/presenter/GameRoomPresenter.java @@ -0,0 +1,14 @@ +package com.chwl.app.avroom.presenter; + + +import com.chwl.app.avroom.view.IGameRoomView; + + +/** + *

+ * + * @author jiahui + * @date 2017/12/8 + */ +public class GameRoomPresenter extends BaseRoomPresenter { +} diff --git a/app/src/main/java/com/chwl/app/avroom/presenter/HomePartyPresenter.java b/app/src/main/java/com/chwl/app/avroom/presenter/HomePartyPresenter.java new file mode 100644 index 0000000..a4be277 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/presenter/HomePartyPresenter.java @@ -0,0 +1,299 @@ +package com.chwl.app.avroom.presenter; + +import static com.chwl.core.manager.RoomEvent.DRAGON_BAR_CANCEL; +import static com.chwl.core.manager.RoomEvent.DRAGON_BAR_END; + +import android.annotation.SuppressLint; + +import androidx.annotation.NonNull; + +import com.netease.nimlib.sdk.chatroom.ChatRoomMessageBuilder; +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage; +import com.netease.nimlib.sdk.msg.constant.MsgTypeEnum; +import com.chwl.app.R; +import com.chwl.app.avroom.view.IHomePartyView; +import com.chwl.app.utils.UserUtils; +import com.chwl.core.Constants; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.bean.RoomQueueInfo; +import com.chwl.core.im.custom.bean.CustomAttachment; +import com.chwl.core.im.custom.bean.FaceAttachment; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.manager.IMNetEaseManager; +import com.chwl.core.manager.RoomEvent; +import com.chwl.core.room.bean.DragonBarInfo; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.core.room.dragonball.DragonBallModel; +import com.chwl.core.room.face.FaceInfo; +import com.chwl.core.room.face.FaceReceiveInfo; +import com.chwl.core.room.giftvalue.helper.GiftValueMrg; +import com.chwl.core.room.model.RoomSettingModel; +import com.chwl.core.room.queue.bean.MicMemberInfo; +import com.chwl.core.user.UserModel; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.core.utils.net.BeanObserver; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; +import com.chwl.library.utils.config.BasicConfig; + +import java.util.ArrayList; +import java.util.List; + +import io.reactivex.Single; + + +/** + *

+ * + * @author jiahui + * @date 2017/12/8 + */ +public class HomePartyPresenter extends BaseRoomPresenter { + + private boolean isLeaveMode = false; + + /** + * 上麥 + * + * @param micPosition + * @param uId + * @param isInviteUpMic 是否是主動的,false:主動 + * @param isReconnect 是否需要清除禮物值,普通情況下上麥傳false,斷網重連傳ture + */ + public void upMicroPhone(final int micPosition, final String uId, boolean isInviteUpMic, boolean isReconnect) { + final RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) { + return; + } + if (!isInviteUpMic) { + if (AvRoomDataManager.get().haveStartDragon) { + if (getMvpView() != null) { + getMvpView().onDragonBarChangeMic(micPosition, uId, isInviteUpMic, roomInfo); + } + } else if (AvRoomDataManager.get().isShowGiftValue() && AvRoomDataManager.get().isOwnerOnMic()) { + if (getMvpView() != null) { + getMvpView().onGiftValueChangeMic(micPosition, uId, isInviteUpMic, roomInfo); + } + } else { + upMicroPhone(micPosition, uId, isInviteUpMic, roomInfo, isReconnect); + } + } else { + AvRoomDataManager.get().haveStartDragon = false; + upMicroPhone(micPosition, uId, isInviteUpMic, roomInfo, isReconnect); + } + } + + public void upMicroPhone(int micPosition, String uId, boolean isInviteUpMic, RoomInfo roomInfo) { + upMicroPhone(micPosition, uId, isInviteUpMic, roomInfo, false); + } + + //isGiven上次是否異常退出 + public void sendDragonBar(FaceInfo faceInfo, String point, boolean isGiven) { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) return; + if (isGiven) { + final ChatRoomMessage message = getChatRoomMessage(roomInfo, getPointList(faceInfo, point), CustomAttachment.CUSTOM_MSG_DRAGON_BAR_START); + IMNetEaseManager.get().sendChatRoomMessage(message, false) + .subscribe((chatRoomMessage, throwable) -> { + parseDragonBar(chatRoomMessage); + }); + } else { + final ChatRoomMessage message1 = getChatRoomMessage(roomInfo, getPointList(faceInfo, point), CustomAttachment.CUSTOM_MSG_DRAGON_BAR_RUNAWAY); + IMNetEaseManager.get().sendChatRoomMessage(message1, false) + .subscribe((chatRoomMessage, throwable) -> { + parseDragonBar(chatRoomMessage); + IMNetEaseManager.get().addMessages(chatRoomMessage); + }); + } + } + + public void openDragonBar() { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) return; + // 普通表情 + final ChatRoomMessage message = getChatRoomMessage(roomInfo, AvRoomDataManager.get().dragons, CustomAttachment.CUSTOM_MSG_DRAGON_BAR_END); + IMNetEaseManager.get().sendChatRoomMessage(message, false) + .subscribe((chatRoomMessage, throwable) -> { + IMNetEaseManager.get().getChatRoomEventObservable(). + onNext(new RoomEvent().setEvent(DRAGON_BAR_END) + .setChatRoomMessage(chatRoomMessage)); + IMNetEaseManager.get().addMessages(chatRoomMessage); + }); + } + + public void cancelDragon() { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) return; + // 普通表情 + final ChatRoomMessage message = getChatRoomMessage(roomInfo, AvRoomDataManager.get().dragons, CustomAttachment.CUSTOM_MSG_DRAGON_BAR_CANCEL); + IMNetEaseManager.get().sendChatRoomMessage(message, false) + .subscribe((chatRoomMessage, throwable) -> { + IMNetEaseManager.get().getChatRoomEventObservable(). + onNext(new RoomEvent().setEvent(DRAGON_BAR_CANCEL) + .setChatRoomMessage(chatRoomMessage)); + IMNetEaseManager.get().addMessages(chatRoomMessage); + + }); + } + + @NonNull + private ChatRoomMessage getChatRoomMessage(RoomInfo roomInfo, List integers, int second) { + UserInfo userInfo = UserModel.get().getCacheLoginUserInfo(); + List faceReceiveInfos = new ArrayList<>(); + FaceReceiveInfo faceReceiveInfo = new FaceReceiveInfo(); + faceReceiveInfo.setNick(userInfo.getNick()); + faceReceiveInfo.setFaceId(Constants.DRAGON_BAR_ID); + faceReceiveInfo.setUid(userInfo.getUid()); + + faceReceiveInfo.setResultIndexes(integers); + faceReceiveInfos.add(faceReceiveInfo); + + // 發送雲信信息給所有人 + FaceAttachment faceAttachment = + new FaceAttachment(CustomAttachment.CUSTOM_MSG_DRAGON_BAR, second); + faceAttachment.setUid(userInfo.getUid()); + faceAttachment.setFaceReceiveInfos(faceReceiveInfos); + + return ChatRoomMessageBuilder.createChatRoomCustomMessage( + // 聊天室id + roomInfo.getRoomId() + "", + // 自定義消息 + faceAttachment + ); + } + + private List getPointList(FaceInfo faceInfo, String point) { + List list = new ArrayList(); + String[] split = point.replace("[", "").replace("]", "").split(", "); + for (String s : split) { + list.add(Integer.valueOf(s) + faceInfo.getResultIndexStart()); + } + AvRoomDataManager.get().dragons = list; + return list; + } + + private void parseDragonBar(ChatRoomMessage chatRoomMessage) { + if (chatRoomMessage != null) { + if (chatRoomMessage.getMsgType() == MsgTypeEnum.custom) { + CustomAttachment attachment = (CustomAttachment) chatRoomMessage.getAttachment(); + // 顯示錶情在對應的位置 + if (attachment.getFirst() == CustomAttachment.CUSTOM_MSG_DRAGON_BAR) { + FaceAttachment faceAttachment = (FaceAttachment) attachment; + List faceReceiveInfos = faceAttachment.getFaceReceiveInfos(); + + if (faceReceiveInfos != null && faceReceiveInfos.size() > 0) { + // 显示動畫 + IMNetEaseManager.get().getChatRoomEventObservable() + .onNext(new RoomEvent().setEvent(RoomEvent.DRAGON_BAR_SELF_START).setChatRoomMessage(chatRoomMessage)); + } + } + } + } + } + + public Single clearDragonBar() { + return DragonBallModel.get().clearDragonBar() + .compose(bindToLifecycle()) + .doOnError(throwable -> SingleToastUtil.showToast(BasicConfig.INSTANCE.getAppContext(), throwable.getMessage())) + .doOnSuccess(s -> { + openDragonBar(); + AvRoomDataManager.get().haveStartDragon = false; + }); + } + + public Single getDragonBar(FaceInfo faceInfo) { + return DragonBallModel.get().getDragonBar() + .compose(bindToLifecycle()) + .doOnError(throwable -> SingleToastUtil.showToast(BasicConfig.INSTANCE.getAppContext(), throwable.getMessage())) + .doOnSuccess(dragonBarInfo -> { + sendDragonBar(faceInfo, dragonBarInfo.getValue(), dragonBarInfo.isIsGen()); + AvRoomDataManager.get().haveStartDragon = true; + }); + } + + + /** + * 本地更新房主位信息或者關閉離線模式 + */ + @SuppressWarnings("CheckResult") + public void leaveModeCheck() { + isLeaveMode = AvRoomDataManager.get().isLeaveMode(); // 進房緩存離線模式狀態 + + if (!AvRoomDataManager.get().isCpRoom() && !AvRoomDataManager.get().isOpenKTV()) { + RoomQueueInfo queueInfo = AvRoomDataManager.get().getRoomQueueMemberInfoByMicPosition(-1); + + // 新版管理員首次進房,如果房主位有人,並且房間是離開模式,需要調用接口關閉離開模式(提高關閉離開模式的幾率) + if (AvRoomDataManager.get().isManager()) { + + if (queueInfo != null) { + MicMemberInfo chatRoomMember = queueInfo.mChatRoomMember; + if (chatRoomMember != null) { + closeLeaveMode(-1, null); + return; + } + + } + } + + } + + } + + public void closeLeaveMode(int micPosition, String account) { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + int position = AvRoomDataManager.get().getMicPosition(AvRoomDataManager.get().getRoomUid()); + if (roomInfo != null && roomInfo.isLeaveMode() && micPosition == position) { + // 新版由管理員和房主位上麥用戶共同調接口關閉離開模式(提高關閉離開模式成功率,降低接口調用頻率); + if (AvRoomDataManager.get().isManager() || String.valueOf(AuthModel.get().getCurrentUid()).equals(account)) { + new RoomSettingModel().leaveModeClose(roomInfo.getUid()).subscribe(new BeanObserver() { + @Override + public void onErrorMsg(String error) { + + } + + @Override + public void onSuccess(String s) { + + if (AvRoomDataManager.get().isShowGiftValue()) + GiftValueMrg.get().requestDownMic(-1, String.valueOf(AuthModel.get().getCurrentUid())); + + } + }); + } + + } + + } + + public void updateLeaveMode() { + if (isLeaveMode == AvRoomDataManager.get().isLeaveMode()) + return; + + isLeaveMode = AvRoomDataManager.get().isLeaveMode(); + + if (!isLeaveMode && AvRoomDataManager.get().isShowGiftValue()) // 禮物值模式下關閉離開模式,本地清除禮物值 + GiftValueMrg.get().handleDownMic(-1, String.valueOf(AvRoomDataManager.get().getRoomUid())); + + } + + + public void datingNext() { + final RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) return; + mHomePartyMode.datingNext(roomInfo.getUid()) + .compose(bindToLifecycle()) + .doOnError(e -> SingleToastUtil.showToast(e.getMessage())) + .subscribe(); + } + + @SuppressLint("CheckResult") + public void datingSelect(long chosenUserId) { + final RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) return; + mHomePartyMode.datingSelect(chosenUserId, UserUtils.getUserUid(), roomInfo.getUid()) + .compose(bindToLifecycle()) + .subscribe(s -> SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_presenter_homepartypresenter_01)) + , e -> SingleToastUtil.showToast(e.getMessage())); + } + +} diff --git a/app/src/main/java/com/chwl/app/avroom/presenter/HomePartyUserListPresenter.java b/app/src/main/java/com/chwl/app/avroom/presenter/HomePartyUserListPresenter.java new file mode 100644 index 0000000..a09ee85 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/presenter/HomePartyUserListPresenter.java @@ -0,0 +1,33 @@ +package com.chwl.app.avroom.presenter; + +import android.annotation.SuppressLint; + +import com.chwl.app.avroom.view.IHomePartyUserListView; +import com.chwl.app.base.BaseMvpPresenter; +import com.chwl.core.room.model.AvRoomModel; + +/** + *

+ * + * @author jiahui + * @date 2017/12/8 + */ +public class HomePartyUserListPresenter extends BaseMvpPresenter { + + public HomePartyUserListPresenter() { + } + + @SuppressLint("CheckResult") + public void requestRoomOnlineList(long roomUid){ + AvRoomModel.get().getRoomOnlineList(roomUid).compose(bindToLifecycle()).subscribe((data, throwable) -> { + if (getMvpView() != null) { + if (data != null) { + getMvpView().onRequestRoomOnlineListSuccess(data); + } else { + getMvpView().onRequestChatMemberByPageFail(throwable.getMessage(), 1); + } + } + }); + } + +} diff --git a/app/src/main/java/com/chwl/app/avroom/presenter/RecordForPKPresenter.java b/app/src/main/java/com/chwl/app/avroom/presenter/RecordForPKPresenter.java new file mode 100644 index 0000000..5a6c6ad --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/presenter/RecordForPKPresenter.java @@ -0,0 +1,62 @@ +package com.chwl.app.avroom.presenter; + +import com.chwl.app.R; +import com.chwl.app.avroom.view.IRecordForPKView; +import com.chwl.app.base.BaseMvpPresenter; +import com.chwl.app.home.helper.LoadPageDataHelper; +import com.chwl.core.Constants; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.core.room.pk.bean.PKRecordInfo; +import com.chwl.core.room.pk.bean.PKRecordListInfo; +import com.chwl.core.room.pk.model.PkModel; +import com.chwl.library.utils.ResUtil; + +import java.util.List; + +import io.reactivex.Single; +import io.reactivex.SingleSource; +import io.reactivex.functions.Function; + +/** + * @author jack + * @Description + * @Date 2018/12/29 + */ +public class RecordForPKPresenter extends BaseMvpPresenter + implements LoadPageDataHelper.LoadData> { + + LoadPageDataHelper> loadPageDataHelper; + + public RecordForPKPresenter() { + loadPageDataHelper = new LoadPageDataHelper>(this); + } + + @Override + public Single> loadData(int curPage) { + RoomInfo currentRoomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (currentRoomInfo == null) { + return Single.error(new Throwable(ResUtil.getString(R.string.avroom_presenter_recordforpkpresenter_01))); + } + return PkModel.get().loadPKRecordList( + currentRoomInfo.getUid(), + curPage, + Constants.PAGE_SIZE + ) + .flatMap(new Function>>() { + @Override + public SingleSource> apply(PKRecordListInfo pkRecordListInfo) throws Exception { + return Single.just(pkRecordListInfo.getRecords()); + } + }); + + } + + public Single> refreshData() { + return loadPageDataHelper.refreshData(); + } + + public Single> loadMoreData() { + return loadPageDataHelper.loadMoreData(); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/presenter/RoomBlackPresenter.java b/app/src/main/java/com/chwl/app/avroom/presenter/RoomBlackPresenter.java new file mode 100644 index 0000000..5a9fed8 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/presenter/RoomBlackPresenter.java @@ -0,0 +1,44 @@ +package com.chwl.app.avroom.presenter; + +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMember; +import com.chwl.app.avroom.view.IRoomBlackView; +import com.chwl.app.base.BaseMvpPresenter; +import com.chwl.core.room.model.RoomBaseModel; +import com.chwl.library.net.rxnet.callback.CallBack; + +/** + *

+ * + * @author jiahui + * @date 2017/12/19 + */ +public class RoomBlackPresenter extends BaseMvpPresenter { + private final RoomBaseModel mRoomBaseModel; + + public RoomBlackPresenter() { + mRoomBaseModel = new RoomBaseModel(); + } + + /** + * 拉黑操作 + * + * @param roomId + * @param account + * @param mark true,拉黑,false:移除拉黑 + */ + public void markBlackList(long roomId, String account, final boolean mark) { + mRoomBaseModel.markBlackList(roomId, String.valueOf(account), mark, new CallBack() { + @Override + public void onSuccess(ChatRoomMember data) { + if (getMvpView() != null) + getMvpView().makeBlackListSuccess(data, mark); + } + + @Override + public void onFail(int code, String error) { + if (getMvpView() != null) + getMvpView().makeBlackListFail(code, error, mark); + } + }); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/presenter/RoomCharmRankingPresenter.java b/app/src/main/java/com/chwl/app/avroom/presenter/RoomCharmRankingPresenter.java new file mode 100644 index 0000000..e953d73 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/presenter/RoomCharmRankingPresenter.java @@ -0,0 +1,68 @@ +package com.chwl.app.avroom.presenter; + +import com.chwl.app.avroom.view.IRoomCharmRankingListView; +import com.chwl.core.bean.response.ServiceResult; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.room.bean.RoomContributeDataInfo; +import com.chwl.core.room.bean.RoomContributeUserInfo; +import com.chwl.core.room.bean.RoomRankMultiItem; +import com.chwl.core.room.model.RoomCharmModel; +import com.chwl.core.room.model.inteface.IRoomCharmModel; + +import java.util.ArrayList; +import java.util.List; + +import io.reactivex.SingleObserver; +import io.reactivex.disposables.Disposable; + +public class RoomCharmRankingPresenter extends BaseRoomRankPresenter { + private IRoomCharmModel model; + + public RoomCharmRankingPresenter() { + this.model = RoomCharmModel.get(); + } + + public void getRoomCharmList(int page, String type) { + long currentUid = AvRoomDataManager.get().mCurrentRoomInfo.getUid(); + model.getRoomCharmList( + String.valueOf(currentUid), + page, + 10, + type + ).compose(bindToLifecycle()) + .subscribe(new SingleObserver>() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onSuccess(ServiceResult roomContributeDataInfoServiceResult) { + List list = new ArrayList<>(); + ArrayList dataInfoList = roomContributeDataInfoServiceResult.getData().getRankings(); + if (page <= 1){ + if (roomContributeDataInfoServiceResult.isSuccess()){ + + list = handleList(dataInfoList); + } + if (list == null || list.size() == 0) { + list = new ArrayList<>(); + list.add(completeTopThree(new ArrayList<>())); + } + }else { + list = handleNormalList(dataInfoList); + } + if (getMvpView() != null) { + getMvpView().roomCharmListSuccess(list); + } + } + + @Override + public void onError(Throwable e) { + if (getMvpView() != null) + getMvpView().roomCharListFail(e.getMessage()); + } + }); + } + +} diff --git a/app/src/main/java/com/chwl/app/avroom/presenter/RoomContributeListPresenter.java b/app/src/main/java/com/chwl/app/avroom/presenter/RoomContributeListPresenter.java new file mode 100644 index 0000000..d6c15f7 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/presenter/RoomContributeListPresenter.java @@ -0,0 +1,39 @@ +package com.chwl.app.avroom.presenter; + +import android.annotation.SuppressLint; + +import com.chwl.app.R; +import com.chwl.app.avroom.view.IRoomContributeListView; +import com.chwl.core.room.model.RoomContributeListModel; +import com.chwl.library.utils.ResUtil; + +/** + * Created by MadisonRong on 25/04/2018. + */ + +public class RoomContributeListPresenter extends BaseRoomRankPresenter { + + private RoomContributeListModel model; + + public RoomContributeListPresenter() { + this.model = RoomContributeListModel.get(); + } + + @SuppressLint("CheckResult") + public void getSingleRoomRanking(int page, String type) { + model.getSingleRoomRanking(page, type) + .subscribe((roomContributeDataInfoServiceResult, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + getMvpView().getSingleRakingFail(-1, ResUtil.getString(R.string.avroom_presenter_roomcontributelistpresenter_01)); + } else if (roomContributeDataInfoServiceResult != null && roomContributeDataInfoServiceResult.isSuccess()) { + getMvpView().getSingleRankingSuccess(roomContributeDataInfoServiceResult.getData()); + } else if (roomContributeDataInfoServiceResult != null && !roomContributeDataInfoServiceResult.isSuccess()) { + getMvpView().getSingleRakingFail(roomContributeDataInfoServiceResult.getCode(), + roomContributeDataInfoServiceResult.getMessage()); + } else { + getMvpView().getSingleRakingFail(-1, ResUtil.getString(R.string.avroom_presenter_roomcontributelistpresenter_02)); + } + }); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/presenter/RoomInvitePresenter.java b/app/src/main/java/com/chwl/app/avroom/presenter/RoomInvitePresenter.java new file mode 100644 index 0000000..3c1bc67 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/presenter/RoomInvitePresenter.java @@ -0,0 +1,99 @@ +package com.chwl.app.avroom.presenter; + +import android.annotation.SuppressLint; +import android.util.SparseArray; + +import com.netease.nimlib.sdk.chatroom.constant.MemberType; +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMember; +import com.chwl.app.avroom.view.IRoomInviteView; +import com.chwl.app.base.BaseMvpPresenter; +import com.chwl.core.bean.RoomQueueInfo; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.room.model.RoomInviteModel; +import com.chwl.core.super_admin.util.SuperAdminUtil; + +import java.util.List; +import java.util.ListIterator; +import java.util.Objects; + +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.functions.Consumer; + +/** + *

+ * + * @author jiahui + * @date 2017/12/21 + */ +public class RoomInvitePresenter extends BaseMvpPresenter { + + private RoomInviteModel mRoomInviteModel; + + public RoomInvitePresenter() { + mRoomInviteModel = new RoomInviteModel(); + } + + /** + * 分页获取房间成员:第一页包含固定在线成员,游客50人,之后每一页获取游客50人 + * + * @param page 页数 + * @param time 固定成员列表用updateTime, + * 游客列表用进入enterTime, + * 填0会使用当前服务器最新时间开始查询,即第一页,单位毫秒 + */ + @SuppressLint("CheckResult") + public void requestChatMemberByPage(final int page, long time, boolean onlyManager) { + mRoomInviteModel.getPageMembers(page, time) + .map(chatRoomMemberList -> { + SparseArray queueInfoSparseArray = AvRoomDataManager.get().mMicQueueMemberMap; + int size; + if (queueInfoSparseArray == null || (size = queueInfoSparseArray.size()) <= 0) { + return chatRoomMemberList; + } + //移除麦上人员 + ChatRoomMember chatRoomMember; + ListIterator iterator = chatRoomMemberList.listIterator(); + while (iterator.hasNext()) { + chatRoomMember = iterator.next(); + boolean removed = false; + //过滤超管 + if (SuperAdminUtil.isSuperAdmin(chatRoomMember)) { + iterator.remove(); + removed = true; + } else { + for (int i = 0; i < size; i++) { + RoomQueueInfo roomQueueInfo = queueInfoSparseArray.valueAt(i); + if (roomQueueInfo.mChatRoomMember != null + && Objects.equals(chatRoomMember.getAccount(), roomQueueInfo.mChatRoomMember.getAccount())) { + iterator.remove(); + removed = true; + break; + } + } + } + //过滤掉非管理和房主的固定成员 + if (!removed && onlyManager && chatRoomMember.getMemberType() != MemberType.ADMIN && chatRoomMember.getMemberType() != MemberType.CREATOR) { + iterator.remove(); + } + } + return chatRoomMemberList; + }) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Consumer>() { + @Override + public void accept(List chatRoomMemberList) throws Exception { + if (getMvpView() != null) { + getMvpView().onRequestMemberByPageSuccess(chatRoomMemberList, page); + } + } + }, new Consumer() { + @Override + public void accept(Throwable throwable) throws Exception { + throwable.printStackTrace(); + if (getMvpView() != null) { + getMvpView().onRequestChatMemberByPageFail(throwable.getMessage(), page); + } + } + }); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/presenter/RoomManagerPresenter.java b/app/src/main/java/com/chwl/app/avroom/presenter/RoomManagerPresenter.java new file mode 100644 index 0000000..42fc288 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/presenter/RoomManagerPresenter.java @@ -0,0 +1,148 @@ +package com.chwl.app.avroom.presenter; + +import android.annotation.SuppressLint; +import android.text.TextUtils; + +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMember; +import com.chwl.app.avroom.view.IRoomManagerView; +import com.chwl.app.base.BaseMvpPresenter; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.room.model.AvRoomModel; +import com.chwl.core.room.model.RoomBaseModel; +import com.chwl.core.user.UserModel; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.library.base.PresenterEvent; +import com.chwl.library.net.rxnet.callback.CallBack; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import io.reactivex.Single; +import io.reactivex.SingleSource; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.functions.Function; +import io.reactivex.schedulers.Schedulers; + +/** + *

+ * + * @author jiahui + * @date 2017/12/19 + */ +public class RoomManagerPresenter extends BaseMvpPresenter { + + private final RoomBaseModel mRoomBaseModel; + + public RoomManagerPresenter() { + mRoomBaseModel = new RoomBaseModel(); + } + + @SuppressLint("CheckResult") + public void queryManagerList(int limit) { + Single.just(AvRoomDataManager.get().mRoomManagerList) + .observeOn(Schedulers.io()) + .flatMap((Function, SingleSource>>) chatRoomMembers -> { + List uids = new ArrayList<>(); + for (ChatRoomMember member : chatRoomMembers) { + if (member != null && !TextUtils.isEmpty(member.getAccount())) { + uids.add(member.getAccount()); + } + } + if (uids.size() == 0) { + return Single.just(new ArrayList()); + } + return Single.zip( + UserModel.get().loadUserInfoByUids(uids), + Single.just(chatRoomMembers), + (userInfos, paramList) -> { + Map map = new HashMap<>(); + for (UserInfo info : userInfos) { + if (info != null && info.isSuperAdmin()) { + map.put(String.valueOf(info.getUid()), true); + } + if (info != null && AvRoomDataManager.get().isSuperAdmin(String.valueOf(info.getUid()))) { + map.put(String.valueOf(info.getUid()), true); + } + } + Iterator iterator = paramList.iterator(); + while (iterator.hasNext()) { + ChatRoomMember member = iterator.next(); + if (member != null && !TextUtils.isEmpty(member.getAccount())) { + if (map.containsKey(member.getAccount())) { + iterator.remove(); + } else { + if (member.getNick() == null || member.getAvatar() == null) { + for (UserInfo info : userInfos) { + if (String.valueOf(info.getUid()).equals(member.getAccount())) { + member.setNick(info.getNick()); + member.setAvatar(info.getAvatar()); + break; + } + } + } + } + } + } + return paramList; + }); + }) + .observeOn(AndroidSchedulers.mainThread()) + .compose(this.bindUntilEvent(PresenterEvent.DESTROY)) + .subscribe(chatRoomMemberList -> { + if (getMvpView() != null) { + getMvpView().queryManagerListSuccess(chatRoomMemberList); + } + }, throwable -> { + if (getMvpView() != null) { + getMvpView().queryManagerListFail(); + } + }); + + } + + /** + * 设置管理员 + * + * @param roomId + * @param account + */ + @SuppressLint("CheckResult") + public void removeManagerList(long roomId, String account) { + if (AvRoomDataManager.get().isSuperAdmin()) { + AvRoomModel.get().markManager(Long.parseLong(account),false).subscribe( + s -> { + if (getMvpView() != null) { + ChatRoomMember chatRoomMember = new ChatRoomMember(); + chatRoomMember.setAccount(account); + getMvpView().markManagerListSuccess(chatRoomMember); + } + }, + e -> { + if (getMvpView() != null) { + getMvpView().markManagerListFail(-1, e.getMessage()); + } + } + ); + } else { + mRoomBaseModel.markManagerList(roomId, account, false, new CallBack() { + @Override + public void onSuccess(ChatRoomMember data) { + if (getMvpView() != null) { + getMvpView().markManagerListSuccess(data); + } + } + + @Override + public void onFail(int code, String error) { + if (getMvpView() != null) { + getMvpView().markManagerListFail(code, error); + } + } + }); + } + + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/presenter/RoomNewbiePresenter.java b/app/src/main/java/com/chwl/app/avroom/presenter/RoomNewbiePresenter.java new file mode 100644 index 0000000..c94968c --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/presenter/RoomNewbiePresenter.java @@ -0,0 +1,68 @@ +package com.chwl.app.avroom.presenter; + +import com.chwl.app.R; +import com.chwl.app.base.BaseMvpPresenter; +import com.chwl.app.module.IRoomNewbieView; +import com.chwl.app.module.RoomNewbieModel; +import com.chwl.core.Constants; +import com.chwl.core.bean.RoomNewbieInfo; +import com.chwl.library.utils.ResUtil; + +import java.util.List; + +import io.reactivex.SingleObserver; +import io.reactivex.disposables.Disposable; + +public class RoomNewbiePresenter extends BaseMvpPresenter { + + private int page = 0; + + public void loadData(boolean isRefresh) { + if (isRefresh) { + page = 1; + } else { + page++; + } + + RoomNewbieModel.get().getRoomNewbieList(page, Constants.PAGE_SIZE) + .compose(bindToLifecycle()).subscribe(new SingleObserver>() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onSuccess(List roomNewbieInfos) { + if (roomNewbieInfos != null) { + if (mMvpView != null) { + if (isRefresh){ + mMvpView.getRoomNewbieSuccess(roomNewbieInfos); + }else { + mMvpView.getRoomNewbieLoadMoreSuccess(roomNewbieInfos); + } + } + } else { + if (mMvpView != null) { + if (isRefresh){ + mMvpView.getRoomNewbieFails(ResUtil.getString(R.string.avroom_presenter_roomnewbiepresenter_01)); + }else { + mMvpView.getRoomNewbieLoadMoreFails(ResUtil.getString(R.string.avroom_presenter_roomnewbiepresenter_02)); + } + } + } + } + + @Override + public void onError(Throwable e) { + if (mMvpView != null) { + mMvpView.getRoomNewbieFails(e.getMessage()); + } + + } + }); + } + + public int getPage() { + return page; + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/presenter/RoomRankHalfHourPresenter.java b/app/src/main/java/com/chwl/app/avroom/presenter/RoomRankHalfHourPresenter.java new file mode 100644 index 0000000..f4e0c8b --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/presenter/RoomRankHalfHourPresenter.java @@ -0,0 +1,103 @@ +package com.chwl.app.avroom.presenter; + +import com.chwl.app.avroom.fragment.IRoomRankHalfHourView; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.core.room.bean.RoomRankHalfHourDataInfo; +import com.chwl.core.room.bean.RoomRankHalfHourRankInfo; +import com.chwl.core.room.bean.RoomRankMultiItem; +import com.chwl.core.room.model.RoomRankModel; +import com.chwl.library.base.factory.AbstractMvpPresenter; +import com.chwl.library.utils.SingleToastUtil; + +import java.util.ArrayList; +import java.util.List; + +import io.reactivex.SingleObserver; +import io.reactivex.disposables.Disposable; + +public class RoomRankHalfHourPresenter extends AbstractMvpPresenter { + + public void getRankListInfo() { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo != null) { + RoomRankModel.get() + .getRoomRankHalfHourList(roomInfo.getUid()) + .compose(bindToLifecycle()) + .subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onSuccess(RoomRankHalfHourDataInfo roomRankHalfHourDataInfo) { + if (roomRankHalfHourDataInfo != null) { + + if (mMvpView != null) { + if (roomRankHalfHourDataInfo.getMe() != null) { + mMvpView.showMeInfo(roomRankHalfHourDataInfo.getMe()); + } else + mMvpView.showMeInfo(null); + + transformData(roomRankHalfHourDataInfo.getRankVoList()); + } + + } else { + if (mMvpView != null) + mMvpView.loadDataFailure(); + } + } + + @Override + public void onError(Throwable e) { + if (mMvpView != null) + mMvpView.loadDataFailure(); + SingleToastUtil.showToast(e.getMessage()); + } + }); + } + } + + private void transformData(List dataInfoList) { + + if (dataInfoList != null) { + List top3rankInfo; + if (dataInfoList.size() >= 3) { + top3rankInfo = dataInfoList.subList(0, 3); + } else { + top3rankInfo = dataInfoList; + } + mMvpView.showTop3Info(top3rankInfo); + // 第四名开始以后的信息 + List otherRankInfo = new ArrayList<>(); + if (dataInfoList.size() > 3) { + + for (int i = 3; i < dataInfoList.size(); i++) { + RoomRankHalfHourRankInfo info = dataInfoList.get(i); + RoomRankMultiItem item = new RoomRankMultiItem(); + item.setItemType(RoomRankMultiItem.TYPE_LINEAR); + item.setData(info); + otherRankInfo.add(item); + + } + + } + +// RoomRankMultiItem item = new RoomRankMultiItem(); +// item.setItemType(RoomRankHalfHourListAdapter.TYPE_TIPS); +// otherRankInfo.add(item); + mMvpView.showRankListInfo(otherRankInfo); + + } else { + mMvpView.showTop3Info(null); + + List otherRankInfo = new ArrayList<>(); + RoomRankMultiItem item = new RoomRankMultiItem(); + item.setItemType(RoomRankMultiItem.TYPE_EMPTY); + otherRankInfo.add(item); + mMvpView.showRankListInfo(otherRankInfo); + } + } + +} diff --git a/app/src/main/java/com/chwl/app/avroom/presenter/RoomSettingPresenter.java b/app/src/main/java/com/chwl/app/avroom/presenter/RoomSettingPresenter.java new file mode 100644 index 0000000..b6d65d5 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/presenter/RoomSettingPresenter.java @@ -0,0 +1,258 @@ +package com.chwl.app.avroom.presenter; + +import android.annotation.SuppressLint; +import android.os.Handler; + +import com.chwl.app.avroom.view.IRoomSettingView; +import com.chwl.app.base.BaseMvpPresenter; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.manager.IMNetEaseManager; +import com.chwl.core.manager.RoomEvent; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.core.room.bean.RoomSettingTabInfo; +import com.chwl.core.room.giftvalue.GiftValueModel; +import com.chwl.core.room.giftvalue.bean.RoomGiftValue; +import com.chwl.core.room.giftvalue.helper.GiftValueMrg; +import com.chwl.core.room.model.MicQueueModel; +import com.chwl.core.room.model.RoomSettingModel; +import com.chwl.core.user.UserModel; +import com.chwl.core.utils.net.BeanObserver; +import com.chwl.core.utils.net.DontWarnObserver; +import com.chwl.library.net.rxnet.callback.CallBack; + +import java.util.List; + +import io.reactivex.functions.BiConsumer; + +/** + *

+ * + * @author jiahui + * @date 2017/12/15 + */ +public class RoomSettingPresenter extends BaseMvpPresenter { + + private static final String TAG = "RoomSettingPresenter"; + + private final RoomSettingModel model; + + public RoomSettingPresenter() { + model = new RoomSettingModel(); + } + + @SuppressLint("CheckResult") + public void requestTagAll() { + model.requestTagAll(AuthModel.get().getTicket()) + .subscribe(new BiConsumer, Throwable>() { + @Override + public void accept(List listServiceResult, + Throwable throwable) throws Exception { + IRoomSettingView roomSettingView = getMvpView(); + if (roomSettingView == null) return; + if (throwable != null) { + roomSettingView.onResultRequestTagAllFail(throwable.getMessage()); + } else { + roomSettingView.onResultRequestTagAllSuccess(listServiceResult); + } + } + }); + } + + @SuppressLint("CheckResult") + public void requestSingleRoomSort() { + model.requestSingleRoomSort() + .subscribe((date, throwable) -> { + IRoomSettingView roomSettingView = getMvpView(); + if (roomSettingView == null) return; + if (throwable != null) { + roomSettingView.onResultRequestSingleRoomSortFail(throwable.getMessage()); + } else { + roomSettingView.onResultRequestSingleRoomSortSuccess(date); + } + }); + } + + public void requestRoomInfo(long uid) { + model.requestRoomInfoFromService(uid + "", new CallBack() { + @Override + public void onSuccess(RoomInfo data) { + if (getMvpView() != null) { + getMvpView().reQuestRoomInfo(data); + } + } + + @Override + public void onFail(int code, String error) { + + } + }); + } + + @SuppressLint("CheckResult") + public void updateGiftEffect(RoomInfo roomInfo) { + IMNetEaseManager.get().updateGiftEffect(roomInfo.getRoomId()) + .subscribe((chatRoomMessage, throwable) -> { + if (!AvRoomDataManager.get().haveSelfChange) { + IMNetEaseManager.get().getChatRoomEventObservable().onNext(new RoomEvent() + .setEvent(RoomEvent.RECEIVE_MSG) + .setChatRoomMessage(chatRoomMessage)); + } + }); + } + + @SuppressLint("CheckResult") + public void updateAudiouality(RoomInfo roomInfo) { + IMNetEaseManager.get().updateAudiouality(roomInfo.getRoomId()) + .subscribe((chatRoomMessage, throwable) -> { + IMNetEaseManager.get().getChatRoomEventObservable().onNext(new RoomEvent() + .setEvent(RoomEvent.RECEIVE_MSG) + .setChatRoomMessage(chatRoomMessage)); + }); + } + + @SuppressLint("CheckResult") + public void openQueuingMicMode() { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) { + return; + } + MicQueueModel.get() + .openQueuingMicMode(roomInfo.getUid()) + .subscribe((s, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + getMvpView().onFailToToast(throwable.getMessage()); + } else { + getMvpView().onSuccessToFinish(); + } + }); + } + + @SuppressLint("CheckResult") + public void closeQueuingMicMode() { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) { + return; + } + MicQueueModel.get() + .closeQueuingMicMode(roomInfo.getUid()) + .subscribe((s, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + getMvpView().onFailToToast(throwable.getMessage()); + } else { + getMvpView().onSuccessToFinish(); + } + }); + } + + public void openRoomPureMode() { + updateRoomPureMode(true); + } + + public void closeRoomPureMode() { + updateRoomPureMode(false); + } + + public void leaveModeOpen(long roomUid) { + model.leaveModeOpen(roomUid).subscribe(new BeanObserver() { + @Override + public void onErrorMsg(String error) { + if (mMvpView != null) + mMvpView.leaveModeOpenFail(error); + + } + + @Override + public void onSuccess(String s) { + if (mMvpView != null) + mMvpView.leaveModeOpenSuccess(); + + updateRoomOwnerMic(); + + } + }); + + } + + public void leaveModeClose(long roomUid) { + model.leaveModeClose(roomUid).subscribe(new BeanObserver() { + @Override + public void onErrorMsg(String error) { + if (mMvpView != null) + mMvpView.leaveModeCloseFail(error); + + } + + @Override + public void onSuccess(String s) { + if (mMvpView != null) + mMvpView.leaveModeCloseSuccess(); + + } + }); + + } + + @SuppressLint("CheckResult") + private void updateRoomPureMode(boolean isPureMode) { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) { + return; + } + if (AvRoomDataManager.get().isRoomOwner()) { + model.updateRoomPureModeForOwner(roomInfo.getTitle(), roomInfo.getRoomDesc(), + roomInfo.getIntroduction(), roomInfo.getRoomPwd(), roomInfo.getRoomTag(), + roomInfo.getTagId(), roomInfo.isHasAnimationEffect(), + roomInfo.getAudioQuality(), roomInfo.getLimitType(), isPureMode) + .compose(bindToLifecycle()) + .subscribe((roomInfo1, throwable) -> { + if (throwable == null) { + getMvpView().onUpdateRoomPureMode(roomInfo1); + } else { + getMvpView().onResultRequestTagAllFail(throwable.getMessage()); + } + }); + } else if (AvRoomDataManager.get().isRoomAdmin()) { + model.updateRoomPureMode(roomInfo.getUid(), roomInfo.getTitle(), roomInfo.getRoomDesc(), + roomInfo.getIntroduction(), roomInfo.getRoomPwd(), roomInfo.getRoomTag(), roomInfo.getTagId(), + roomInfo.isHasAnimationEffect(), roomInfo.getAudioQuality(), isPureMode) + .compose(bindToLifecycle()) + .subscribe((roomInfo1, throwable) -> { + if (throwable == null) { + getMvpView().onUpdateRoomPureMode(roomInfo1); + } else { + getMvpView().onResultRequestTagAllFail(throwable.getMessage()); + } + }); + } + } + + @SuppressWarnings("CheckResult") + private void updateRoomOwnerMic() { + RoomInfo roomInfo1 = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo1 == null) + return; + + UserModel.get().getUserInfo(roomInfo1.getUid()).subscribe((userInfo, throwable) -> { + if (userInfo != null) + IMNetEaseManager.get().leaveModeMessage(roomInfo1.getRoomId(), userInfo.getNick(), userInfo.getGender(), userInfo.getAvatar()).subscribe(); + }); + GiftValueModel.get().upMic(AuthModel.get().getCurrentUid(), -1).subscribe(new DontWarnObserver() { + @Override + public void acceptThrowable(RoomGiftValue values, Throwable throwable) { + super.acceptThrowable(values, throwable); + GiftValueMrg.get().sendRoomGiftValueMsg(values); + final Handler handler = new Handler(); + handler.postDelayed(new Runnable() { + @Override + public void run() { + GiftValueMrg.get().updateAllMicGiftValueByMsg(values); + } + }, 1200); + } + }); + + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/presenter/SingleRoomPresenter.java b/app/src/main/java/com/chwl/app/avroom/presenter/SingleRoomPresenter.java new file mode 100644 index 0000000..9f7ee37 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/presenter/SingleRoomPresenter.java @@ -0,0 +1,15 @@ +package com.chwl.app.avroom.presenter; + + + +import com.chwl.app.avroom.view.ISingleRoomView; + +/** + *

+ * + * @author jiahui + * @date 2017/12/8 + */ +public class SingleRoomPresenter extends BaseRoomPresenter { + +} diff --git a/app/src/main/java/com/chwl/app/avroom/rank/RoomRankNumberWidget.kt b/app/src/main/java/com/chwl/app/avroom/rank/RoomRankNumberWidget.kt new file mode 100644 index 0000000..504047f --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/rank/RoomRankNumberWidget.kt @@ -0,0 +1,91 @@ +package com.chwl.app.avroom.rank + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import androidx.databinding.DataBindingUtil +import com.chwl.app.R +import com.chwl.app.databinding.RoomRankNumberWidgetBinding +import com.chwl.app.ui.webview.DialogWebViewActivity +import com.chwl.core.UriProvider +import com.chwl.core.im.custom.bean.RoomSerialValueChangedAttachment +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.manager.IMNetEaseManager +import com.chwl.core.manager.RoomEvent +import com.chwl.core.support.room.FrameLayoutRoomWidget +import com.chwl.core.support.room.RoomContext +import com.chwl.core.support.room.RoomView +import com.chwl.core.support.room.RoomWidget +import com.example.lib_utils.ktx.singleClick + +/** + * 房间榜单入口 + */ +class RoomRankNumberWidget : FrameLayoutRoomWidget, RoomWidget { + + private val binding: RoomRankNumberWidgetBinding = + DataBindingUtil.inflate( + LayoutInflater.from( + context + ), R.layout.room_rank_number_widget, this, true + ) + + constructor(context: Context) : super(context) + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) + + constructor( + context: Context, + attrs: AttributeSet?, + defStyleAttr: Int, + defStyleRes: Int + ) : super(context, attrs, defStyleAttr, defStyleRes) + + init { + this.singleClick { + DialogWebViewActivity.start(context, UriProvider.getRoomRanking()) + } + } + + override fun onInitialize(roomView: RoomView, roomContext: RoomContext) { + super.onInitialize(roomView, roomContext) + refreshData() + registerMemberChangedListener() + } + + override fun onUnbindContext() { + super.onUnbindContext() + updateView(null) + } + + private fun registerMemberChangedListener() { + getCompositeDisposable().add(IMNetEaseManager.get().chatRoomEventObservable.subscribe { + when (it.event) { + RoomEvent.SERIAL_VALUE_CHANGED -> { + val attachment = + it.chatRoomMessage.attachment as? RoomSerialValueChangedAttachment + attachment?.serialValue?.let { + updateView(attachment.serialValue) + } + } + } + }) + } + + private fun refreshData() { + val value = AvRoomDataManager.get().serialValue + updateView(value) + } + + private fun updateView(value: Double?) { + if (value == null || value <= 0) { + binding.tvNumber.text = "0" + } else { + binding.tvNumber.text = value.toString() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/rank/RoomRankWidget.kt b/app/src/main/java/com/chwl/app/avroom/rank/RoomRankWidget.kt new file mode 100644 index 0000000..80e450c --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/rank/RoomRankWidget.kt @@ -0,0 +1,94 @@ +package com.chwl.app.avroom.rank + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import androidx.core.view.isVisible +import androidx.databinding.DataBindingUtil +import com.chwl.core.support.room.FrameLayoutRoomWidget +import com.chwl.core.support.room.RoomWidget +import com.chwl.app.R +import com.chwl.app.databinding.RoomRankWidgetBinding +import com.chwl.app.ui.utils.loadAvatar +import com.chwl.app.ui.webview.DialogWebViewActivity +import com.chwl.core.UriProvider +import com.chwl.core.room.bean.RoomContributeDataInfo +import com.chwl.core.room.bean.RoomContributeUserInfo +import com.chwl.core.room.model.RoomContributeListModel +import com.chwl.core.support.room.RoomContext +import com.chwl.core.support.room.RoomView +import com.chwl.core.utils.net.RxHelper +import com.example.lib_utils.ktx.singleClick + +/** + * 房间榜单入口 + */ +class RoomRankWidget : FrameLayoutRoomWidget, RoomWidget { + + private val binding: RoomRankWidgetBinding = + DataBindingUtil.inflate( + LayoutInflater.from( + context + ), R.layout.room_rank_widget, this, true + ) + + constructor(context: Context) : super(context) + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) + + constructor( + context: Context, + attrs: AttributeSet?, + defStyleAttr: Int, + defStyleRes: Int + ) : super(context, attrs, defStyleAttr, defStyleRes) + + init { + this.singleClick { + DialogWebViewActivity.start(context, UriProvider.getRoomRanking()) + refreshData() + } + } + + override fun onInitialize(roomView: RoomView, roomContext: RoomContext) { + super.onInitialize(roomView, roomContext) + refreshData() + } + + override fun onUnbindContext() { + super.onUnbindContext() + updateView(null) + } + + private fun refreshData() { + val disposable = RoomContributeListModel.get() + .getSingleRoomRanking(1, RoomContributeDataInfo.TYPE_ROOM_DAY_RANKING) + .compose(RxHelper.handleBeanData()) + .subscribe { roomContributeDataInfo: RoomContributeDataInfo -> + updateView(roomContributeDataInfo.rankings) + } + getCompositeDisposable().add(disposable) + } + + private fun updateView(list: List?) { + arrayListOf( + binding.ivRank0, binding.ivRank1, binding.ivRank2 + ).forEachIndexed { index, imageView -> + val url = list?.getOrNull(index)?.avatar + if (url.isNullOrEmpty()) { + imageView.isVisible = false + } else { + imageView.loadAvatar(url) + imageView.isVisible = true + } + } + } + + fun setContentBackgroundResource(resId: Int) { + binding.layoutRoot.setBackgroundResource(resId) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/recommendcard/MyRecommendCardActivity.java b/app/src/main/java/com/chwl/app/avroom/recommendcard/MyRecommendCardActivity.java new file mode 100644 index 0000000..23cb56c --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/recommendcard/MyRecommendCardActivity.java @@ -0,0 +1,86 @@ +package com.chwl.app.avroom.recommendcard; + +import android.content.Context; +import android.content.Intent; +import android.view.View; + +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentStatePagerAdapter; + +import com.chwl.app.R; +import com.chwl.app.avroom.adapter.CommonVPAdapter; +import com.chwl.app.base.BaseViewBindingActivity; +import com.chwl.app.base.TitleBar; +import com.chwl.app.databinding.ActivityMyRecommendCardBinding; +import com.chwl.app.module_hall.hall.view.indicator.StatisticsIndicatorAdapter; +import com.chwl.app.ui.webview.CommonWebViewActivity; +import com.chwl.app.ui.widget.magicindicator.ViewPagerHelper; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.CommonNavigator; +import com.chwl.core.UriProvider; +import com.chwl.core.room.recommendpos.bean.RcmdCardType; +import com.chwl.library.utils.ResUtil; + +import java.util.ArrayList; +import java.util.List; + +/** + * 我的推荐位 + * Created by lvzebiao on 2019/1/30. + */ + +public class MyRecommendCardActivity extends BaseViewBindingActivity { + + private List fragmentList = new ArrayList<>(); + + public static void start(Context context) { + Intent intent = new Intent(context, MyRecommendCardActivity.class); + context.startActivity(intent); + } + + @Override + public void init() { + initTitleBar(R.string.my_recommend_position_text); + initIndicator(); + //未使用 + fragmentList.add(RecommendCardFragment.newInstance(RcmdCardType.UN_USE)); + //使用中 + fragmentList.add(RecommendCardFragment.newInstance(RcmdCardType.USING)); + //已使用 + fragmentList.add(RecommendCardFragment.newInstance(RcmdCardType.HAS_USED)); + //已失效 + fragmentList.add(RecommendCardFragment.newInstance(RcmdCardType.INVALID)); + binding.viewPager.setAdapter(new CommonVPAdapter(getSupportFragmentManager() ,getLifecycle(), fragmentList)); + } + + @Override + public void initTitleBar(int title) { + super.initTitleBar(title); + if (mTitleBar != null) { + mTitleBar.addAction(new TitleBar.ImageAction(R.drawable.ic_rcmd_help) { + @Override + public void performAction(View view) { + CommonWebViewActivity.start(context, UriProvider.JAVA_WEB_URL + + "/molistar/modules/recommend-card/help.html"); + } + }); + } + } + + private void initIndicator() { + List tagList = new ArrayList<>(); + tagList.add(ResUtil.getString(R.string.avroom_recommendcard_myrecommendcardactivity_01)); + tagList.add(ResUtil.getString(R.string.avroom_recommendcard_myrecommendcardactivity_02)); + tagList.add(ResUtil.getString(R.string.avroom_recommendcard_myrecommendcardactivity_03)); + tagList.add(ResUtil.getString(R.string.avroom_recommendcard_myrecommendcardactivity_04)); + + StatisticsIndicatorAdapter adapter = new StatisticsIndicatorAdapter(tagList, 0); + adapter.setOnItemSelectListener(position -> binding.viewPager.setCurrentItem(position)); + CommonNavigator navigator = new CommonNavigator(this); + navigator.setAdapter(adapter); + navigator.setAdjustMode(true); + binding.indicator.setNavigator(navigator); + ViewPagerHelper.bind(binding.indicator, binding.viewPager); + + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/recommendcard/RecommendCardFragment.java b/app/src/main/java/com/chwl/app/avroom/recommendcard/RecommendCardFragment.java new file mode 100644 index 0000000..0c1c176 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/recommendcard/RecommendCardFragment.java @@ -0,0 +1,132 @@ +package com.chwl.app.avroom.recommendcard; + +import android.content.Context; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.netease.nim.uikit.common.util.sys.ScreenUtil; +import com.trello.rxlifecycle3.android.FragmentEvent; +import com.chwl.app.R; +import com.chwl.app.base.BaseFragment; +import com.chwl.app.base.list.BaseViewHolder; +import com.chwl.app.base.list.CommonAdapter; +import com.chwl.app.base.list.IRecyclerListener; +import com.chwl.app.base.list.RefreshRecyclerView; +import com.chwl.app.ui.webview.event.H5NotifyClientEvent; +import com.chwl.app.ui.widget.recyclerview.decoration.HorizontalDecoration; +import com.chwl.core.room.recommendpos.RecommendCardModel; +import com.chwl.core.room.recommendpos.bean.RcmdCardType; +import com.chwl.core.room.recommendpos.bean.RecommendCard; +import com.chwl.core.web.bean.H5NotifyData; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.List; + +import io.reactivex.Single; + +/** + * 推荐位的fragment + * Created by lvzebiao on 2019/1/30. + */ +public class RecommendCardFragment extends BaseFragment implements IRecyclerListener { + + private RefreshRecyclerView refreshRecyclerView; + + private int cardType; + /** + * 如果为ture,onResume的时候要刷新 + */ + private boolean refreshWhenOnResume = false; + + public static RecommendCardFragment newInstance(int cardType) { + Bundle bundle = new Bundle(); + bundle.putInt(RcmdCardType.EXTRA_TYPE, cardType); + RecommendCardFragment fragment = new RecommendCardFragment(); + fragment.setArguments(bundle); + return fragment; + } + + @Override + public void onFindViews() { + super.onFindViews(); + refreshRecyclerView = mView.findViewById(R.id.refresh_recycler_view); + } + + @Override + public void initiate() { + if (getArguments() != null) { + cardType = getArguments().getInt(RcmdCardType.EXTRA_TYPE, RcmdCardType.INVALID); + } + refreshRecyclerView.addItemDecoration(new HorizontalDecoration(ScreenUtil.dip2px(5), false, true)); + refreshRecyclerView.setRecyclerListener(this, this); + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + mView = super.onCreateView(inflater, container, savedInstanceState); + EventBus.getDefault().register(this); + return mView; + } + + @Override + public void onDestroyView() { + EventBus.getDefault().unregister(this); + super.onDestroyView(); + } + + @Override + public int getRootLayoutId() { + return R.layout.fragment_recommend_card; + } + + @Override + public CommonAdapter createAdapter(Context context) { + return new RecommendCardListAdapter(R.layout.item_recommend_card, cardType); + } + + @Override + public RecyclerView.LayoutManager createLayoutManager() { + return new LinearLayoutManager(mContext); + } + + @Override + public Single> getSingle(int page, int size) { + return RecommendCardModel.get().getBagList(cardType, page, size); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onRefreshData(H5NotifyClientEvent event) { + if (event.getData() == null) { + return; + } + H5NotifyData notifyData = H5NotifyData.jsonToBean(event.getData()); + if (notifyData == null) { + return; + } + if (notifyData.getType() == H5NotifyData.TYPE_REFRESH_RECOMMEND_POS_DATA) { + //未使用,和已使用界面需要刷新 || cardType == RcmdCardType.HAS_USED + if (cardType == RcmdCardType.UN_USE || cardType == RcmdCardType.HAS_USED) { + refreshWhenOnResume = true; + } + } + } + + @Override + public void onResume() { + super.onResume(); + if (refreshWhenOnResume) { + refreshWhenOnResume = false; + refreshRecyclerView.onRefreshList(); + } + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/recommendcard/RecommendCardListAdapter.java b/app/src/main/java/com/chwl/app/avroom/recommendcard/RecommendCardListAdapter.java new file mode 100644 index 0000000..2320bef --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/recommendcard/RecommendCardListAdapter.java @@ -0,0 +1,103 @@ +package com.chwl.app.avroom.recommendcard; + +import android.content.Context; +import android.text.style.AbsoluteSizeSpan; +import android.view.View; + +import com.chwl.app.ui.widget.TextSpannableBuilder; +import com.coorchice.library.SuperTextView; +import com.netease.nim.uikit.common.util.sys.ScreenUtil; +import com.chwl.app.R; +import com.chwl.app.UIHelper; +import com.chwl.app.avroom.widget.MessageView; +import com.chwl.app.base.list.BaseViewHolder; +import com.chwl.app.base.list.CommonAdapter; +import com.chwl.core.room.recommendpos.bean.RcmdCardType; +import com.chwl.core.room.recommendpos.bean.RecommendCard; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.TimeUtils; + +/** + * 推荐卡列表 + * Created by lvzebiao on 2019/1/30. + */ + +public class RecommendCardListAdapter extends CommonAdapter { + + private int cardType; + + public RecommendCardListAdapter(int layoutId, int cardType) { + super(layoutId); + this.cardType = cardType; + } + + @Override + protected void convert(BaseViewHolder holder, RecommendCard item) { + holder.setText(R.id.tv_time_title, item.getCardName()); + + TextSpannableBuilder builder = new TextSpannableBuilder(null); + builder.append("X", new AbsoluteSizeSpan(ScreenUtil.sp2px(12))) + .append(String.valueOf(item.getCount())); + holder.setText(R.id.tv_card_count, builder.build()); + SuperTextView stv_card_op = holder.getView(R.id.stv_card_op); + Context context = stv_card_op.getContext(); + holder.setText(R.id.tv_card_valid_time, ResUtil.getString(R.string.avroom_recommendcard_recommendcardlistadapter_01)); + StringBuilder validTimeBuild = new StringBuilder(); + //有效期格式 使用时间开始的格式 + String validEndFormat = "year.mon.day hour:min"; + String useEndFormat = "-hour:min"; + if (cardType == RcmdCardType.UN_USE) { + holder.setBackgroundRes(R.id.scl_container, R.drawable.bg_recommend_card_vaild); + holder.setVisible(R.id.iv_card_status, false); + holder.setGone(R.id.ll_valid_day_container, true); + //有效期 + holder.setText(R.id.tv_card_valid_days, item.getDays() + ResUtil.getString(R.string.avroom_recommendcard_recommendcardlistadapter_02)); + stv_card_op.setVisibility(View.VISIBLE); + stv_card_op.setSolid(context.getResources().getColor(R.color.white)); + stv_card_op.setText(ResUtil.getString(R.string.avroom_recommendcard_recommendcardlistadapter_03)); + stv_card_op.setClickable(true); + holder.setGone(R.id.view_white_line, false); + holder.setGone(R.id.tv_card_count, true); + validTimeBuild.append(ResUtil.getString(R.string.avroom_recommendcard_recommendcardlistadapter_04)) + .append(TimeUtils.getFormatTimeString(item.getValidEndTime(), validEndFormat)); + stv_card_op.setOnClickListener(v -> { + UIHelper.showRecommendPosH5(context); + }); + } else if (cardType == RcmdCardType.USING) { + holder.setBackgroundRes(R.id.scl_container, R.drawable.bg_recommend_card_vaild); + holder.setVisible(R.id.iv_card_status, false); + stv_card_op.setVisibility(View.VISIBLE); + stv_card_op.setSolid(context.getResources().getColor(R.color.white_transparent_50)); + stv_card_op.setText(ResUtil.getString(R.string.avroom_recommendcard_recommendcardlistadapter_06)); + stv_card_op.setClickable(false); + holder.setGone(R.id.ll_valid_day_container, false); + holder.setGone(R.id.view_white_line, true); + holder.setGone(R.id.tv_card_count, false); + validTimeBuild.append(ResUtil.getString(R.string.avroom_recommendcard_recommendcardlistadapter_07)) + .append(TimeUtils.getFormatTimeString(item.getUseStartTime(), validEndFormat)) + .append(TimeUtils.getFormatTimeString(item.getUseEndTime(), useEndFormat)); + } else if (cardType == RcmdCardType.HAS_USED) { + holder.setBackgroundRes(R.id.scl_container, R.drawable.bg_recommend_card_invaild); + holder.setVisible(R.id.iv_card_status, true); + holder.setImageResource(R.id.iv_card_status, R.drawable.ic_card_has_used); + stv_card_op.setVisibility(View.GONE); + holder.setGone(R.id.ll_valid_day_container, false); + holder.setGone(R.id.view_white_line, true); + holder.setGone(R.id.tv_card_count, false); + validTimeBuild.append(ResUtil.getString(R.string.avroom_recommendcard_recommendcardlistadapter_08)) + .append(TimeUtils.getFormatTimeString(item.getUseStartTime(), validEndFormat)) + .append(TimeUtils.getFormatTimeString(item.getUseEndTime(), useEndFormat)); + } else { + holder.setBackgroundRes(R.id.scl_container, R.drawable.bg_recommend_card_invaild); + holder.setVisible(R.id.iv_card_status, true); + holder.setImageResource(R.id.iv_card_status, R.drawable.ic_card_invalid); + stv_card_op.setVisibility(View.GONE); + holder.setGone(R.id.ll_valid_day_container, false); + holder.setGone(R.id.view_white_line, true); + holder.setGone(R.id.tv_card_count, true); + validTimeBuild.append(ResUtil.getString(R.string.avroom_recommendcard_recommendcardlistadapter_09)); + validTimeBuild.append(TimeUtils.getFormatTimeString(item.getValidEndTime(), validEndFormat)); + } + holder.setText(R.id.tv_card_valid_time, validTimeBuild.toString()); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/room_album/ChooseGiftRoomAlbumDialogFragment.kt b/app/src/main/java/com/chwl/app/avroom/room_album/ChooseGiftRoomAlbumDialogFragment.kt new file mode 100644 index 0000000..9905e0b --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/room_album/ChooseGiftRoomAlbumDialogFragment.kt @@ -0,0 +1,84 @@ +package com.chwl.app.avroom.room_album + +import android.app.Dialog +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.WindowManager +import androidx.recyclerview.widget.GridLayoutManager +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import com.chwl.app.R +import com.chwl.app.databinding.DialogChooseGiftRoomAlbumBinding +import com.chwl.app.ui.utils.ImageLoadUtilsV2 +import com.chwl.app.ui.widget.recyclerview.decoration.GridSpacingItemNewDecoration +import com.chwl.core.gift.GiftModel +import com.chwl.core.gift.bean.GiftInfo +import com.chwl.core.gift.bean.GiftType + +class ChooseGiftRoomAlbumDialogFragment : BottomSheetDialogFragment() { + + private var _binding: DialogChooseGiftRoomAlbumBinding? = null + private val binding get() = _binding!! + + var onPickedListener: OnPickedListener? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setStyle(STYLE_NO_TITLE, R.style.ErbanBottomSheetDialog) + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val dialog = super.onCreateDialog(savedInstanceState) + dialog.window?.attributes?.apply { + width = WindowManager.LayoutParams.MATCH_PARENT + height = WindowManager.LayoutParams.MATCH_PARENT + } + + return dialog + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = DialogChooseGiftRoomAlbumBinding.inflate(layoutInflater, container, false) + + binding.rvGifts.layoutManager = GridLayoutManager(context, 4) + binding.rvGifts.addItemDecoration(GridSpacingItemNewDecoration(resources.getDimensionPixelOffset(R.dimen.dp_20), true)) + + + binding.rvGifts.adapter = object : BaseQuickAdapter(R.layout.item_gift_room_album){ + override fun convert(helper: BaseViewHolder, item: GiftInfo) { + ImageLoadUtilsV2.loadImage(helper.getView(R.id.iv_gift), item.giftUrl) + helper.setText(R.id.tv_gift, item.giftName) + helper.setText(R.id.tv_value, item.goldPrice.toString()) + } + }.apply { + val gifts = GiftModel.get().getGiftInfoList(GiftType.GIFT_TYPE_NORMAL) + setNewData(gifts) + + setOnItemClickListener { _, _, position -> + onPickedListener?.onPicked(data[position]) + dismiss() + } + } + + binding.ivClose.setOnClickListener { dismiss() } + + return binding.root + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + + fun interface OnPickedListener { + fun onPicked(giftInfo: GiftInfo) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/room_album/PhotoItem.kt b/app/src/main/java/com/chwl/app/avroom/room_album/PhotoItem.kt new file mode 100644 index 0000000..8cffee5 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/room_album/PhotoItem.kt @@ -0,0 +1,14 @@ +package com.chwl.app.avroom.room_album + +import com.chad.library.adapter.base.entity.MultiItemEntity + +data class PhotoItem(val path: String, val type: Int) : MultiItemEntity { + override fun getItemType(): Int { + return type + } + + companion object { + const val TYPE_PHOTO = 0 + const val TYPE_ADD = 1 + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/room_album/RoomAlbumActivity.kt b/app/src/main/java/com/chwl/app/avroom/room_album/RoomAlbumActivity.kt new file mode 100644 index 0000000..77350c3 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/room_album/RoomAlbumActivity.kt @@ -0,0 +1,121 @@ +package com.chwl.app.avroom.room_album + +import android.annotation.SuppressLint +import android.content.Context +import android.content.Intent +import android.graphics.Canvas +import android.graphics.LinearGradient +import android.graphics.Shader +import androidx.activity.viewModels +import androidx.core.content.ContextCompat +import androidx.fragment.app.Fragment +import androidx.viewpager2.adapter.FragmentStateAdapter +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.databinding.ActivityRoomAlbumBinding +import com.chwl.app.ui.widget.magicindicator.ViewPagerHelper +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.CommonNavigator +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.CommonNavigatorAdapter +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerIndicator +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerTitleView +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.indicators.GradientLinePagerIndicator +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.indicators.LinePagerIndicator +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.titles.ColorTransitionPagerTitleView + +class RoomAlbumActivity : BaseViewBindingActivity() { + + val viewModel: RoomAlbumViewModel by viewModels() + var loadDialog: UploadRoomAlbumDialogFragment? = null + + override fun init() { + initTitleBar(getString(R.string.room_album)) + mTitleBar.setBackgroundResource(R.color.white) + + val titles = listOf("我的照片", "普通照片", "解鎖照片") + + binding.indicator.navigator = CommonNavigator(this).apply { + isAdjustMode = true + + adapter = object : CommonNavigatorAdapter() { + var startColor = ContextCompat.getColor(context, R.color.color_5CF1FF) + var endColor = ContextCompat.getColor(context, R.color.color_CF70FF) + override fun getCount(): Int { + return 3 + } + + override fun getTitleView(context: Context, index: Int): IPagerTitleView { + return ColorTransitionPagerTitleView(context).apply { + normalColor = ContextCompat.getColor(context, R.color.color_767585) + selectedColor = ContextCompat.getColor(context, R.color.color_1F1B4F) + text = titles[index] + }.apply { + setOnClickListener { binding.vp.currentItem = index } + } + } + + override fun getIndicator(context: Context?): IPagerIndicator { + return object : GradientLinePagerIndicator(context) { + @SuppressLint("DrawAllocation") + override fun onDraw(canvas: Canvas) { + val g = LinearGradient( + lineRect.left, + lineRect.top, + lineRect.right, + lineRect.bottom, + intArrayOf(startColor, endColor), + null, + Shader.TileMode.CLAMP + ) + paint.shader = g + canvas.drawRoundRect(lineRect, roundRadius, roundRadius, paint) + } + + }.apply { + lineHeight = resources.getDimensionPixelOffset(R.dimen.dp_4).toFloat() + lineWidth = resources.getDimensionPixelOffset(R.dimen.dp_15).toFloat() + roundRadius = resources.getDimensionPixelOffset(R.dimen.dp_2).toFloat() + mode = LinePagerIndicator.MODE_EXACTLY + } + } + } + } + ViewPagerHelper.bind(binding.indicator, binding.vp) + + val fragments = listOf( + RoomAlbumFragment.newInstance(RoomAlbumFragment.TYPE_MINE), + RoomAlbumFragment.newInstance(RoomAlbumFragment.TYPE_COMMON), + RoomAlbumFragment.newInstance(RoomAlbumFragment.TYPE_LOCKED) + ) + + binding.vp.adapter = object : FragmentStateAdapter(this) { + override fun getItemCount(): Int { + return fragments.size + } + + override fun createFragment(position: Int): Fragment { + return fragments[position] + } + } + + binding.tvUpload.setOnClickListener { + loadDialog = UploadRoomAlbumDialogFragment() + loadDialog?.show( + supportFragmentManager, + UploadRoomAlbumDialogFragment::class.java.simpleName + ) + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + loadDialog?.onActivityResult(requestCode, resultCode, data) + } + + companion object { + @JvmStatic + fun start(context: Context) { + val starter = Intent(context, RoomAlbumActivity::class.java) + context.startActivity(starter) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/room_album/RoomAlbumFragment.kt b/app/src/main/java/com/chwl/app/avroom/room_album/RoomAlbumFragment.kt new file mode 100644 index 0000000..1b35780 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/room_album/RoomAlbumFragment.kt @@ -0,0 +1,201 @@ +package com.chwl.app.avroom.room_album + +import android.os.Bundle +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.fragment.app.activityViewModels +import androidx.fragment.app.viewModels +import androidx.recyclerview.widget.GridLayoutManager +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chad.library.adapter.base.diff.BaseQuickDiffCallback +import com.chwl.app.R +import com.chwl.app.avroom.bean.RoomAlbumPhotoInfo +import com.chwl.app.base.BaseViewBindingFragment +import com.chwl.app.databinding.FragmentRoomAlbumBinding +import com.chwl.app.photo.BigPhotoActivity +import com.chwl.app.photo.PagerOption +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.app.ui.utils.ImageLoadUtilsV2 +import com.chwl.app.ui.widget.ButtonItem +import com.chwl.app.ui.widget.recyclerview.decoration.GridSpacingItemNewDecoration +import com.chwl.app.utils.ObjectTypeHelper +import com.chwl.core.Constants + +class RoomAlbumFragment : BaseViewBindingFragment() { + + private val activityViewModel by activityViewModels() + private val viewModel by viewModels() + + private val type: Int by lazy { + requireArguments().getInt("type") + } + + private var page = 1 + + override fun init() { + binding.recyclerView.layoutManager = GridLayoutManager(context, 2) + val offsetH = resources.getDimensionPixelOffset(R.dimen.dp_7) + val offsetV = resources.getDimensionPixelOffset(R.dimen.dp_4) + binding.recyclerView.addItemDecoration( + GridSpacingItemNewDecoration( + offsetV, + offsetH, + false + ) + ) + val adapter = object : + BaseQuickAdapter(R.layout.item_room_album) { + override fun convert(helper: BaseViewHolder, item: RoomAlbumPhotoInfo) { + val ivPhoto = helper.getView(R.id.iv_pic) + if (item.status == 1) { + ImageLoadUtilsV2.loadImage(ivPhoto, item.photoUrl) + helper.setVisible(R.id.iv_lock, false) + } else { + ImageLoadUtils.loadImageWithBlur( + context, + item.photoUrl, + ivPhoto, + 25, 4 + ) + helper.setVisible(R.id.iv_lock, true) + } + + helper.setVisible(R.id.v_action, type == TYPE_MINE) + helper.setVisible(R.id.v_bottom_mask, item.type == 2) + helper.setVisible(R.id.iv_gift, item.type == 2) + helper.setVisible(R.id.iv_diamond, item.type == 2) + helper.setVisible(R.id.tv_value, item.type == 2) + + helper.itemView.setOnClickListener { + if (item.type != 1) { + return@setOnClickListener + } + + BigPhotoActivity.start( + activity, + ObjectTypeHelper.pathToCustomItems(item.photoUrl), + 0, PagerOption().setSave(true) + ) + } + + if (item.type == 2) { + val ivGift = helper.getView(R.id.iv_gift) + ImageLoadUtilsV2.loadImage(ivGift, item.giftUrl) + helper.setText(R.id.tv_value, item.totalGoldPrice.toString()) + } + + } + + override fun onCreateDefViewHolder( + parent: ViewGroup?, + viewType: Int + ): BaseViewHolder { + val holder = super.onCreateDefViewHolder(parent, viewType) + holder.addOnClickListener(R.id.v_action) + return holder + } + + }.apply { + addFooterView(View(context).apply { + layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, resources.getDimensionPixelOffset(R.dimen.dp_80)) + }) + setEnableLoadMore(true) + setOnLoadMoreListener({ + viewModel.loadPhotos(type, ++page) + }, binding.recyclerView) + + setOnItemChildClickListener { _, view, position -> + if (view.id == R.id.v_action) { + val buttonItems = listOf( + ButtonItem("發送到公屏") { + dialogManager.showOkCancelDialog("確認將該照片發送至公屏") { + viewModel.sendPhoto(data[position].id) + } + }, + ButtonItem("刪除照片") { + viewModel.deletePhoto(data[position].id) + }, + ButtonItem("查看大圖") { + BigPhotoActivity.start( + activity, + ObjectTypeHelper.pathToCustomItems(data[position].photoUrl), + 0, PagerOption().setSave(true) + ) + } + ) + dialogManager.showCommonPopupDialog(buttonItems) + + } + } + } + + binding.recyclerView.adapter = adapter + + binding.refreshLayout.setOnRefreshListener { + page = Constants.PAGE_START + viewModel.loadPhotos(type) + } + + viewModel.loadPhotos(type) + + activityViewModel.uploadLiveData.observe(this) { + page = Constants.PAGE_START + viewModel.loadPhotos(type) + } + + viewModel.myPhotosLiveData.observe(this@RoomAlbumFragment) { + adapter.loadMoreComplete() + + adapter.setNewDiffData(object : BaseQuickDiffCallback(it) { + override fun areItemsTheSame( + oldItem: RoomAlbumPhotoInfo, + newItem: RoomAlbumPhotoInfo + ): Boolean { + return oldItem.id == newItem.id + } + + override fun areContentsTheSame( + oldItem: RoomAlbumPhotoInfo, + newItem: RoomAlbumPhotoInfo + ): Boolean { + return oldItem.photoUrl === newItem.photoUrl + } + }) + + binding.refreshLayout.finishRefresh() + } + viewModel.deleteLiveData.observe(this) { + viewModel.loadPhotos(type) + } + viewModel.loadStateLiveData.observe(this) { + if (it == true) { + adapter.loadMoreComplete() + } else { + if (page > 1) { + page-- + } + adapter.loadMoreFail() + } + binding.refreshLayout.finishRefresh() + } + viewModel.noMoreLiveData.observe(this) { + if (it == true) { + adapter.loadMoreEnd() + } + } + } + + companion object { + const val TYPE_MINE = 0 + const val TYPE_COMMON = 1 + const val TYPE_LOCKED = 2 + fun newInstance(type: Int) = RoomAlbumFragment().apply { + arguments = Bundle().apply { + putInt("type", type) + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/room_album/RoomAlbumFragmentViewModel.kt b/app/src/main/java/com/chwl/app/avroom/room_album/RoomAlbumFragmentViewModel.kt new file mode 100644 index 0000000..3f75f48 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/room_album/RoomAlbumFragmentViewModel.kt @@ -0,0 +1,69 @@ +package com.chwl.app.avroom.room_album + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import com.chwl.app.R +import com.chwl.app.avroom.bean.RoomAlbumPhotoInfo +import com.chwl.app.base.BaseViewModel +import com.chwl.core.Constants +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.utils.extension.toast +import com.hjq.toast.ToastUtils + +class RoomAlbumFragmentViewModel : BaseViewModel() { + + private val _myPhotosLiveData = MutableLiveData?>() + val myPhotosLiveData: LiveData?> = _myPhotosLiveData + + private val _deleteLiveData = MutableLiveData() + val deleteLiveData: LiveData = _deleteLiveData + + private val _loadStateLiveData = MutableLiveData() + val loadStateLiveData: LiveData = _loadStateLiveData + + private val _noMoreLiveData = MutableLiveData() + val noMoreLiveData: LiveData = _noMoreLiveData + + fun loadPhotos(type: Int, page: Int = 1) { + safeLaunch(block = { + val data = RoomAlbumModel.loadPhotos(AvRoomDataManager.get().roomUid, type, page) + + data?.let { + val value = _myPhotosLiveData.value + if (page == 1) { + _myPhotosLiveData.value = it.toMutableList() + } else { + value?.addAll(it) + _myPhotosLiveData.value = value + } + + _loadStateLiveData.value = true + _noMoreLiveData.value = it.size < Constants.PAGE_SIZE + } + + }, onError = { + it.message.toast() + _loadStateLiveData.value = false + }) + } + + fun sendPhoto(photoId: Int) { + safeLaunch(block = { + RoomAlbumModel.sendPhoto(AvRoomDataManager.get().roomUid, photoId) + }, onComplete = { + ToastUtils.show(R.string.doSuccess) + }) + } + + fun deletePhoto(photoId: Int) { + safeLaunch(block = { + RoomAlbumModel.deletePhoto(photoId) + + _deleteLiveData.value = true + + }, onComplete = { + ToastUtils.show(R.string.doSuccess) + }) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/room_album/RoomAlbumModel.kt b/app/src/main/java/com/chwl/app/avroom/room_album/RoomAlbumModel.kt new file mode 100644 index 0000000..1735dfb --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/room_album/RoomAlbumModel.kt @@ -0,0 +1,100 @@ +package com.chwl.app.avroom.room_album + +import com.chwl.app.avroom.bean.RoomAlbumPhotoInfo +import com.chwl.core.Constants +import com.chwl.core.bean.response.ServiceResult +import com.chwl.core.gift.bean.GiftReceiveInfo +import com.chwl.core.utils.net.RxHelper +import com.chwl.core.utils.net.launchRequest +import com.chwl.library.net.rxnet.RxNet +import io.reactivex.Single +import retrofit2.http.Field +import retrofit2.http.FormUrlEncoded +import retrofit2.http.GET +import retrofit2.http.POST +import retrofit2.http.Query + +object RoomAlbumModel { + private val api = RxNet.create(Api::class.java) + + suspend fun loadPhotos(roomUid: Long, type: Int, page: Int): List? { + return launchRequest { + api.loadPhotos(roomUid, type, page, Constants.PAGE_SIZE) + } + } + + suspend fun uploadPhotos(roomUid: Long, type: Int, photoUrls: String, giftId: Int?): String? { + return launchRequest { + api.uploadPhotos(roomUid, type, photoUrls, giftId) + } + } + + suspend fun sendPhoto(roomUid: Long, photoId: Int): String? { + return launchRequest { + api.sendPhoto(roomUid, photoId) + } + } + + suspend fun deletePhoto(photoId: Int): String? { + return launchRequest { + api.deletePhoto(photoId) + } + } + + fun unlockRoomPhoto(roomUid: Long, photoId: Int): Single { + return api.unlockRoomPhoto(roomUid, photoId) + .compose(RxHelper.handleCommon()) + .compose(RxHelper.handleSchAndExce()) + } + + fun listUnlockRoomPhoto(roomUid: Long): Single> { + return api.listUnlockRoomPhoto(roomUid) + .compose(RxHelper.handleCommon()) + .compose(RxHelper.handleSchAndExce()) + } + + private interface Api { + + @GET("roomAlbum/pagePhoto") + suspend fun loadPhotos( + @Query("roomUid") roomUid: Long, + @Query("type") type: Int, + @Query("page") page: Int, + @Query("pageSize") pageSize: Int, + ): ServiceResult> + + @FormUrlEncoded + @POST("roomAlbum/upload") + suspend fun uploadPhotos( + @Field("roomUid") roomUid: Long, + @Field("type") type: Int, + @Field("photoUrls") photoUrls: String, + @Field("giftId") giftId: Int?, + ): ServiceResult + + @FormUrlEncoded + @POST("roomAlbum/sendPhoto") + suspend fun sendPhoto( + @Field("roomUid") roomUid: Long, + @Field("id") photoId: Int, + ): ServiceResult + + @FormUrlEncoded + @POST("roomAlbum/delete") + suspend fun deletePhoto( + @Field("id") photoId: Int, + ): ServiceResult + + @FormUrlEncoded + @POST("roomAlbum/unlockPhoto") + fun unlockRoomPhoto( + @Field("roomUid") roomUid: Long, + @Field("id") photoId: Int + ): Single> + + @GET("roomAlbum/listUnlockPhoto") + fun listUnlockRoomPhoto( + @Query("roomUid") roomUid: Long, + ): Single>> + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/room_album/RoomAlbumViewModel.kt b/app/src/main/java/com/chwl/app/avroom/room_album/RoomAlbumViewModel.kt new file mode 100644 index 0000000..cf93aa8 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/room_album/RoomAlbumViewModel.kt @@ -0,0 +1,48 @@ +package com.chwl.app.avroom.room_album + +import android.annotation.SuppressLint +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import com.chwl.app.base.BaseViewModel +import com.chwl.app.base.Event +import com.chwl.core.file.FileModel +import com.chwl.core.gift.bean.GiftInfo +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.utils.extension.toast +import io.reactivex.Observable +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.schedulers.Schedulers + +class RoomAlbumViewModel : BaseViewModel() { + + + private val _uploadLiveData = MutableLiveData>() + val uploadLiveData: LiveData?> = _uploadLiveData + + @SuppressLint("CheckResult") + fun upload(list: MutableList, type: Int, unlockedGift: GiftInfo?) { + Observable.fromIterable(list) + .flatMap { + FileModel.get().uploadFile(it).toObservable() + } + .toList() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ + safeLaunch(onError = { + _uploadLiveData.value = Event(false) + }, block = { + RoomAlbumModel.uploadPhotos( + AvRoomDataManager.get().roomUid, + type, + it.joinToString(","), + unlockedGift?.giftId + ) + _uploadLiveData.value = Event(true) + }) + }, { + it.message.toast() + _uploadLiveData.value = Event(false) + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/room_album/UnlockRoomAlbumPhotoDialog.kt b/app/src/main/java/com/chwl/app/avroom/room_album/UnlockRoomAlbumPhotoDialog.kt new file mode 100644 index 0000000..f3beae3 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/room_album/UnlockRoomAlbumPhotoDialog.kt @@ -0,0 +1,59 @@ +package com.chwl.app.avroom.room_album + +import android.annotation.SuppressLint +import android.os.Bundle +import com.hjq.toast.ToastUtils +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.databinding.DialogLockRoomAlbumPhotoBinding +import com.chwl.app.ui.utils.ImageLoadUtilsV2 +import com.chwl.core.gift.bean.GiftReceiveInfo +import com.chwl.core.manager.AvRoomDataManager + +class UnlockRoomAlbumPhotoDialog : BaseDialogFragment(){ + + var onUnlockRoomPhotoListener: OnUnlockRoomPhotoListener? = null + + @SuppressLint("CheckResult") + override fun init() { + val arguments = requireArguments() + val giftUrl = arguments.getString("giftUrl") + val giftName = arguments.getString("giftName") + val price = arguments.getInt("price") + val photoId = arguments.getInt("photoId") + + ImageLoadUtilsV2.loadImage(binding.ivGift, giftUrl) + binding.tvGiftName.text = giftName + binding.tvValue.text = price.toString() + + binding.tvAction.setOnClickListener { + RoomAlbumModel.unlockRoomPhoto(AvRoomDataManager.get().roomUid, photoId) + .subscribe({ + onUnlockRoomPhotoListener?.onUnlockRoomPhoto(it) + dismiss() + }, { + ToastUtils.show(it.message) + }) + } + + binding.ivClose.setOnClickListener { + dismiss() + } + } + + companion object{ + fun newInstance(photoId:Int, giftUrl: String?, giftName:String, price:Int): UnlockRoomAlbumPhotoDialog { + val args = Bundle() + args.putInt("photoId", photoId) + args.putString("giftUrl", giftUrl) + args.putString("giftName", giftName) + args.putInt("price", price) + val fragment = UnlockRoomAlbumPhotoDialog() + fragment.arguments = args + return fragment + } + } + + fun interface OnUnlockRoomPhotoListener{ + fun onUnlockRoomPhoto(unlockRoomAlbumPhotoInfo: GiftReceiveInfo) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/room_album/UploadRoomAlbumDialogFragment.kt b/app/src/main/java/com/chwl/app/avroom/room_album/UploadRoomAlbumDialogFragment.kt new file mode 100644 index 0000000..05a8ce5 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/room_album/UploadRoomAlbumDialogFragment.kt @@ -0,0 +1,280 @@ +package com.chwl.app.avroom.room_album + +import android.annotation.SuppressLint +import android.app.Activity +import android.app.Dialog +import android.content.Intent +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.WindowManager +import androidx.core.content.ContextCompat +import androidx.fragment.app.activityViewModels +import androidx.recyclerview.widget.GridLayoutManager +import com.chad.library.adapter.base.BaseMultiItemQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.base.PhotoPickActivity +import com.chwl.app.common.widget.dialog.DialogManager +import com.chwl.app.databinding.DialogRoomAlbumUploadBinding +import com.chwl.app.ui.utils.ImageLoadUtilsV2 +import com.chwl.app.ui.widget.recyclerview.decoration.GridSpacingItemNewDecoration +import com.chwl.core.Constants +import com.chwl.core.gift.bean.GiftInfo +import com.chwl.core.utils.myutil.MyUriUtils +import com.chwl.library.common.util.PhotoCompressUtil.compress +import com.chwl.library.common.util.PhotoCompressUtil.getCompressCachePath +import com.chwl.library.common.util.PhotosCompressCallback +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import com.hjq.toast.ToastUtils +import kotlinx.coroutines.Job + +class UploadRoomAlbumDialogFragment : BottomSheetDialogFragment() { + + private var _binding: DialogRoomAlbumUploadBinding? = null + private val binding get() = _binding!! + + private val viewModel by activityViewModels() + + private lateinit var photoAdapter: BaseMultiItemQuickAdapter + + private var unlockedGift: GiftInfo? = null + + private val PICK_CODE = 1112 + + private var compressJob: Job? = null + val dialogManager by lazy { + DialogManager(context) + } + + private val addItem = PhotoItem("", PhotoItem.TYPE_ADD) + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setStyle(STYLE_NO_TITLE, R.style.ErbanBottomSheetDialog) + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val dialog = super.onCreateDialog(savedInstanceState) + dialog.window?.attributes?.apply { + width = WindowManager.LayoutParams.MATCH_PARENT + height = WindowManager.LayoutParams.MATCH_PARENT + } + + return dialog + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = DialogRoomAlbumUploadBinding.inflate(layoutInflater, container, false) + + binding.rvPhoto.layoutManager = GridLayoutManager(context, 3) + binding.rvPhoto.addItemDecoration( + GridSpacingItemNewDecoration( + resources.getDimensionPixelOffset( + R.dimen.dp_18 + ), true + ) + ) + + photoAdapter = + object : BaseMultiItemQuickAdapter(mutableListOf(addItem)) { + init { + addItemType(PhotoItem.TYPE_PHOTO, R.layout.item_publish_image) + addItemType(PhotoItem.TYPE_ADD, R.layout.item_add_picture) + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder { + val holder = super.onCreateViewHolder(parent, viewType) + if (viewType == PhotoItem.TYPE_PHOTO) { + holder.setGone(R.id.iv_gif_tag, false) + holder.setImageResource(R.id.iv_delete, R.drawable.ic_delete_room_album) + holder.addOnClickListener(R.id.iv_delete) + } + return holder + } + + override fun convert(helper: BaseViewHolder, item: PhotoItem) { + if (item.type == PhotoItem.TYPE_ADD) { + return + } + + ImageLoadUtilsV2.loadImage(helper.getView(R.id.iv_photo), item.path, false, 8) + } + }.apply { + setOnItemChildClickListener { _, view, position -> + if (view.id == R.id.iv_delete) { + remove(position) + if (data.last().type != PhotoItem.TYPE_ADD) { + addData(addItem) + } + } + } + setOnItemClickListener { _, _, position -> + if (position == data.size - 1) { + checkStoragePermission() + } + } + } + + binding.rvPhoto.adapter = photoAdapter + + binding.vGift.isEnabled = false + binding.rgType.setOnCheckedChangeListener { group, checkedId -> + if (checkedId == binding.rbCommon.id) { + binding.tvNoGift.visibility = View.VISIBLE + binding.tvNoGift.text = + getString(R.string.room_album_type_no_need_unlocked_gift_tips) + binding.groupGift.visibility = View.INVISIBLE + unlockedGift = null + + binding.vGift.isEnabled = false + binding.tvGiftLabel.setTextColor( + ContextCompat.getColor( + requireContext(), + R.color.color_B3B3C3 + ) + ) + } else { + binding.tvNoGift.visibility = View.VISIBLE + binding.tvNoGift.text = + getString(R.string.room_album_type_choose_unlocked_gift_tips) + + binding.groupGift.visibility = View.INVISIBLE + binding.vGift.isEnabled = true + binding.tvGiftLabel.setTextColor( + ContextCompat.getColor( + requireContext(), + R.color.color_1F1B4F + ) + ) + } + } + + binding.vGift.setOnClickListener { + val chooseGiftRoomAlbumDialogFragment = ChooseGiftRoomAlbumDialogFragment() + chooseGiftRoomAlbumDialogFragment.onPickedListener = + ChooseGiftRoomAlbumDialogFragment.OnPickedListener { + unlockedGift = it + + binding.tvNoGift.visibility = View.INVISIBLE + binding.groupGift.visibility = View.VISIBLE + + ImageLoadUtilsV2.loadImage(binding.ivGift, it.giftUrl) + binding.tvGiftName.text = it.giftName + binding.tvGiftValue.text = it.goldPrice.toString() + } + chooseGiftRoomAlbumDialogFragment.show( + childFragmentManager, + UploadRoomAlbumDialogFragment::class.java.simpleName + ) + } + + binding.slConfirm.setOnClickListener { + val list = mutableListOf() + photoAdapter.data.forEach { + if (it.type == PhotoItem.TYPE_PHOTO) { + list.add(it.path) + } + } + if (list.size < 1) { + ToastUtils.show("未選擇圖片") + return@setOnClickListener + } + + val type = if (binding.rgType.checkedRadioButtonId == binding.rbCommon.id) 1 else 2 + if (type == 2 && unlockedGift == null) { + ToastUtils.show("未選擇解鎖禮物") + return@setOnClickListener + } + +// dialogManager.showProgressDialog(context) + viewModel.upload( + list, + type, + unlockedGift + ) + } + + viewModel.uploadLiveData.observe(this) { + it?.getContentIfNotHandled()?.let { success -> +// dialogManager.hideProgressDialog() + + if (success) { + dismiss() + } + + } + } + + binding.ivClose.setOnClickListener { dismiss() } + + return binding.root + } + + private fun checkStoragePermission() { + PhotoPickActivity.start(requireActivity(), PhotoPickActivity.IMG,PICK_CODE) + } + + @Deprecated("Deprecated in Java") + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (resultCode != Activity.RESULT_OK) { + return + } + + if (requestCode == PICK_CODE) { + val uri = data?.data + uri?.let { + if (MyUriUtils.isGif(requireActivity(), uri)) { + ToastUtils.show(R.string.error_file_type) + return@let + } + val file = MyUriUtils.copyFile(requireActivity(), uri) + if (file != null) { + compressPhotos(mutableListOf(file.path)) + } else { + ToastUtils.show(R.string.exception_try_again) + } + } + } + } + + @SuppressLint("NotifyDataSetChanged") + private fun compressPhotos(paths: MutableList) { + compressJob?.cancel(null) + compressJob = compress( + requireContext(), paths, + getCompressCachePath(), + object : PhotosCompressCallback { + override fun onSuccess(compressedImgList: ArrayList) { + val list = photoAdapter.data + val removeLast = list.removeLast() + compressedImgList.forEach { item -> + list.add(PhotoItem(item, PhotoItem.TYPE_PHOTO)) + } + if (list.size < 6) { + list.add(removeLast) + } + photoAdapter.notifyDataSetChanged() + } + + override fun onFail(e: Throwable) { + ToastUtils.show(getString(R.string.picker_image_error)) + } + }, 200, false, Constants.UPLOAD_IMAGE_MAX_SIZE, Constants.UPLOAD_IMAGE_MAX_FILE_LENGTH + ) + + } + + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPKBoardView.kt b/app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPKBoardView.kt new file mode 100644 index 0000000..1112e1d --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPKBoardView.kt @@ -0,0 +1,146 @@ +package com.chwl.app.avroom.singleroompk + +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Color +import android.util.AttributeSet +import android.view.LayoutInflater +import android.widget.FrameLayout +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.view.isVisible +import androidx.lifecycle.Observer +import com.netease.nim.uikit.common.util.sys.TimeUtil +import com.chwl.app.R +import com.chwl.app.avroom.activity.AVRoomActivity +import com.chwl.app.databinding.LayoutSingleRoomPkBoardViewBinding +import com.chwl.app.ui.user.activity.UserInfoActivity +import com.chwl.app.ui.utils.load +import com.chwl.core.im.custom.bean.RoomPkBean +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.room.anotherroompk.SingleRoomPKModel +import com.chwl.core.utils.CurrentTimeUtils +import com.chwl.core.utils.extension.subAndReplaceDot +import com.chwl.core.utils.extension.toast +import com.chwl.library.utils.ResUtil +import io.reactivex.Observable +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import java.util.concurrent.TimeUnit + +class SingleRoomPKBoardView @JvmOverloads constructor( + context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 +) : FrameLayout(context, attrs, defStyleAttr) { + + private val binding = LayoutSingleRoomPkBoardViewBinding.inflate(LayoutInflater.from(context)) + private val observer = Observer { updateView(it) } + private var disposable: Disposable? = null + private var roomPkBean: RoomPkBean? = null + + init { + addView(binding.root, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT) + binding.viewRankListContributeRight.showCharmStyle() + AvRoomDataManager.get().roomPkLiveData.observeForever(observer) + binding.ivFindHim.isVisible = !AvRoomDataManager.get().isRoomOwner + binding.ivFindHim.setOnClickListener { + roomPkBean?.let { + AVRoomActivity.start(context, it.aUid) + } + } + + binding.ivBlueAvatar.setOnClickListener { + roomPkBean?.let { + UserInfoActivity.Companion.start(context, it.aUid) + } + } + + binding.ivRule.setOnClickListener { + SingleRoomPkRuleDialog.newInstance().show(context) + } + + binding.ivMuteAnother.setOnClickListener { + if (AvRoomDataManager.get().isRoomOwner) { + roomPkBean?.let { + if (it.roundId == null) { + return@let + } + SingleRoomPKModel + .muteSingleRoomPkOtherMic(it.roundId, it.aMicStatus xor 1) + .subscribe() + } + } else { + ResUtil.getString(R.string.close_other_room_sound).toast() + } + } + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + AvRoomDataManager.get().roomPkLiveData.removeObserver(observer) + disposable?.dispose() + } + + @SuppressLint("SetTextI18n") + private fun updateView(roomPkBean: RoomPkBean?) { + this.roomPkBean = roomPkBean + + binding.viewRankListContributeLeft.updateData(roomPkBean?.csRank) + binding.viewRankListContributeRight.updateData(roomPkBean?.asRank) + + binding.ivBlueAvatar.load(roomPkBean?.aAvatar) + binding.tvBlueNickname.text = roomPkBean?.aNick.subAndReplaceDot(7) + + binding.pbScore.progress = ((roomPkBean?.cPercent ?: 0.5f) * 100).toInt() + val layoutParams = binding.svgaHot.layoutParams as ConstraintLayout.LayoutParams + val percent = roomPkBean?.cPercent ?: 0.5f + layoutParams.horizontalBias = when { + percent < 0.02f -> 0.02f + percent > 0.98f -> 0.98f + else -> percent + } + binding.svgaHot.layoutParams = layoutParams + + binding.tvScoreLeft.text = "${roomPkBean?.cAmount ?: 0}" + binding.tvScoreRight.text = "${roomPkBean?.aAmount ?: 0}" + disposable?.dispose() + disposable = Observable.interval(1, TimeUnit.SECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { _ -> + if (roomPkBean?.pkState == 1) { + binding.tvPk.text = "PK" + binding.tvTime.text = roomPkBean.endTime.let { + val remainTime = (it - CurrentTimeUtils.getCurrentTime()).toInt() / 1000 + binding.tvTime.setTextColor(Color.parseColor(if (remainTime <= 30) "#ff87a1" else "#ffffff")) + if (remainTime > 0) TimeUtil.secToTime(remainTime) else ResUtil.getString(R.string.avroom_singleroompk_singleroompkboardview_01) + } ?: ResUtil.getString(R.string.avroom_singleroompk_singleroompkboardview_02) + } else { + binding.tvPk.text = ResUtil.getString(R.string.avroom_singleroompk_singleroompkboardview_03) + binding.tvTime.text = roomPkBean?.penaltyEndTime?.let { + val remainTime = (it - CurrentTimeUtils.getCurrentTime()).toInt() / 1000 + binding.tvTime.setTextColor(Color.parseColor(if (remainTime <= 30) "#ff87a1" else "#fff600")) + TimeUtil.secToTime(remainTime) + } ?: "00:00" + } + } + + if (roomPkBean == null || roomPkBean.pkState == 1) { + binding.ivPkResult.isVisible = false + } else if (roomPkBean.winUid == 0L) { + binding.ivPkResult.isVisible = true + binding.ivPkResult.setImageResource(R.drawable.single_room_pk_ic_result_deuce) + } else if (roomPkBean.winUid == roomPkBean.cUid) { + binding.ivPkResult.isVisible = true + binding.ivPkResult.setImageResource(R.drawable.single_room_pk_ic_result_failed) + } else { + binding.ivPkResult.isVisible = true + binding.ivPkResult.setImageResource(R.drawable.single_room_pk_ic_result_win) + } + if (roomPkBean?.aMicStatus == 0) { + binding.ivMuteAnother.isVisible = true + binding.ivMuteAnother.setImageResource(R.drawable.single_room_pk_ic_another_mic_close) + } else { + binding.ivMuteAnother.setImageResource(R.drawable.single_room_pk_ic_another_mic_open) + binding.ivMuteAnother.isVisible = AvRoomDataManager.get().isRoomOwner + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPKCreateActivity.kt b/app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPKCreateActivity.kt new file mode 100644 index 0000000..1052880 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPKCreateActivity.kt @@ -0,0 +1,143 @@ +package com.chwl.app.avroom.singleroompk + +import android.annotation.SuppressLint +import android.content.Context +import android.content.Intent +import android.text.Editable +import android.view.Gravity +import android.view.WindowManager +import androidx.core.view.isVisible +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.databinding.ActivitySingleRoomPkCreateBinding +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.app.ui.widget.TextWatcherSimple +import com.chwl.core.auth.AuthModel +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.room.anotherroompk.SimpleRoomInfo +import com.chwl.core.room.anotherroompk.SingleRoomPKModel +import com.chwl.core.utils.extension.ifNotNullOrEmpty +import com.chwl.core.utils.extension.subAndReplaceDot +import com.chwl.core.utils.extension.toIntOrDef +import com.chwl.core.utils.extension.toast +import com.chwl.library.utils.ResUtil + +class SingleRoomPKCreateActivity : BaseViewBindingActivity() { + + companion object { + @JvmStatic + fun start(context: Context) { + val starter = Intent(context, SingleRoomPKCreateActivity::class.java) + context.startActivity(starter) + } + } + + private var currSimpleRoomInfo: SimpleRoomInfo? = null + + private var pkTime: Int = 10 + + @SuppressLint("CheckResult") + override fun init() { + window.setLayout( + WindowManager.LayoutParams.MATCH_PARENT, + WindowManager.LayoutParams.WRAP_CONTENT, + ) + window.setGravity(Gravity.BOTTOM) + binding.ivHelp.setOnClickListener { + SingleRoomPkRuleDialog.newInstance().show(this) + } + + binding.ivAddPkRoom.setOnClickListener { + SingleRoomPKSearchActivity.start(this) + } + binding.ivDelPkRoom.setOnClickListener { + binding.ivAddPkRoom.isVisible = true + binding.llPkRoom.isVisible = false + currSimpleRoomInfo = null + checkCommitEnable() + } + + binding.rbMin10.setOnCheckedChangeListener { _, isChecked -> + if (isChecked) { + pkTime = 10 + binding.editTime.setText("") + checkCommitEnable() + } + } + binding.rbMin20.setOnCheckedChangeListener { _, isChecked -> + if (isChecked) { + pkTime = 20 + binding.editTime.setText("") + checkCommitEnable() + } + } + binding.rbMin30.setOnCheckedChangeListener { _, isChecked -> + if (isChecked) { + pkTime = 30 + binding.editTime.setText("") + checkCommitEnable() + } + } + + binding.editTime.addTextChangedListener(object : TextWatcherSimple() { + + override fun afterTextChanged(s: Editable?) { + s?.toString().ifNotNullOrEmpty { + pkTime = it.toIntOrDef(0) + if (pkTime != 0) { + binding.rg.clearCheck() + } + checkCommitEnable() + } + } + }) + + binding.tvOk.setOnClickListener { + if (pkTime < 5 || pkTime > 30) { + ResUtil.getString(R.string.avroom_singleroompk_singleroompkcreateactivity_01).toast() + return@setOnClickListener + } + currSimpleRoomInfo?.let { + SingleRoomPKModel.initiateRoomPK( + it.roomUid, + pkTime, + AvRoomDataManager.get().roomUid, + AuthModel.get().currentUid, + binding.editDesc.text?.toString() + ) + .compose(bindToLifecycle()) + .subscribe( + { + ResUtil.getString(R.string.avroom_singleroompk_singleroompkcreateactivity_02).toast() + finish() + }, { throwable -> + dialogManager.showTipsDialog(throwable.message, null) + } + ) + } + + } + + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (resultCode == RESULT_OK && requestCode == SingleRoomPKSearchActivity.REQUEST_CODE) { + (data?.getSerializableExtra(SingleRoomPKSearchActivity.KEY_ROOM_INFO) as? SimpleRoomInfo)?.let { + currSimpleRoomInfo = it + binding.ivAddPkRoom.isVisible = false + binding.llPkRoom.isVisible = true + ImageLoadUtils.loadImage(this, it.avatar, binding.ivAvatar) + binding.tvRoomTitle.text = it.title.subAndReplaceDot(7) + binding.tvRoomId.text = "ID:${it.erbanNo}" + checkCommitEnable() + } + } + } + + private fun checkCommitEnable(): Boolean { + val isEnabled = currSimpleRoomInfo != null && pkTime != 0 + binding.tvOk.isEnabled = isEnabled + return isEnabled + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPKRankListView.kt b/app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPKRankListView.kt new file mode 100644 index 0000000..d5e5daa --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPKRankListView.kt @@ -0,0 +1,61 @@ +package com.chwl.app.avroom.singleroompk + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.widget.FrameLayout +import androidx.core.view.isInvisible +import androidx.core.view.isVisible +import com.chwl.app.R +import com.chwl.app.databinding.LayoutSingleRoomPkRankListViewBinding +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.core.im.custom.bean.RoomPkBean +import com.chwl.core.room.anotherroompk.ShowUserInfoDialogEvent +import com.chwl.library.rxbus.RxBus + +class SingleRoomPKRankListView @JvmOverloads constructor( + context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 +) : FrameLayout(context, attrs, defStyleAttr) { + + private val binding = + LayoutSingleRoomPkRankListViewBinding.inflate(LayoutInflater.from(context)) + private val tvValues = arrayOf(binding.tvValue1, binding.tvValue2, binding.tvValue3) + private val ivAvatars = arrayOf(binding.ivAvatar1, binding.ivAvatar2, binding.ivAvatar3) + private var defaultAvatarRes = R.drawable.single_room_pk_bg_red_mic + + init { + addView(binding.root) + ivAvatars.forEach { ivAvatar -> + ivAvatar.setOnClickListener { + ivAvatar.tag?.toString()?.let { + RxBus.get().post(ShowUserInfoDialogEvent(it)) + } + } + } + } + + fun showCharmStyle() { + binding.ivAvatar1.setImageResource(R.drawable.single_room_pk_bg_blue_mic) + binding.ivAvatar2.setImageResource(R.drawable.single_room_pk_bg_blue_mic) + binding.ivAvatar3.setImageResource(R.drawable.single_room_pk_bg_blue_mic) + defaultAvatarRes = R.drawable.single_room_pk_bg_blue_mic + } + + fun updateData(data: List?) { + for (i in tvValues.indices) { + val rankBean = data?.getOrNull(i) + tvValues[i].text = rankBean?.amount ?: "0" + tvValues[i].isInvisible = "0" == tvValues[i].text + if (i == 0) { + binding.viewMvp.isVisible = "0" != tvValues[i].text + } + ImageLoadUtils.loadImage( + context, + rankBean?.avatar, + ivAvatars[i], + if (rankBean?.avatar.isNullOrEmpty()) defaultAvatarRes else R.drawable.default_avatar + ) + ivAvatars[i].tag = rankBean?.uid + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPKSearchActivity.kt b/app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPKSearchActivity.kt new file mode 100644 index 0000000..cffdd5c --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPKSearchActivity.kt @@ -0,0 +1,94 @@ +package com.chwl.app.avroom.singleroompk + +import android.annotation.SuppressLint +import android.app.Activity +import android.content.Intent +import android.view.Gravity +import android.view.WindowManager +import androidx.recyclerview.widget.LinearLayoutManager +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.common.EmptyViewHelper +import com.chwl.app.databinding.ActivitySingleRoomPkSearchBinding +import com.chwl.app.ui.user.activity.UserInfoActivity +import com.chwl.app.ui.utils.RVDelegate +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.room.anotherroompk.SimpleRoomInfo +import com.chwl.core.room.anotherroompk.SingleRoomPKModel +import com.chwl.library.utils.ResUtil + +class SingleRoomPKSearchActivity : BaseViewBindingActivity() { + + companion object { + + const val REQUEST_CODE = 0xffaa + const val KEY_ROOM_INFO = "SimpleRoomInfo" + + @JvmStatic + fun start(context: Activity) { + val starter = Intent(context, SingleRoomPKSearchActivity::class.java) + context.startActivityForResult(starter, REQUEST_CODE) + } + } + + private lateinit var rvDelegate: RVDelegate + private var pageNum = 1 + private val pageSize = 20 + private lateinit var roomPKSearchAdapter: SingleRoomPKSearchAdapter + private var searchKey: String? = null + override fun init() { + + window.setLayout( + WindowManager.LayoutParams.MATCH_PARENT, + WindowManager.LayoutParams.WRAP_CONTENT + ) + window.setGravity(Gravity.BOTTOM) + roomPKSearchAdapter = SingleRoomPKSearchAdapter() + rvDelegate = RVDelegate.Builder() + .setPageSize(pageSize) + .setEmptyView(EmptyViewHelper.createEmptyTextView(this, ResUtil.getString(R.string.avroom_singleroompk_singleroompksearchactivity_01))) + .setLayoutManager(LinearLayoutManager(this)) + .setRecyclerView(binding.recyclerView) + .setAdapter(roomPKSearchAdapter) + .build() + + roomPKSearchAdapter.setOnLoadMoreListener({ loadData(false) }, binding.recyclerView) + + roomPKSearchAdapter.setOnItemChildClickListener { _, view, position -> + roomPKSearchAdapter.getItem(position)?.let { + when (view.id) { + R.id.iv_avatar -> UserInfoActivity.Companion.start(this, it.roomUid) + R.id.tv_select -> { + setResult(RESULT_OK, Intent().putExtra(KEY_ROOM_INFO, it)) + finish() + } + } + } + } + + binding.ivBack.setOnClickListener { finish() } + + binding.ivSearch.setOnClickListener { + searchKey = binding.editSearch.text?.toString() + loadData(true) + } + loadData(true) + } + + @SuppressLint("CheckResult") + private fun loadData(isRefresh: Boolean) { + pageNum = if (isRefresh) 1 else pageNum + 1 + SingleRoomPKModel.searchPermitRoom( + searchKey, + AvRoomDataManager.get().roomUid, + pageNum, + pageSize + ) + .compose(bindToLifecycle()) + .subscribe({ + rvDelegate.loadData(it, isRefresh) + }, { + rvDelegate.loadErr(isRefresh) + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPKSearchAdapter.kt b/app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPKSearchAdapter.kt new file mode 100644 index 0000000..d2afcc6 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPKSearchAdapter.kt @@ -0,0 +1,35 @@ +package com.chwl.app.avroom.singleroompk + +import android.graphics.Color +import android.widget.TextView +import androidx.core.graphics.toColorInt +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.core.room.anotherroompk.SimpleRoomInfo +import com.chwl.core.utils.extension.subAndReplaceDot +import com.chwl.library.utils.ResUtil + +class SingleRoomPKSearchAdapter : + BaseQuickAdapter(R.layout.item_single_room_pk_search) { + + override fun convert(helper: BaseViewHolder, item: SimpleRoomInfo) { + helper.setText(R.id.tv_room_title, item.nick.subAndReplaceDot(7)) + .setText(R.id.tv_room_id, "ID:${item.erbanNo}") + ImageLoadUtils.loadImage(mContext, item.avatar, helper.getView(R.id.iv_avatar)) + helper.addOnClickListener(R.id.iv_avatar, R.id.tv_select) + val tvSelect = helper.getView(R.id.tv_select) + tvSelect.isEnabled = !item.crossPking && item.valid + if (!item.valid) { + tvSelect.text = ResUtil.getString(R.string.offline) + tvSelect.setTextColor("#80C6C6E9".toColorInt()) + } else if (item.crossPking) { + tvSelect.text = tvSelect.context.getString(R.string.layout_item_home_tab_map_02) + tvSelect.setTextColor("#80C6C6E9".toColorInt()) + } else { + tvSelect.text = ResUtil.getString(R.string.select) + tvSelect.setTextColor(Color.WHITE) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPkFinishDialog.kt b/app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPkFinishDialog.kt new file mode 100644 index 0000000..bdd90da --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPkFinishDialog.kt @@ -0,0 +1,97 @@ +package com.chwl.app.avroom.singleroompk + +import android.annotation.SuppressLint +import android.os.Bundle +import android.view.WindowManager +import androidx.core.view.isVisible +import com.chwl.app.R +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.databinding.DialogSingleRoomPkFinishBinding +import com.chwl.app.ui.utils.load +import com.chwl.core.im.custom.bean.RoomPkBean +import com.chwl.core.utils.extension.subAndReplaceDot +import io.reactivex.Observable +import io.reactivex.android.schedulers.AndroidSchedulers +import java.util.concurrent.TimeUnit + +class SingleRoomPkFinishDialog : BaseDialogFragment() { + + companion object { + @JvmStatic + fun newInstance(pkBean: RoomPkBean): SingleRoomPkFinishDialog { + val args = Bundle() + args.putSerializable("RoomPkBean", pkBean) + val fragment = SingleRoomPkFinishDialog() + fragment.arguments = args + return fragment + } + } + + override var width = WindowManager.LayoutParams.MATCH_PARENT + + private val roomPkBean: RoomPkBean by lazy { requireArguments().getSerializable("RoomPkBean") as RoomPkBean } + + @SuppressLint("CheckResult", "SetTextI18n") + override fun init() { + binding?.tvClose?.setOnClickListener { dismissAllowingStateLoss() } + binding?.tvTitleRed?.text = roomPkBean.cNick.subAndReplaceDot(7) + binding?.tvValueRed?.text = "${roomPkBean.cAmount}" + binding?.ivAvatarRed?.load(roomPkBean.cAvatar, defaultRes = R.drawable.default_avatar) + + roomPkBean.csRank.getOrNull(0)?.let { + binding?.groupRank1?.isVisible = true + binding?.tvRankNick1?.text = it.nick.subAndReplaceDot(7) + binding?.tvRankValue1?.text = "PK值:${it.amount}" + binding?.ivAvatar1?.load(it.avatar, defaultRes = R.drawable.default_avatar) + } ?: run { + binding?.groupRank1?.isVisible = false + binding?.tvEmptyTip?.isVisible = true + } + + roomPkBean.csRank.getOrNull(1)?.let { + binding?.groupRank2?.isVisible = true + binding?.tvRankNick2?.text = it.nick.subAndReplaceDot(7) + binding?.tvRankValue2?.text = "PK值:${it.amount}" + binding?.ivAvatar2?.load(it.avatar, defaultRes = R.drawable.default_avatar) + } ?: run { + binding?.groupRank2?.isVisible = false + } + + roomPkBean.csRank.getOrNull(2)?.let { + binding?.groupRank3?.isVisible = true + binding?.tvRankNick3?.text = it.nick.subAndReplaceDot(7) + binding?.tvRankValue3?.text = "PK值:${it.amount}" + binding?.ivAvatar3?.load(it.avatar, defaultRes = R.drawable.default_avatar) + } ?: run { + binding?.groupRank3?.isVisible = false + } + + Observable.intervalRange(0, 6, 0, 1, TimeUnit.SECONDS) + .compose(bindToLifecycle()) + .observeOn(AndroidSchedulers.mainThread()) + .doOnComplete { dismissAllowingStateLoss() } + .subscribe { + binding?.tvClose?.text = "關閉(${5 - it})" + } + + when (roomPkBean.winUid) { + 0L -> { + binding?.viewBg?.setBackgroundResource(R.drawable.single_room_pk_bg_finish_deuce) + binding?.viewBgAvatar?.setBackgroundResource(R.drawable.single_room_pk_bg_finish_deuce_avatar) + binding?.tvContributeTitle?.setBackgroundResource(R.drawable.single_room_pk_bg_finish_deuce_contribute) + } + roomPkBean.cUid -> { + binding?.viewBg?.setBackgroundResource(R.drawable.single_room_pk_bg_finish_win) + binding?.viewBgAvatar?.setBackgroundResource(R.drawable.single_room_pk_bg_finish_win_avatar) + binding?.tvContributeTitle?.setBackgroundResource(R.drawable.single_room_pk_bg_finish_win_contribute) + } + else -> { + binding?.viewBg?.setBackgroundResource(R.drawable.single_room_pk_bg_finish_failed) + binding?.viewBgAvatar?.setBackgroundResource(R.drawable.single_room_pk_bg_finish_failed_avatar) + binding?.tvContributeTitle?.setBackgroundResource(R.drawable.single_room_pk_bg_finish_failed_contribute) + } + } + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPkForceFinishDialog.kt b/app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPkForceFinishDialog.kt new file mode 100644 index 0000000..3f707a1 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPkForceFinishDialog.kt @@ -0,0 +1,54 @@ +package com.chwl.app.avroom.singleroompk + +import android.annotation.SuppressLint +import android.os.Bundle +import android.view.WindowManager +import com.chwl.app.R +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.databinding.DialogSingleRoomPkForceFinishBinding +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.core.im.custom.bean.RoomPkBean +import com.chwl.core.utils.extension.subAndReplaceDot + +class SingleRoomPkForceFinishDialog : BaseDialogFragment() { + + companion object { + @JvmStatic + fun newInstance(pkBean: RoomPkBean): SingleRoomPkForceFinishDialog { + val args = Bundle() + args.putSerializable("RoomPkBean", pkBean) + val fragment = SingleRoomPkForceFinishDialog() + fragment.arguments = args + return fragment + } + } + + override var width = WindowManager.LayoutParams.MATCH_PARENT + + private val roomPkBean: RoomPkBean by lazy { requireArguments().getSerializable("RoomPkBean") as RoomPkBean } + + @SuppressLint("CheckResult", "SetTextI18n") + override fun init() { + binding?.ivClose?.setOnClickListener { dismissAllowingStateLoss() } + binding?.tvTitleRed?.text = roomPkBean.cNick.subAndReplaceDot(7) + binding?.tvValueRed?.text = "${roomPkBean.cAmount}" + ImageLoadUtils.loadImage( + context, + roomPkBean.cAvatar, + binding?.ivAvatarRed, + R.drawable.default_avatar + ) + + binding?.tvTitleBlue?.text = roomPkBean.aNick.subAndReplaceDot(7) + binding?.tvValueBlue?.text = "${roomPkBean.aAmount}" + + ImageLoadUtils.loadImage( + context, + roomPkBean.aAvatar, + binding?.ivAvatarBlue, + R.drawable.default_avatar + ) + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPkReceivedDialog.kt b/app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPkReceivedDialog.kt new file mode 100644 index 0000000..ba156d7 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPkReceivedDialog.kt @@ -0,0 +1,77 @@ +package com.chwl.app.avroom.singleroompk + +import android.annotation.SuppressLint +import android.os.Bundle +import androidx.core.view.isVisible +import com.chwl.app.R +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.databinding.DialogSingleRoomPkReceivedBinding +import com.chwl.core.im.custom.bean.RoomPkBean +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.room.anotherroompk.SingleRoomPKModel +import com.chwl.core.utils.extension.ifNotNullOrEmpty +import com.chwl.core.utils.extension.subAndReplaceDot +import com.chwl.core.utils.extension.toast +import io.reactivex.Observable +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import java.util.concurrent.TimeUnit + +class SingleRoomPkReceivedDialog : BaseDialogFragment() { + + companion object { + + @JvmStatic + fun newInstance(pkBean: RoomPkBean): SingleRoomPkReceivedDialog { + val args = Bundle() + args.putSerializable("RoomPkBean", pkBean) + val fragment = SingleRoomPkReceivedDialog() + fragment.arguments = args + return fragment + } + } + + private val pkBean: RoomPkBean by lazy { requireArguments().getSerializable("RoomPkBean") as RoomPkBean } + + private var disposable: Disposable? =null + + @SuppressLint("CheckResult") + override fun init() { + binding?.tvNick?.text = pkBean.inviteRoomTitle.subAndReplaceDot(7) + binding?.tvTime?.text = "${pkBean.pkDuration}${getString(R.string.layout_activity_room_pk_create_010)}" + pkBean.pkDesc.ifNotNullOrEmpty { + binding?.tvDescTitle?.isVisible = true + binding?.tvDesc?.isVisible = true + binding?.tvDesc?.text = it + } + disposable = Observable.intervalRange(0, 10, 0, 1, TimeUnit.SECONDS) + .compose(bindToLifecycle()) + .observeOn(AndroidSchedulers.mainThread()) + .doOnComplete { dismissAllowingStateLoss() } + .subscribe { + binding?.tvCloseTime?.text = "${10 - it}" + } + + binding?.tvReceived?.setOnClickListener { + commit(true) + } + + binding?.tvRefuse?.setOnClickListener { + commit(false) + } + } + + @SuppressLint("CheckResult") + private fun commit(accept: Boolean) { + disposable?.dispose() + SingleRoomPKModel.acceptRoomPK(accept, AvRoomDataManager.get().roomUid, pkBean.roundId) + .compose(bindToLifecycle()) + .subscribe({ + //"接受PK邀請成功".toast() + dismissAllowingStateLoss() + }, { + it.message.toast() + dismissAllowingStateLoss() + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPkRuleDialog.kt b/app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPkRuleDialog.kt new file mode 100644 index 0000000..6f3aefe --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/singleroompk/SingleRoomPkRuleDialog.kt @@ -0,0 +1,30 @@ +package com.chwl.app.avroom.singleroompk + +import android.text.method.ScrollingMovementMethod +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.databinding.DialogSingleRoomPkRuleBinding +import com.chwl.core.room.anotherroompk.SingleRoomPKModel +import com.chwl.core.utils.extension.toast + +class SingleRoomPkRuleDialog : BaseDialogFragment() { + + companion object { + + @JvmStatic + fun newInstance(): SingleRoomPkRuleDialog { + return SingleRoomPkRuleDialog() + } + } + + override fun init() { + binding?.ivClose?.setOnClickListener { dismissAllowingStateLoss() } + binding?.tvContent?.movementMethod = ScrollingMovementMethod.getInstance() + SingleRoomPKModel.getSingleRoomPkRule() + .compose(bindToLifecycle()) + .doOnSuccess { + binding?.tvContent?.text = it.replace("\\n", "\n").replace("\\r", "\r") + } + .doOnError { it?.message.toast() } + .subscribe() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/view/IAvRoomView.java b/app/src/main/java/com/chwl/app/avroom/view/IAvRoomView.java new file mode 100644 index 0000000..2699953 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/view/IAvRoomView.java @@ -0,0 +1,86 @@ +package com.chwl.app.avroom.view; + + +import com.chwl.core.channel_page.bean.HelloMessageInfo; +import com.chwl.core.gift.bean.GiftInfo; +import com.chwl.core.monsterhunting.bean.MonsterInfo; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.core.user.bean.FirstChargeInfo; +import com.chwl.library.base.IMvpBaseView; + +/** + *

+ * + * @author jiahui + * @date 2017/12/11 + */ +public interface IAvRoomView extends IMvpBaseView { + + void requestRoomInfoSuccessView(RoomInfo roomInfo); + + void requestRoomInfoFailView(Throwable throwable); + + /** + * 进去房间成功 + */ + void enterRoomSuccess(); + + /** + * 进入房间失败 + */ + void enterRoomFail(int code, String error); + + /** + * 显示结束直播界面 + */ + void showFinishRoomView(long uid); + + /** + * 显示黑名单进入房间错误页面 + */ + void showBlackEnterRoomView(); + + /** + * 显示新用户打招呼消息 + */ + void showHelloMessageDialog(HelloMessageInfo helloMessageInfo); + + /** + * 取消loading弹窗 + */ + void dismissLoadingDialog(); + + /** + * 退出房间 + * + * @param currentRoomInfo + */ + void exitRoom(RoomInfo currentRoomInfo); + + /** + * 定时拉取人数成功 + * + * @param onlineNumber + */ + void onRoomOnlineNumberSuccess(int onlineNumber); + + /** + * 成功获取怪兽信息 + * @param monsterInfo + */ + void getMonsterInfoSuccess(MonsterInfo monsterInfo); + + /** + * 获取怪兽信息失败 + * @param error + */ + void getMonsterInfoFail(String error); + + /** + * 恢复最小化的时候 处理青少年时长限制 + * @param throwable - + */ + void recoverRoomMinWhenPmLimit(Throwable throwable); + + void showNewUserDialog(GiftInfo giftInfo); +} diff --git a/app/src/main/java/com/chwl/app/avroom/view/IBaseRoomView.kt b/app/src/main/java/com/chwl/app/avroom/view/IBaseRoomView.kt new file mode 100644 index 0000000..ca3bd78 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/view/IBaseRoomView.kt @@ -0,0 +1,76 @@ +package com.chwl.app.avroom.view + +import com.chwl.core.bean.RoomMicInfo +import com.chwl.core.room.bean.RoomContributeUserInfo +import com.chwl.library.base.IMvpBaseView +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage + +/** + * + * 轰趴房View层 + * + * @author jiahui + * @date 2017/12/8 + */ +interface IBaseRoomView : IMvpBaseView { + /** + * 被踢下麦成功 + */ + fun kickDownMicroPhoneSuccess() + + /** + * 麦上没人点击坑位处理 + * + * @param roomMicInfo 坑位信息 + * @param micPosition + * @param currentUid + */ + fun showOwnerClickDialog(roomMicInfo: RoomMicInfo, micPosition: Int, currentUid: Long) + + /** + * 断网重连回调 + */ + fun chatRoomReConnectView() + fun showToast(msg: String?) + fun onSendMsgSuccess(msg: String?) + fun onSendPublicChatMsgSuccess(msg: ChatRoomMessage) + + /** + * 上麦请求 + * + * @param micPosition + * @param currentUid + * @param b + */ + fun toUpMicroPhone(micPosition: Int, currentUid: String, b: Boolean) + + /** + * 没有关注用户的监听 + */ + fun noFollow() + + /** + * 没有关注用户的监听 + */ + fun showAttentionDialog() + + /** + * 鬼知道之前有一个,现在又要加一个 + */ + fun noFollow2() + + /** + * 关注成功 + * @param position + */ + fun onFollowSuccess(position: Int) + + /** + * 关注失败 + * @param msg + */ + fun onFollowFail(msg: String?) + + fun updateMicView() + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/view/ICreatePKView.java b/app/src/main/java/com/chwl/app/avroom/view/ICreatePKView.java new file mode 100644 index 0000000..ff3167c --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/view/ICreatePKView.java @@ -0,0 +1,11 @@ +package com.chwl.app.avroom.view; + +import com.chwl.library.base.IMvpBaseView; + +/** + * @author jack + * @Description + * @Date 2018/12/28 + */ +public interface ICreatePKView extends IMvpBaseView { +} diff --git a/app/src/main/java/com/chwl/app/avroom/view/IGameRoomView.java b/app/src/main/java/com/chwl/app/avroom/view/IGameRoomView.java new file mode 100644 index 0000000..f5f1f64 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/view/IGameRoomView.java @@ -0,0 +1,17 @@ +package com.chwl.app.avroom.view; + +import com.chwl.core.home.bean.BannerInfo; + +import java.util.List; + +/** + *

轰趴房View层

+ * + * @author jiahui + * @date 2017/12/8 + */ +public interface IGameRoomView extends IBaseRoomView { + +// void onShowBanner(List dialogInfos); + +} diff --git a/app/src/main/java/com/chwl/app/avroom/view/IHomePartyUserListView.java b/app/src/main/java/com/chwl/app/avroom/view/IHomePartyUserListView.java new file mode 100644 index 0000000..52cb657 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/view/IHomePartyUserListView.java @@ -0,0 +1,22 @@ +package com.chwl.app.avroom.view; + + + +import com.chwl.core.room.bean.RoomOnlineUserBean; +import com.chwl.library.base.IMvpBaseView; + +import java.util.List; + +/** + *

+ * + * @author jiahui + * @date 2017/12/8 + */ +public interface IHomePartyUserListView extends IMvpBaseView { + void onRequestRoomOnlineListSuccess(List memberList); + + void onRequestChatMemberByPageFail(String errorStr, int page); + + void onMemberInRefresh(); +} diff --git a/app/src/main/java/com/chwl/app/avroom/view/IHomePartyView.java b/app/src/main/java/com/chwl/app/avroom/view/IHomePartyView.java new file mode 100644 index 0000000..3864fd9 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/view/IHomePartyView.java @@ -0,0 +1,22 @@ +package com.chwl.app.avroom.view; + +import com.chwl.core.room.bean.RoomInfo; + + +/** + *

轰趴房View层

+ * + * @author jiahui + * @date 2017/12/8 + */ +public interface IHomePartyView extends IBaseRoomView { + + //玩龙珠时换坑 + void onDragonBarChangeMic(int micPosition, String uId, boolean isInviteUpMic, RoomInfo roomInfo); + + /** + * 礼物值模式下换麦 + */ + void onGiftValueChangeMic(int micPosition, String uId, boolean isInviteUpMic, RoomInfo roomInfo); + +} diff --git a/app/src/main/java/com/chwl/app/avroom/view/ILightChatConsumeView.java b/app/src/main/java/com/chwl/app/avroom/view/ILightChatConsumeView.java new file mode 100644 index 0000000..f74fd60 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/view/ILightChatConsumeView.java @@ -0,0 +1,21 @@ +package com.chwl.app.avroom.view; + + + +import com.chwl.core.room.queue.bean.RoomConsumeInfo; +import com.chwl.library.base.IMvpBaseView; + +import java.util.List; + +/** + *

+ * + * @author jiahui + * @date 2017/12/24 + */ +public interface ILightChatConsumeView extends IMvpBaseView { + + void onGetRoomConsumeListSuccess(List roomConsumeInfos); + + void onGetRoomConsumeListFail(String error); +} diff --git a/app/src/main/java/com/chwl/app/avroom/view/ILightChatOnlineView.java b/app/src/main/java/com/chwl/app/avroom/view/ILightChatOnlineView.java new file mode 100644 index 0000000..86b5a68 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/view/ILightChatOnlineView.java @@ -0,0 +1,40 @@ +package com.chwl.app.avroom.view; + +import android.util.SparseArray; + +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMember; +import com.chwl.app.ui.widget.ButtonItem; + +import java.util.List; + +/** + *

+ * + * @author jiahui + * @date 2017/12/25 + */ +public interface ILightChatOnlineView extends IHomePartyUserListView { + /** + * 获取按钮相关操作集合 + * + * @param chatRoomMember 操作当前的成员 + * @param position 麦序 + * @return + */ + SparseArray getButtonItemList(ChatRoomMember chatRoomMember, int position); + + /** + * 显示列表点击对话框 + * + * @param buttonItemList + */ + void showItemClickDialog(List buttonItemList); + + /** + * 显示用户信息对话框 + * + * @param account + */ + void showUserInfoDialog(String account); + +} diff --git a/app/src/main/java/com/chwl/app/avroom/view/ILightChatRoomView.java b/app/src/main/java/com/chwl/app/avroom/view/ILightChatRoomView.java new file mode 100644 index 0000000..8064312 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/view/ILightChatRoomView.java @@ -0,0 +1,32 @@ +package com.chwl.app.avroom.view; + + +import com.chwl.library.base.IMvpBaseView; + +/** + *

轻聊房

+ * + * @author jiahui + * @date 2017/12/24 + */ +public interface ILightChatRoomView extends IMvpBaseView { + /** + * 赞操作成功 + * + * @param type type:喜欢操作类型,1是喜欢,2是取消喜欢,必填 + * @param likedUid 被点赞人uid,必填 + */ + void praiseSuccess(int type, long likedUid); + + /** + * 赞操作失败 + * + * @param type type:喜欢操作类型,1是喜欢,2是取消喜欢,必填 + * @param likedUid 被点赞人uid,必填 + */ + void praiseFail(int type, long likedUid); + + /** 被踢下麦成功 */ + void kickDownMicroPhoneSuccess(); + +} diff --git a/app/src/main/java/com/chwl/app/avroom/view/IRecordForPKView.java b/app/src/main/java/com/chwl/app/avroom/view/IRecordForPKView.java new file mode 100644 index 0000000..d5a5ef8 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/view/IRecordForPKView.java @@ -0,0 +1,12 @@ +package com.chwl.app.avroom.view; + +import com.chwl.library.base.IMvpBaseView; + +/** + * @author jack + * @Description + * @Date 2018/12/29 + */ +public interface IRecordForPKView extends IMvpBaseView { + +} diff --git a/app/src/main/java/com/chwl/app/avroom/view/IRoomBlackView.java b/app/src/main/java/com/chwl/app/avroom/view/IRoomBlackView.java new file mode 100644 index 0000000..e821233 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/view/IRoomBlackView.java @@ -0,0 +1,43 @@ +package com.chwl.app.avroom.view; + +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMember; +import com.chwl.library.base.IMvpBaseView; + +import java.util.List; + +/** + *

+ * + * @author jiahui + * @date 2017/12/19 + */ +public interface IRoomBlackView extends IMvpBaseView { + /** + * 获取黑名单列表成功 + * + * @param chatRoomMemberList + */ + void queryBlackListSuccess(List chatRoomMemberList); + + /** + * 获取黑名单列表失败 + */ + void queryBlackListFail(); + + /** + * 拉黑操作成功 + * + * @param chatRoomMember + * @param mark true,拉黑,false:移除拉黑 + */ + void makeBlackListSuccess(ChatRoomMember chatRoomMember, boolean mark); + + /** + * 拉黑操作失败 + * + * @param code + * @param error + * @param mark true,拉黑,false:移除拉黑 + */ + void makeBlackListFail(int code, String error, boolean mark); +} diff --git a/app/src/main/java/com/chwl/app/avroom/view/IRoomCharmRankingListView.java b/app/src/main/java/com/chwl/app/avroom/view/IRoomCharmRankingListView.java new file mode 100644 index 0000000..69d262e --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/view/IRoomCharmRankingListView.java @@ -0,0 +1,12 @@ +package com.chwl.app.avroom.view; + +import com.chwl.core.room.bean.RoomRankMultiItem; +import com.chwl.library.base.IMvpBaseView; + +import java.util.List; + +public interface IRoomCharmRankingListView extends IMvpBaseView { + + void roomCharmListSuccess(List list); + void roomCharListFail(String message); +} diff --git a/app/src/main/java/com/chwl/app/avroom/view/IRoomContributeListView.java b/app/src/main/java/com/chwl/app/avroom/view/IRoomContributeListView.java new file mode 100644 index 0000000..1e0cab4 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/view/IRoomContributeListView.java @@ -0,0 +1,16 @@ +package com.chwl.app.avroom.view; + + +import com.chwl.core.room.bean.RoomContributeDataInfo; +import com.chwl.library.base.IMvpBaseView; + +/** + * Created by MadisonRong on 25/04/2018. + */ + +public interface IRoomContributeListView extends IMvpBaseView { + + void getSingleRankingSuccess(RoomContributeDataInfo roomContributeDataInfo); + + void getSingleRakingFail(int errorCode, String errorMsg); +} diff --git a/app/src/main/java/com/chwl/app/avroom/view/IRoomInviteView.java b/app/src/main/java/com/chwl/app/avroom/view/IRoomInviteView.java new file mode 100644 index 0000000..f53cb5d --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/view/IRoomInviteView.java @@ -0,0 +1,17 @@ +package com.chwl.app.avroom.view; + +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMember; + +import java.util.List; + +/** + *

+ * + * @author jiahui + * @date 2017/12/21 + */ +public interface IRoomInviteView extends IHomePartyUserListView { + + void onRequestMemberByPageSuccess(List memberList, int page); + +} diff --git a/app/src/main/java/com/chwl/app/avroom/view/IRoomManagerView.java b/app/src/main/java/com/chwl/app/avroom/view/IRoomManagerView.java new file mode 100644 index 0000000..0d053a3 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/view/IRoomManagerView.java @@ -0,0 +1,20 @@ +package com.chwl.app.avroom.view; + +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMember; + +import java.util.List; + +/** + *

+ * + * @author jiahui + * @date 2017/12/19 + */ +public interface IRoomManagerView extends IRoomMemberView { + + void queryManagerListSuccess(List chatRoomMemberList); + + void queryManagerListFail(); + + +} diff --git a/app/src/main/java/com/chwl/app/avroom/view/IRoomMemberView.java b/app/src/main/java/com/chwl/app/avroom/view/IRoomMemberView.java new file mode 100644 index 0000000..6eb0c43 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/view/IRoomMemberView.java @@ -0,0 +1,29 @@ +package com.chwl.app.avroom.view; + +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMember; +import com.chwl.library.base.IMvpBaseView; + + +/** + *

+ * + * @author jiahui + * @date 2017/12/19 + */ +public interface IRoomMemberView extends IMvpBaseView { + /** + * 设置管理员成功 + * + * @param chatRoomMember + */ + void markManagerListSuccess(ChatRoomMember chatRoomMember); + + /** + * 设置管理员失败 + * + * @param code + * @param error + */ + void markManagerListFail(int code, String error); + +} diff --git a/app/src/main/java/com/chwl/app/avroom/view/IRoomSettingView.java b/app/src/main/java/com/chwl/app/avroom/view/IRoomSettingView.java new file mode 100644 index 0000000..350310a --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/view/IRoomSettingView.java @@ -0,0 +1,42 @@ +package com.chwl.app.avroom.view; + +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.core.room.bean.RoomSettingTabInfo; +import com.chwl.core.room.bean.SingleRoomSortInfo; +import com.chwl.library.base.IMvpBaseView; + +import java.util.List; + +/** + *

+ * + * @author jiahui + * @date 2017/12/15 + */ +public interface IRoomSettingView extends IMvpBaseView { + + void onResultRequestTagAllSuccess(List tabInfoList); + + void onResultRequestTagAllFail(String error); + + void onResultRequestSingleRoomSortSuccess(List tabInfoList); + + void onResultRequestSingleRoomSortFail(String error); + + void reQuestRoomInfo(RoomInfo roomInfo); + + void onSuccessToFinish(); + + void onFailToToast(String error); + + /** + * 更新房间纯净模式时使用 + */ + void onUpdateRoomPureMode(RoomInfo roomInfo); + + // 离开模式 + void leaveModeOpenSuccess(); + void leaveModeOpenFail(String msg); + void leaveModeCloseSuccess(); + void leaveModeCloseFail(String msg); +} diff --git a/app/src/main/java/com/chwl/app/avroom/view/ISingleRoomView.java b/app/src/main/java/com/chwl/app/avroom/view/ISingleRoomView.java new file mode 100644 index 0000000..0b650a4 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/view/ISingleRoomView.java @@ -0,0 +1,13 @@ +package com.chwl.app.avroom.view; + + + +/** + *

轰趴房View层

+ * + * @author jiahui + * @date 2017/12/8 + */ +public interface ISingleRoomView extends IBaseRoomView { + +} diff --git a/app/src/main/java/com/chwl/app/avroom/widget/ActivityTimerView.java b/app/src/main/java/com/chwl/app/avroom/widget/ActivityTimerView.java new file mode 100644 index 0000000..2003499 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/widget/ActivityTimerView.java @@ -0,0 +1,79 @@ +package com.chwl.app.avroom.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.Nullable; + +import com.chwl.app.R; +import com.chwl.core.room.activitytimer.TimerBean; +import com.chwl.library.utils.ResUtil; + +import java.util.concurrent.TimeUnit; + +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.schedulers.Schedulers; + +/** + * create by lvzebiao @2020/2/24 + */ +public class ActivityTimerView extends LinearLayout { + + private TextView tvTime; + + private Disposable disposable; + + private TimerBean lastTimerBean; + + public ActivityTimerView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + inflate(context, R.layout.view_activity_timer, this); + tvTime = findViewById(R.id.tv_time); + } + + public void start(TimerBean currTimerBean) { + //先判断两条消息时效 + if (lastTimerBean != null) { + if (currTimerBean.getRunawayTime() < lastTimerBean.getRunawayTime()) { + //说明新来的消息,实际上比上个消息还旧,则不读取,直接忽略 + return; + } + } + lastTimerBean = currTimerBean; + stop(); + long maxTime = currTimerBean.getLimitTime(); + setVisibility(GONE);//如果接口返回0,说明活动可能下架了,直接隐藏倒计时 + if (maxTime <= 1) { + return; + } + setVisibility(VISIBLE); + disposable = Observable.intervalRange(0, (maxTime + 1), 0, 1, TimeUnit.SECONDS) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .doOnNext(aLong -> { + + tvTime.setText((maxTime - aLong) + ResUtil.getString(R.string.avroom_widget_activitytimerview_01)); + if (maxTime - aLong <= 0) { + setVisibility(GONE); + } + + }) + .subscribe(); + } + + private void stop() { + if (disposable != null) { + disposable.dispose(); + } + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + stop(); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/widget/BottomView.java b/app/src/main/java/com/chwl/app/avroom/widget/BottomView.java new file mode 100644 index 0000000..c0da1c8 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/widget/BottomView.java @@ -0,0 +1,594 @@ +package com.chwl.app.avroom.widget; + +import android.animation.Keyframe; +import android.animation.ObjectAnimator; +import android.animation.PropertyValuesHolder; +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Context; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.PopupWindow; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.chwl.app.R; +import com.chwl.app.avroom.BottomViewListenerWrapper; +import com.chwl.app.avroom.activity.RoomTypeSwitchActivity; +import com.chwl.app.room_chat.fragment.RoomMsgTabFragment; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.contacts.MyConstant; +import com.chwl.core.helper.ImHelperUtils; +import com.chwl.core.manager.AudioEngineManager; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.manager.IMMessageManager; +import com.chwl.core.pay.event.FirstChargeEvent; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.core.room.bean.RoomModeType; +import com.chwl.core.super_admin.util.SuperAdminUtil; +import com.chwl.core.utils.ComboUtil; +import com.chwl.core.utils.LogUtils; +import com.chwl.core.utils.SharedPreferenceUtils; +import com.chwl.core.utils.extension.StringExtensionKt; +import com.chwl.core.utils.myutil.MyUtil; +import com.chwl.library.utils.ListUtils; +import com.hjq.toast.ToastUtils; +import com.netease.nim.uikit.api.NimUIKit; +import com.netease.nim.uikit.common.util.sys.ScreenUtil; +import com.netease.nimlib.sdk.msg.model.RecentContact; +import com.netease.nimlib.sdk.uinfo.model.UserInfo; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.List; + +/** + * @author chenran + * @date 2017/7/26 + */ + +public class BottomView extends LinearLayout implements View.OnClickListener { + + /** + * 有新功能,加1 + */ + private static final int NEW_OPTION = 1; + private static final String SH_NEW_OPTION = "sh_new_option"; + private static final String NEW_OPTION_ROOM_TYPE = "new_option_room_type"; + + private BottomViewListenerWrapper wrapper; + private ImageView openMic; + private TextView sendMsgInput; + private ImageView sendGift; + private ImageView sendMagic; + private ImageView sendFace; + + private ImageView remoteMute; + private LinearLayout faceLayout; + private LinearLayout micLayout; + private ImageView iconMicQueue; + private ImageView iconRoomMsg; + + + @Nullable + private PopupWindow msgTipPopupWindow; + private PopupWindow micSetPopupWindow; + + private int bottomHeight; + private int micSetHeight; + @NonNull + private final Runnable msgRunnable = this::dismissMsgPopupWindow; + + public BottomView(Context context) { + super(context); + init(); + } + + public BottomView(Context context, AttributeSet attr) { + super(context, attr); + init(); + } + + public BottomView(Context context, AttributeSet attr, int i) { + super(context, attr, i); + init(); + } + + @SuppressLint("CheckResult") + private void init() { + inflate(getContext(), R.layout.layout_bottom_view, this); + openMic = findViewById(R.id.icon_room_open_mic); + sendMsgInput = findViewById(R.id.tv_room_send_msg_input); + sendFace = findViewById(R.id.icon_room_face); + sendGift = findViewById(R.id.icon_room_send_gift); + sendMagic = findViewById(R.id.icon_room_send_magic); + remoteMute = findViewById(R.id.icon_room_open_remote_mic); + faceLayout = findViewById(R.id.room_face_layout); + micLayout = findViewById(R.id.room_mic_layout); + + iconMicQueue = (ImageView) findViewById(R.id.icon_mic_queue); + + iconRoomMsg = findViewById(R.id.iv_room_message); + openMic.setOnClickListener(this); + sendMsgInput.setOnClickListener(this); + sendFace.setOnClickListener(this); + sendGift.setOnClickListener(this); + remoteMute.setOnClickListener(this); + sendMagic.setOnClickListener(this); + iconMicQueue.setOnClickListener(this); +// iconRoomMsg.setOnClickListener(this); + iconRoomMsg.setOnTouchListener(new OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + if (MyUtil.INSTANCE.isDoubleClick()) return false; + RoomMsgTabFragment.Companion.newInstance(null).show(v.getContext()); + } + return false; + } + }); + + setMicBtnEnable(false); + setMicBtnOpen(false); + updateQueuingMicButton(); + setRoomMessageUnread(IMMessageManager.get().queryUnreadMsg()); + + if (SuperAdminUtil.isSuperAdmin()) { + sendGift.setVisibility(GONE); + sendMsgInput.setVisibility(GONE); + } + + iconRoomMsg.post(() -> { + bottomHeight = iconRoomMsg.getHeight(); + View view = LayoutInflater.from(getContext()).inflate(R.layout.popup_mic_set, null); + view.setVisibility(View.INVISIBLE); + ViewGroup parent = (ViewGroup) this.getParent(); + parent.addView(view); + view.post(() -> { + micSetHeight = view.getHeight(); + try { + parent.removeView(view); + }catch (Exception e){ + + } + }); + }); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + EventBus.getDefault().register(this); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + dismissMsgPopupWindow(); + iconRoomMsg.removeCallbacks(msgRunnable); + EventBus.getDefault().unregister(this); + } + + /** + * 轻聊房没有魔法礼物 + * + * @param enable 允许与否 + */ + public void setMagicBtnEnable(boolean enable) { + if (enable) { + sendMagic.setVisibility(VISIBLE); + int newOption = (int) SharedPreferenceUtils.get(SH_NEW_OPTION, 0); + + if (newOption == NEW_OPTION) { + sendMagic.setImageResource(R.drawable.room_menu_ic_more); + if (isRemindOptionForRoomType()) { + sendMagic.setImageResource(R.drawable.room_menu_ic_more_new); + } + } else { + sendMagic.setImageResource(R.drawable.room_menu_ic_more_new); + } + sendMagic.setClickable(true); + sendMagic.setOnClickListener(this); + } else { + sendMagic.setClickable(false); + sendMagic.setOnClickListener(null); + sendMagic.setVisibility(GONE); + } + } + + private boolean isRemindOptionForRoomType() { + boolean isReminded = (boolean) SharedPreferenceUtils.get(NEW_OPTION_ROOM_TYPE, false); + if (isReminded) { + return false; + } + if (RoomTypeSwitchActivity.Companion.isCanSwitch()) { + return true; + } + return false; + } + + private boolean updateOptionForRoomType() { + boolean isReminded = (boolean) SharedPreferenceUtils.get(NEW_OPTION_ROOM_TYPE, false); + if (isReminded) { + return false; + } + if (RoomTypeSwitchActivity.Companion.isCanSwitch()) { + SharedPreferenceUtils.put(NEW_OPTION_ROOM_TYPE, true); + return true; + } + return false; + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onReceiveRecentContactChanged(List imMessages) { + setRoomMessageUnread(IMMessageManager.get().queryUnreadMsg()); + if (!ListUtils.isListEmpty(imMessages)) { + iconRoomMsg.post(() -> showMsgPopup(iconRoomMsg, imMessages.get(0))); + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onFirstRechargeEvent(FirstChargeEvent event) { +// sendGift.setImageResource(R.drawable.icon_room_send_gift); + } + + public void setRoomMessageUnread(int count) { + iconRoomMsg.setImageResource(count > 0 ? R.drawable.room_menu_ic_message_new : R.drawable.room_menu_ic_message); + } + + public void setBottomViewListener(BottomViewListenerWrapper wrapper) { + this.wrapper = wrapper; + } + + public void setMicBtnEnable(boolean enable) { + if (enable) { + openMic.setClickable(true); + openMic.setOnClickListener(this); + } else { + openMic.setClickable(false); + openMic.setOnClickListener(null); + } + } + + public void setMicBtnOpen(boolean isOpen) { + if(openMic == null){ + return; + } + +// if (isOpen) { +// openMic.setImageResource(R.drawable.room_menu_ic_mic_open); +// } else { +// openMic.setImageResource(R.drawable.room_menu_ic_mic_close); +// } + + if (isOpen) { + if (AudioEngineManager.get().isNotRecord()) { + openMic.setImageResource(R.drawable.room_menu_ic_mic_music); + } else { + openMic.setImageResource(R.drawable.room_menu_ic_mic_open); + } + } else { + openMic.setImageResource(R.drawable.room_menu_ic_mic_close); + } + +// +// RoomInfo currentRoomInfo = AvRoomDataManager.get().mCurrentRoomInfo; +// if (currentRoomInfo != null) { +// openMic.setEnabled(true); +// if(!AudioEngineManager.get().isMute()){ +// if (AudioEngineManager.get().isNotRecord()) { +// openMic.setImageResource(R.drawable.room_menu_ic_mic_music); +// } else { +// openMic.setImageResource(R.drawable.room_menu_ic_mic_open); +// } +// }else{ +// openMic.setImageResource(R.drawable.room_menu_ic_mic_close); +// } +// } else { +// openMic.setEnabled(false); +// openMic.setImageResource(R.drawable.room_menu_ic_mic_close); +// } + + + } + + public void setRemoteMuteOpen(boolean isOpen) { + if (isOpen) { + remoteMute.setImageResource(R.drawable.room_menu_ic_vocality_open); + } else { + remoteMute.setImageResource(R.drawable.room_menu_ic_vocality_close); + } + } + + + public void notifyStateChanged() { + setMagicBtnEnable(true); + } + + public void showHomePartyUpMicBottom() { + faceLayout.setVisibility(VISIBLE); + micLayout.setVisibility(VISIBLE); + } + + public void updateGameEntrance() { + // game btn pk按钮,游戏按钮 显示控制 +// if (AvRoomDataManager.get().isManager() || SuperAdminUtil.isSuperAdmin()) { +// if (!AvRoomDataManager.get().isCpRoom()) { +// pkGameView.setVisibility(VISIBLE); +// iconRoomBaiShunGame.setVisibility(VISIBLE); +// } +// } else { +// pkGameView.setVisibility(GONE); +// iconRoomBaiShunGame.setVisibility(GONE); +// } +// if (AvRoomDataManager.get().isSingleRoom() || AvRoomDataManager.get().isDatingMode()) { +// pkGameView.setVisibility(GONE); +// } + + } + + public void showHomePartyDownMicBottom() { + faceLayout.setVisibility(GONE); + micLayout.setVisibility(GONE); + } + + public void showLightChatUpMicBottom() { + faceLayout.setVisibility(GONE); + micLayout.setVisibility(VISIBLE); + } + + public void showLightChatDownMicBottom() { + faceLayout.setVisibility(GONE); + micLayout.setVisibility(GONE); + } + + /** + * PK模式、相亲模式的管理员,排麦模式的所有人,展示排麦按钮 + * PK模式、相亲模式的普通用户入口展示在BottomView右上方 + */ + + public void updateQueuingMicButton() { + if (SuperAdminUtil.isSuperAdmin()) { + iconMicQueue.setVisibility(GONE); + return; + } + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) return; + boolean show = ( + AvRoomDataManager.get().isQueuingMicro() || AvRoomDataManager.get().isOpenPKMode()) + && !AvRoomDataManager.get().isCpRoom() + && (AvRoomDataManager.get().isManager() || roomInfo.getRoomModeType() == RoomModeType.OPEN_MICRO_MODE); + iconMicQueue.setVisibility(show ? VISIBLE : GONE); + } + + public void setQueuingMicButtonBackground(boolean isEmpty) { + iconMicQueue.setImageResource(isEmpty ? R.drawable.room_menu_ic_mic_queue : + R.drawable.room_menu_ic_mic_queue_new); + } + + + public void showKtvBottom(boolean isShow) { + + } + + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.icon_room_open_mic: + showMicSetDialog(openMic); + break; + + case R.id.tv_room_send_msg_input: + if (wrapper != null) { + wrapper.onSendMsgBtnClick(); + } + break; + case R.id.icon_room_send_gift: + if (wrapper != null) { + wrapper.onSendGiftBtnClick(); + } + break; + case R.id.icon_room_face: + if (wrapper != null) { + wrapper.onSendFaceBtnClick(); + } + break; + + case R.id.icon_room_open_remote_mic: + if (wrapper != null) { + wrapper.onRemoteMuteBtnClick(); + } + break; + case R.id.icon_room_send_magic: + int newOption = (int) SharedPreferenceUtils.get(SH_NEW_OPTION, 0); + if (newOption != NEW_OPTION) { + SharedPreferenceUtils.put(SH_NEW_OPTION, NEW_OPTION); + setMagicBtnEnable(true); + } + if (updateOptionForRoomType()) { + setMagicBtnEnable(true); + } + + if (wrapper != null) { + wrapper.onMoreBtnClick(); + } + break; + case R.id.icon_mic_queue: + case R.id.iv_queuing_micro://注意这里是在HomePartyRoomFragment调用的 + if (wrapper != null) { + wrapper.onMicQueueClick(); + } + break; + case R.id.iv_room_message: + if (wrapper != null) { + wrapper.onRoomMessageClick(); + } + break; +// case R.id.icon_room_PK_game: +// if (wrapper != null) { +// wrapper.onRoomGameplayClick(true); +// } +// break; +// case R.id.icon_room_baishun_game: +// if (wrapper != null) { +// wrapper.onRoomGameplayClick(false); +// } +// break; + default: + break; + } + } + + public void showInputOrIcon(boolean isIcon) { + if (SuperAdminUtil.isSuperAdmin()) { + return; + } + sendMsgInput.setVisibility(VISIBLE); + } + + private void dismissMsgPopupWindow() { + if (msgTipPopupWindow != null) { + try { + msgTipPopupWindow.dismiss(); + } catch (Exception e) { + e.printStackTrace(); + } + msgTipPopupWindow = null; + } + } + + private void showMsgPopup(View parent, RecentContact recentContact) { + if (parent == null || recentContact == null || recentContact.getUnreadCount() == 0 || !isAttachedToWindow()) + return; + if (getContext() instanceof Activity && ((Activity) getContext()).isFinishing()) return; + + UserInfo userInfo = NimUIKit.getUserInfoProvider().getUserInfo(recentContact.getFromAccount()); + if (userInfo == null) return; + + parent.removeCallbacks(msgRunnable); + View contentView; + if (msgTipPopupWindow == null) { + contentView = LayoutInflater.from(getContext()).inflate(R.layout.popup_message_tip, null); + msgTipPopupWindow = new PopupWindow(contentView, ScreenUtil.dip2px(90), ScreenUtil.dip2px(55)); + msgTipPopupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); + msgTipPopupWindow.setAnimationStyle(R.style.style_anim_message_tip); + } else { + contentView = msgTipPopupWindow.getContentView(); + View clContent = contentView.findViewById(R.id.cl_content); + + Keyframe kx0 = Keyframe.ofFloat(0f, 0); + Keyframe kx1 = Keyframe.ofFloat(0.5f, ScreenUtil.dip2px(54)); + Keyframe kx2 = Keyframe.ofFloat(0.5f, -ScreenUtil.dip2px(54)); + Keyframe kx3 = Keyframe.ofFloat(1f, 0); + + Keyframe ka0 = Keyframe.ofFloat(0f, 1f); + Keyframe ka1 = Keyframe.ofFloat(0.5f, 0f); + Keyframe ka2 = Keyframe.ofFloat(1f, 1f); + + PropertyValuesHolder p0 = PropertyValuesHolder.ofKeyframe("translationX", kx0, kx1, kx2, kx3); + PropertyValuesHolder p4 = PropertyValuesHolder.ofKeyframe("alpha", ka0, ka1, ka2); + ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(clContent, p0, p4); + objectAnimator.setDuration(200); + objectAnimator.start(); + } + ImageView ivAvatar = contentView.findViewById(R.id.iv_avatar); + TextView tvNickname = contentView.findViewById(R.id.tv_nickname); + TextView tvContent = contentView.findViewById(R.id.tv_content); + ImageLoadUtils.loadAvatar(userInfo.getAvatar(), ivAvatar); + tvNickname.setText(StringExtensionKt.subAndReplaceDot(userInfo.getName(), 4)); + tvContent.setText(ImHelperUtils.getMsgDigest(recentContact)); + + contentView.setOnClickListener(v -> { + if (ComboUtil.INSTANCE.isChangePoint()) { + return; + } + RoomMsgTabFragment.Companion.newInstance(recentContact.getFromAccount()).show(getContext()); + }); + int[] vLoc = new int[2]; + parent.getLocationInWindow(vLoc); + try { + msgTipPopupWindow.showAtLocation( + parent, + Gravity.START | Gravity.TOP, + vLoc[0] - ScreenUtil.dip2px(30),//(90-30)/2 + vLoc[1] - ScreenUtil.dip2px(60)//55+5 + ); + } catch (Exception e) { + e.printStackTrace(); + } + + parent.postDelayed(msgRunnable, 3000); + } + + + private void showMicSetDialog(View parent){ + //xxx 关麦开麦 + View contentView; + if (micSetPopupWindow == null) { + contentView = LayoutInflater.from(getContext()).inflate(R.layout.popup_mic_set, null); + micSetPopupWindow = new PopupWindow(contentView, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + micSetPopupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); + micSetPopupWindow.setOutsideTouchable(true); +// micSetPopupWindow.setTouchable(true); +// micSetPopupWindow.setFocusable(false); +// micSetPopupWindow.setAnimationStyle(R.style.style_anim_mic_set); + } else { + if (micSetPopupWindow.isShowing()) return; + contentView = micSetPopupWindow.getContentView(); + } + contentView.post(() -> { + LogUtils.d("height = "+contentView.getHeight()); + }); + + ImageView micOff = contentView.findViewById(R.id.micOff); + ImageView micMusic = contentView.findViewById(R.id.micMusic); + ImageView micOn = contentView.findViewById(R.id.micOn); + + micOn.setOnClickListener(v -> { + micSetPopupWindow.dismiss(); + if (wrapper != null) { + ToastUtils.show(R.string.roomMicSetOpen); + wrapper.onOpenMicBtnClick(MyConstant.MicType.open); + } + }); + + micMusic.setOnClickListener(v -> { + micSetPopupWindow.dismiss(); + if (wrapper != null) { + ToastUtils.show(R.string.roomMicSetMusic); + wrapper.onOpenMicBtnClick(MyConstant.MicType.music); + } + }); + + micOff.setOnClickListener(v -> { + micSetPopupWindow.dismiss(); + if (wrapper != null) { + ToastUtils.show(R.string.roomMicSetClose); + wrapper.onOpenMicBtnClick(MyConstant.MicType.close); + } + }); + + + int[] vLoc = new int[2]; + parent.getLocationInWindow(vLoc); + try { + micSetPopupWindow.showAsDropDown(parent,0,-(bottomHeight+micSetHeight),Gravity.BOTTOM); + } catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/app/src/main/java/com/chwl/app/avroom/widget/BravoCoinView.kt b/app/src/main/java/com/chwl/app/avroom/widget/BravoCoinView.kt new file mode 100644 index 0000000..84aaa1f --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/widget/BravoCoinView.kt @@ -0,0 +1,154 @@ +package com.chwl.app.avroom.widget + +import android.animation.Animator +import android.animation.AnimatorSet +import android.animation.ObjectAnimator +import android.animation.PropertyValuesHolder +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.widget.FrameLayout +import com.chwl.app.databinding.ViewBravoCoinViewBinding +import com.chwl.app.utils.NumberUtils +import com.chwl.core.gift.bean.BravoGiftRewardBean +import com.chwl.core.user.event.BravoCoinAnimEvent +import com.chwl.library.common.util.formatToString +import com.chwl.library.common.util.isVerify +import com.chwl.library.common.util.postSafe +import com.chwl.library.common.util.setVis +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode +import java.util.LinkedList + +class BravoCoinView : FrameLayout { + + constructor(context: Context) : super(context) { + init(context) + } + + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { + init(context) + } + + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) { + init(context) + } + + private var mUid :Long?=null; + private val queue = LinkedList() + private lateinit var mViewBinding: ViewBravoCoinViewBinding + private var isPlaying = false + + + public fun setDataToLong(uid:Long?) { + mUid = uid + //此时清除队列 + if (uid == null) { + if (isAttachedToWindow) { + queue.clear() + this.clearAnimation() + this.setVis(false) + } + } + } + public fun setData(uid:String?) { + if (uid != null) { + try { + val toLongUid = uid.toLongOrNull() + setDataToLong(toLongUid) + } catch (e: Exception) { + setDataToLong(null) + } + } else { + setDataToLong(null) + } + } + + private fun init(context: Context) { + mViewBinding = ViewBravoCoinViewBinding.inflate(LayoutInflater.from(context),this,true) + EventBus.getDefault().register(this) + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onBravoCoinAnimEvent(event: BravoCoinAnimEvent?) { + if (event?.data != null && mUid != null) { + if (event.data.receiverUidList.contains(mUid)) { + queue.add(event.data) + showAnimation() + } + } + } + + + override fun onDetachedFromWindow() { + EventBus.getDefault().unregister(this) + if (isAttachedToWindow) { + this@BravoCoinView.clearAnimation() + this@BravoCoinView.setVis(false) + } + super.onDetachedFromWindow() + } + + fun showAnimation() { + + if (isPlaying || !queue.isVerify()) return + val data = queue.removeAt(0) + mViewBinding.coinAnim.text = "+${data.receiverProfit.formatToString()}" + NumberUtils + + // 透明度从0到1 + val fadeIn = ObjectAnimator.ofFloat(this@BravoCoinView, "alpha", 1f, 1f) + fadeIn.setDuration(1000) + + // 尺寸从0%到100% + val scaleUp = ObjectAnimator.ofPropertyValuesHolder( + this@BravoCoinView, + PropertyValuesHolder.ofFloat(SCALE_X, 0f, 1.2f, 1f), + PropertyValuesHolder.ofFloat(SCALE_Y, 0f, 1.2f, 1f) + ) + scaleUp.setDuration(1000) + + // 组合动画 + val appearSet = AnimatorSet() + appearSet.playTogether(fadeIn, scaleUp) + + // // 设置动画结束监听器 + appearSet.addListener(object : Animator.AnimatorListener { + override fun onAnimationStart(animation: Animator) { + this@BravoCoinView.postSafe { + this@BravoCoinView.setVis(true) + isPlaying = true + } + } + + override fun onAnimationEnd(animation: Animator) { + this@BravoCoinView.postSafe { + this@BravoCoinView.clearAnimation() + this@BravoCoinView.setVis(false) + mViewBinding.coinAnim.text = "" + isPlaying = false + showAnimation() + } + } + override fun onAnimationCancel(animation: Animator) { + this@BravoCoinView.postSafe { + this@BravoCoinView.clearAnimation() + this@BravoCoinView.setVis(false) + mViewBinding.coinAnim.text = "" + isPlaying = false + showAnimation() + } + } + override fun onAnimationRepeat(animation: Animator) { + } + }); + // 开始显示动画 + appearSet.start() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/widget/CoinTipsView.kt b/app/src/main/java/com/chwl/app/avroom/widget/CoinTipsView.kt new file mode 100644 index 0000000..138ead8 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/widget/CoinTipsView.kt @@ -0,0 +1,225 @@ +package com.chwl.app.avroom.widget + +import android.animation.Animator +import android.animation.AnimatorSet +import android.animation.ObjectAnimator +import android.animation.PropertyValuesHolder +import android.content.Context +import android.graphics.Typeface +import android.util.AttributeSet +import android.view.Gravity +import android.view.LayoutInflater +import android.view.ViewGroup +import android.view.animation.AccelerateDecelerateInterpolator +import android.widget.FrameLayout +import android.widget.TextView +import com.chwl.app.databinding.ViewCoinTipsBinding +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil +import com.chwl.core.gift.event.GiftComboEvent +import com.chwl.core.pay.PayModel +import com.chwl.library.common.util.formatToString +import com.chwl.library.common.util.setVis +import com.chwl.library.common.util.toColor +import com.example.lib_utils.ktx.dp +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode +import java.math.BigDecimal + +class CoinTipsView : FrameLayout { + + constructor(context: Context) : super(context){initView(context)} + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs){initView(context)} + + lateinit var mRootViewBinding : ViewCoinTipsBinding + var mCoin : Double?=null + + private fun initView(context: Context) { + mRootViewBinding = ViewCoinTipsBinding.inflate(LayoutInflater.from(context),this,true) + + mCoin = (PayModel.get().currentWalletInfo?.diamondNum ?: 0.0) + mRootViewBinding.price.text = mCoin?.formatToString() + } + + + /** + * true ,表示 接收金币变动广播,这时只展示扣除 + * false ,表示 接收中奖消息, 这时展示增加 + */ + fun showView(number: String?, isAdd: Boolean, isHeight:Boolean = false) { +// this@CoinTipsView.setVis(true) + + var textStr = setCoinText(number,isAdd) + + if (textStr == null) { + return + } + + val changNumText = createChangNum(textStr, isAdd) + + val yValue = if (isAdd) -UIUtil.dip2px(context, if (isHeight) 90.0 else 65.0).toFloat() else -UIUtil.dip2px(context, 40.0).toFloat() + //移动动画 + val translationY = ObjectAnimator.ofFloat(changNumText, "translationY", 0f, yValue).setDuration(200) + translationY.interpolator = AccelerateDecelerateInterpolator() + + + //透明动画 透明度从0到1 + val fadeIn = ObjectAnimator.ofFloat(changNumText, "alpha", 0.5f, 1f,1f,0f) + fadeIn.setDuration(2000) + + //爆炸动画 尺寸从0%到100% + val scaleUp: ObjectAnimator = ObjectAnimator.ofPropertyValuesHolder( + changNumText, + PropertyValuesHolder.ofFloat(SCALE_X, 1f, 1.3f, 1f), + PropertyValuesHolder.ofFloat(SCALE_Y, 1f, 1.3f, 1f) + ) + scaleUp.setDuration(1000) + + // 组合动画 + val appearSet = AnimatorSet() + appearSet.playTogether(fadeIn, translationY,scaleUp) + + appearSet.addListener(object : Animator.AnimatorListener { + override fun onAnimationStart(animation: Animator) { + changNumText.setVis(true) + } + override fun onAnimationEnd(animation: Animator) { + this@CoinTipsView.post(object : Runnable { + override fun run() { + this@CoinTipsView.removeView(changNumText) + } + }) + } + override fun onAnimationCancel(animation: Animator) { + } + override fun onAnimationRepeat(animation: Animator) { + } + }); + + appearSet.start() + +// translationY.addListener(object : AnimatorListenerAdapter() { +// override fun onAnimationStart(animation: Animator) { +// super.onAnimationStart(animation) +// changNumText.setVis(true) +// } +// override fun onAnimationEnd(animation: Animator) { +// super.onAnimationEnd(animation) +// this@CoinTipsView.postDelayed(object : Runnable { +// override fun run() { +// this@CoinTipsView.removeView(changNumText) +// } +// },2000) +// } +// }) +// translationY.start() + + + } + + /** + * number == null ,表示 接收金币变动广播,这时只展示扣除 + * number != null ,表示 接收中奖消息, 这时展示增加 + */ + private fun setCoinText(number: String?,isAdd: Boolean) : String? { + val newCoin = (PayModel.get().currentWalletInfo?.diamondNum ?: 0.0) + val oldCoin = if (mCoin != null ) mCoin else newCoin + + val total: BigDecimal = BigDecimal.valueOf(newCoin) + oldCoin?.let { + total.subtract(BigDecimal.valueOf(it)) + } + val num = total.toDouble() + + mRootViewBinding.price.text = newCoin.formatToString() + mCoin = newCoin + + var text = "" + if (number != null && isAdd) { + text = "+$number" + }else if (number != null && !isAdd) { + text = "-$number" + } else { + text = "$num" + if (num > 0 && isAdd) { + // isAdd = true ,表示 接收金币变动广播,这时只展示扣除, 返回空给外层 + return null; + } + } + + return text + } + + /** + * number == null ,表示 接收金币变动广播,这时只展示扣除 isAdd = true + * number != null ,表示 接收中奖消息, 这时展示增加 isAdd = false + */ + private fun createChangNum(str:String,isAdd:Boolean) : TextView{ +// + + val textView = TextView(context) + textView.setVis(false) + this.addView(textView,0) + + val lp = textView.layoutParams as FrameLayout.LayoutParams + lp.gravity = Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL + lp.width = ViewGroup.LayoutParams.WRAP_CONTENT + lp.height = 36.dp + textView.layoutParams = lp + + + textView.setTextColor( if (isAdd) "#BC36FF".toColor() else "#f8ce1f".toColor()) + textView.textSize = 22f + textView.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD)) + textView.text = str + + return textView + } + + fun plusCoin(num:Int) { + mCoin?.let { + val newCoin = num + it + mRootViewBinding.price.text = newCoin.formatToString() + } + } + + + +// @Subscribe(threadMode = ThreadMode.MAIN) +// fun onWalletInfoUpdate(event: UpdateWalletInfoEvent?) { +// showView(null) +// } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onGiftComboEvent(event: GiftComboEvent?) { + event?.let { + when (it.action) { + GiftComboEvent.Action.ACT_GIFT_COIN_TIPS -> { + showView(it.giftPrice.toString(),false) + } + } + } + } + + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + EventBus.getDefault().register(this) + } + + override fun onDetachedFromWindow() { + EventBus.getDefault().unregister(this) + super.onDetachedFromWindow() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/widget/EditRoomTitleDialog.java b/app/src/main/java/com/chwl/app/avroom/widget/EditRoomTitleDialog.java new file mode 100644 index 0000000..dee5646 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/widget/EditRoomTitleDialog.java @@ -0,0 +1,237 @@ +package com.chwl.app.avroom.widget; + +import android.content.Context; +import android.content.DialogInterface; +import android.os.Bundle; +import android.text.Editable; +import android.text.InputFilter; +import android.text.InputType; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.View; +import android.widget.EditText; +import android.widget.TextView; + +import androidx.appcompat.app.AppCompatDialog; + +import com.trello.rxlifecycle3.android.ActivityEvent; +import com.trello.rxlifecycle3.components.support.RxAppCompatActivity; +import com.chwl.app.R; +import com.chwl.app.utils.KeyBoardUtils; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; + +import java.util.concurrent.TimeUnit; + +import io.reactivex.Single; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.functions.Consumer; + + +/** + * 房间编辑dialog + * Created by huangmeng1 on 2018/8/14. + */ + +public class EditRoomTitleDialog extends AppCompatDialog { + /** + * 房间名字 + */ + public final static int TYPE_EDIT_NAME = 0; + /** + * 房间密码 + */ + public final static int TYPE_EDIT_PASSWORD = 1; + /** + * 房间描述 + */ + public final static int TYPE_EDIT_DESC = 2; + public final static int TYPE_EDIT_TEAM_NAME = 3; + public final static int TYPE_EDIT_TEAM_THEME = 4; + + private EditText etContent; + private TextView tvLimit; + private TextView tvTitle; + + private OnEditTitleListner onEditTitleListner; + + private OnCancelEditListner onCancelEditListner; + private Context context; + private String oldContent; + + + private int dialogType; + + private int maxLength = 0; + + public void setOnEditTitleListner(OnEditTitleListner onEditTitleListner) { + this.onEditTitleListner = onEditTitleListner; + } + + public void setOnCancelEditListner(OnCancelEditListner onCancelEditListner) { + this.onCancelEditListner = onCancelEditListner; + } + + public EditRoomTitleDialog(Context context, int dialogType, String oldContent) { + super(context, R.style.TranslucentNoTitle); + this.context = context; + this.dialogType = dialogType; + this.oldContent = oldContent; + } + + private String mCancelLabel; + public EditRoomTitleDialog(Context context, int dialogType, String oldContent, String cancelLabel) { + this(context, dialogType, oldContent); + this.mCancelLabel = cancelLabel; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.dialog_common_edit); + etContent = findViewById(R.id.et_content); + tvLimit = findViewById(R.id.tv_limit); + tvTitle = findViewById(R.id.tv_title); + + if (!TextUtils.isEmpty(oldContent)) { + etContent.setText(oldContent); + etContent.setSelection(oldContent.length()); + } + if (dialogType == TYPE_EDIT_PASSWORD) { + tvTitle.setText(ResUtil.getString(R.string.avroom_widget_editroomtitledialog_01)); + tvLimit.setVisibility(View.VISIBLE); + etContent.setInputType(InputType.TYPE_CLASS_NUMBER); + etContent.setHint(ResUtil.getString(R.string.avroom_widget_editroomtitledialog_02)); + maxLength = 8; + etContent.setFilters(new InputFilter[]{new InputFilter.LengthFilter(maxLength)}); + setLimtText(); + } else if (dialogType == TYPE_EDIT_NAME){ + tvTitle.setText(ResUtil.getString(R.string.avroom_widget_editroomtitledialog_03)); + tvLimit.setVisibility(View.VISIBLE); + etContent.setHint(ResUtil.getString(R.string.avroom_widget_editroomtitledialog_04)); + maxLength = 25; + etContent.setFilters(new InputFilter[]{new InputFilter.LengthFilter(maxLength)}); + setLimtText(); + } else if (dialogType == TYPE_EDIT_DESC) { + tvTitle.setText(ResUtil.getString(R.string.avroom_widget_editroomtitledialog_05)); + tvLimit.setVisibility(View.VISIBLE); + etContent.setHint(ResUtil.getString(R.string.avroom_widget_editroomtitledialog_06)); + maxLength = 15; + etContent.setFilters(new InputFilter[]{new InputFilter.LengthFilter(maxLength)}); + setLimtText(); + } else if (dialogType == TYPE_EDIT_TEAM_NAME) { + tvTitle.setText(ResUtil.getString(R.string.avroom_widget_editroomtitledialog_07)); + tvLimit.setVisibility(View.GONE); + etContent.setHint(ResUtil.getString(R.string.avroom_widget_editroomtitledialog_08)); + maxLength = 16; + etContent.setFilters(new InputFilter[]{new InputFilter.LengthFilter(maxLength)}); + setLimtText(); + + } else if (dialogType == TYPE_EDIT_TEAM_THEME) { + tvTitle.setText(ResUtil.getString(R.string.avroom_widget_editroomtitledialog_09)); + tvLimit.setVisibility(View.GONE); + etContent.setHint(ResUtil.getString(R.string.avroom_widget_editroomtitledialog_010)); + maxLength = 16; + etContent.setFilters(new InputFilter[]{new InputFilter.LengthFilter(maxLength)}); + setLimtText(); + + } + + TextView tvCancel = findViewById(R.id.btn_cancel); + if (!TextUtils.isEmpty(mCancelLabel)) + tvCancel.setText("" + mCancelLabel); + tvCancel.setOnClickListener(v -> { + dismiss(); + + if (onCancelEditListner != null) { + onCancelEditListner.onEditTeamThemeListener(); + } + }); + + findViewById(R.id.btn_ok).setOnClickListener(v -> { + if (TextUtils.isEmpty(etContent.getText().toString())){ + SingleToastUtil.showToast(ResUtil.getString(R.string.avroom_widget_editroomtitledialog_011)); + return; + } + if (onEditTitleListner != null) { + dismiss(); + if (dialogType == TYPE_EDIT_PASSWORD){ + onEditTitleListner.onEditPwdListner(etContent.getText().toString()); + } else if (dialogType == TYPE_EDIT_NAME){ + onEditTitleListner.onEditTitleListner(etContent.getText().toString()); + } else if (dialogType == TYPE_EDIT_DESC) { + onEditTitleListner.onEditDescLisner(etContent.getText().toString()); + } else if (dialogType == TYPE_EDIT_TEAM_NAME) { + onEditTitleListner.onEditTeamNameListener(etContent.getText().toString()); + } else if (dialogType == TYPE_EDIT_TEAM_THEME) { + onEditTitleListner.onEditTeamThemeListener(etContent.getText().toString()); + } + } + }); + etContent.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + tvLimit.setText(s.length() + "/" + maxLength); + } + + @Override + public void afterTextChanged(Editable s) { + + } + }); + setOnShowListener(new OnShowListener() { + @Override + public void onShow(DialogInterface dialog) { + etContent.requestFocus(); + etContent.setSelection(etContent.getText().toString().length()); + Single.timer(200, TimeUnit.MILLISECONDS) + .compose(((RxAppCompatActivity) context).bindUntilEvent(ActivityEvent.DESTROY)) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Consumer() { + @Override + public void accept(Long aLong) throws Exception { + KeyBoardUtils.showDialogSoftInput(getContext()); + } + }); + + } + }); + setOnDismissListener(new OnDismissListener() { + @Override + public void onDismiss(DialogInterface dialog) { + KeyBoardUtils.hideDialogSoftInput(context); + } + }); + } + + public static abstract class OnEditTitleListner { + public void onEditTitleListner(String title) { + } + + public void onEditPwdListner(String title) { + } + + public void onEditDescLisner(String desc) { + } + public void onEditTeamThemeListener(String theme){ + } + public void onEditTeamNameListener(String name) { + } + } + + public static abstract class OnCancelEditListner { + public void onEditTeamThemeListener(){ + } + public void onEditTeamNameListener(String name) { + } + } + + private void setLimtText() { + tvLimit.setText(etContent.getText().toString().length() + "/" + maxLength); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/widget/FixRoomTitleTextView.java b/app/src/main/java/com/chwl/app/avroom/widget/FixRoomTitleTextView.java new file mode 100644 index 0000000..cb3d643 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/widget/FixRoomTitleTextView.java @@ -0,0 +1,38 @@ +package com.chwl.app.avroom.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; + +import androidx.appcompat.widget.AppCompatTextView; + +/** + *

+ * 不一定可行... + *

+ * create by lvzebiao @2019/7/16 + */ +public class FixRoomTitleTextView extends AppCompatTextView { + + public FixRoomTitleTextView(Context context) { + super(context); + } + + public FixRoomTitleTextView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public FixRoomTitleTextView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + try { + return super.onTouchEvent(event); + } catch (Exception ex) { + ex.printStackTrace(); + } + return false; + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/widget/GalleryLayoutManager.java b/app/src/main/java/com/chwl/app/avroom/widget/GalleryLayoutManager.java new file mode 100644 index 0000000..2902416 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/widget/GalleryLayoutManager.java @@ -0,0 +1,1071 @@ +package com.chwl.app.avroom.widget; + +import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE; + +import android.content.Context; +import android.graphics.PointF; +import android.graphics.Rect; +import android.util.AttributeSet; +import android.util.Log; +import android.util.SparseArray; +import android.view.View; +import android.view.ViewGroup; + +import androidx.recyclerview.widget.LinearSmoothScroller; +import androidx.recyclerview.widget.LinearSnapHelper; +import androidx.recyclerview.widget.OrientationHelper; +import androidx.recyclerview.widget.RecyclerView; +import androidx.viewpager.widget.ViewPager; + +import com.chwl.app.application.App; + +/** + * A custom LayoutManager to build a {@link android.widget.Gallery} or a {@link ViewPager}like {@link RecyclerView} and + * support both {@link GalleryLayoutManager#HORIZONTAL} and {@link GalleryLayoutManager#VERTICAL} scroll. + * Created by chensuilun on 2016/11/18. + */ +public class GalleryLayoutManager extends RecyclerView.LayoutManager implements RecyclerView.SmoothScroller.ScrollVectorProvider { + private static final String TAG = "GalleryLayoutManager"; + final static int LAYOUT_START = -1; + + final static int LAYOUT_END = 1; + + public static final int HORIZONTAL = OrientationHelper.HORIZONTAL; + + public static final int VERTICAL = OrientationHelper.VERTICAL; + + private int mFirstVisiblePosition = 0; + private int mLastVisiblePos = 0; + private int mInitialSelectedPosition = 0; + + int mCurSelectedPosition = -1; + + View mCurSelectedView; + /** + * Scroll state + */ + private State mState; + + private LinearSnapHelper mSnapHelper = new LinearSnapHelper(); + + private InnerScrollListener mInnerScrollListener = new InnerScrollListener(); + + private boolean mCallbackInFling = false; + + /** + * Current orientation. Either {@link #HORIZONTAL} or {@link #VERTICAL} + */ + private int mOrientation = HORIZONTAL; + + private OrientationHelper mHorizontalHelper; + private OrientationHelper mVerticalHelper; + + public GalleryLayoutManager(int orientation) { + mOrientation = orientation; + } + + public int getOrientation() { + return mOrientation; + } + + public int getCurSelectedPosition() { + return mCurSelectedPosition; + } + + @Override + public RecyclerView.LayoutParams generateDefaultLayoutParams() { + if (mOrientation == VERTICAL) { + return new GalleryLayoutManager.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT); + } else { + return new GalleryLayoutManager.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.MATCH_PARENT); + } + } + + @Override + public RecyclerView.LayoutParams generateLayoutParams(Context c, AttributeSet attrs) { + return new LayoutParams(c, attrs); + } + + @Override + public RecyclerView.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) { + if (lp instanceof ViewGroup.MarginLayoutParams) { + return new LayoutParams((ViewGroup.MarginLayoutParams) lp); + } else { + return new LayoutParams(lp); + } + } + + @Override + public boolean checkLayoutParams(RecyclerView.LayoutParams lp) { + return lp instanceof LayoutParams; + } + + + @Override + public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { + if (App.isDebug()) { + Log.d(TAG, "onLayoutChildren() called with: state = [" + state + "]"); + } + if (getItemCount() == 0) { + reset(); + detachAndScrapAttachedViews(recycler); + return; + } + if (state.isPreLayout()) { + return; + } + if (state.getItemCount() != 0 && !state.didStructureChange()) { + if (App.isDebug()) { + Log.d(TAG, "onLayoutChildren: ignore extra layout step"); + } + return; + } + if (getChildCount() == 0 || state.didStructureChange()) { + reset(); + } + mInitialSelectedPosition = Math.min(Math.max(0, mInitialSelectedPosition), getItemCount() - 1); + detachAndScrapAttachedViews(recycler); + try { + firstFillCover(recycler, state, 0); + } catch (Exception e) { + } + } + + + private void reset() { + if (App.isDebug()) { + Log.d(TAG, "reset: "); + } + if (mState != null) { + mState.mItemsFrames.clear(); + } + //when data set update keep the last selected position + if (mCurSelectedPosition != -1) { + mInitialSelectedPosition = mCurSelectedPosition; + } + mInitialSelectedPosition = Math.min(Math.max(0, mInitialSelectedPosition), getItemCount() - 1); + mFirstVisiblePosition = mInitialSelectedPosition; + mLastVisiblePos = mInitialSelectedPosition; + mCurSelectedPosition = -1; + if (mCurSelectedView != null) { + mCurSelectedView.setSelected(false); + mCurSelectedView = null; + } + } + + + private void firstFillCover(RecyclerView.Recycler recycler, RecyclerView.State state, int scrollDelta) { + if (mOrientation == HORIZONTAL) { + firstFillWithHorizontal(recycler, state); + } else { + firstFillWithVertical(recycler, state); + } + + if (App.isDebug()) { + Log.d(TAG, "firstFillCover finish:first: " + mFirstVisiblePosition + ",last:" + mLastVisiblePos); + } + + if (mItemTransformer != null) { + View child; + for (int i = 0; i < getChildCount(); i++) { + child = getChildAt(i); + mItemTransformer.transformItem(this, child, calculateToCenterFraction(child, scrollDelta)); + } + } + mInnerScrollListener.onScrolled(mRecyclerView, 0, 0); + } + + /** + * Layout the item view witch position specified by {@link GalleryLayoutManager#mInitialSelectedPosition} first and then layout the other + * + * @param recycler + * @param state + */ + private void firstFillWithHorizontal(RecyclerView.Recycler recycler, RecyclerView.State state) { + detachAndScrapAttachedViews(recycler); + int leftEdge = getOrientationHelper().getStartAfterPadding(); + int rightEdge = getOrientationHelper().getEndAfterPadding(); + int startPosition = mInitialSelectedPosition; + int scrapWidth, scrapHeight; + Rect scrapRect = new Rect(); + int height = getVerticalSpace(); + int topOffset; + //layout the init position view + View scrap = recycler.getViewForPosition(mInitialSelectedPosition); + addView(scrap, 0); + measureChildWithMargins(scrap, 0, 0); + scrapWidth = getDecoratedMeasuredWidth(scrap); + scrapHeight = getDecoratedMeasuredHeight(scrap); + topOffset = (int) (getPaddingTop() + (height - scrapHeight) / 2.0f); + int left = (int) (getPaddingLeft() + (getHorizontalSpace() - scrapWidth) / 2.f); + scrapRect.set(left, topOffset, left + scrapWidth, topOffset + scrapHeight); + layoutDecorated(scrap, scrapRect.left, scrapRect.top, scrapRect.right, scrapRect.bottom); + if (getState().mItemsFrames.get(startPosition) == null) { + getState().mItemsFrames.put(startPosition, scrapRect); + } else { + getState().mItemsFrames.get(startPosition).set(scrapRect); + } + mFirstVisiblePosition = mLastVisiblePos = startPosition; + int leftStartOffset = getDecoratedLeft(scrap); + int rightStartOffset = getDecoratedRight(scrap); + //fill left of center + fillLeft(recycler, mInitialSelectedPosition - 1, leftStartOffset, leftEdge); + //fill right of center + fillRight(recycler, mInitialSelectedPosition + 1, rightStartOffset, rightEdge); + } + + @Override + public void onItemsRemoved(RecyclerView recyclerView, int positionStart, int itemCount) { + super.onItemsRemoved(recyclerView, positionStart, itemCount); + } + + /** + * Layout the item view witch position special by {@link GalleryLayoutManager#mInitialSelectedPosition} first and then layout the other + * + * @param recycler + * @param state + */ + private void firstFillWithVertical(RecyclerView.Recycler recycler, RecyclerView.State state) { + detachAndScrapAttachedViews(recycler); + int topEdge = getOrientationHelper().getStartAfterPadding(); + int bottomEdge = getOrientationHelper().getEndAfterPadding(); + int startPosition = mInitialSelectedPosition; + int scrapWidth, scrapHeight; + Rect scrapRect = new Rect(); + int width = getHorizontalSpace(); + int leftOffset; + //layout the init position view + View scrap = recycler.getViewForPosition(mInitialSelectedPosition); + addView(scrap, 0); + measureChildWithMargins(scrap, 0, 0); + scrapWidth = getDecoratedMeasuredWidth(scrap); + scrapHeight = getDecoratedMeasuredHeight(scrap); + leftOffset = (int) (getPaddingLeft() + (width - scrapWidth) / 2.0f); + int top = (int) (getPaddingTop() + (getVerticalSpace() - scrapHeight) / 2.f); + scrapRect.set(leftOffset, top, leftOffset + scrapWidth, top + scrapHeight); + layoutDecorated(scrap, scrapRect.left, scrapRect.top, scrapRect.right, scrapRect.bottom); + if (getState().mItemsFrames.get(startPosition) == null) { + getState().mItemsFrames.put(startPosition, scrapRect); + } else { + getState().mItemsFrames.get(startPosition).set(scrapRect); + } + mFirstVisiblePosition = mLastVisiblePos = startPosition; + int topStartOffset = getDecoratedTop(scrap); + int bottomStartOffset = getDecoratedBottom(scrap); + //fill left of center + fillTop(recycler, mInitialSelectedPosition - 1, topStartOffset, topEdge); + //fill right of center + fillBottom(recycler, mInitialSelectedPosition + 1, bottomStartOffset, bottomEdge); + } + + /** + * Fill left of the center view + * + * @param recycler + * @param startPosition start position to fill left + * @param startOffset layout start offset + * @param leftEdge + */ + private void fillLeft(RecyclerView.Recycler recycler, int startPosition, int startOffset, int leftEdge) { + View scrap; + int topOffset; + int scrapWidth, scrapHeight; + Rect scrapRect = new Rect(); + int height = getVerticalSpace(); + for (int i = startPosition; i >= 0 && startOffset > leftEdge; i--) { + scrap = recycler.getViewForPosition(i); + addView(scrap, 0); + measureChildWithMargins(scrap, 0, 0); + scrapWidth = getDecoratedMeasuredWidth(scrap); + scrapHeight = getDecoratedMeasuredHeight(scrap); + topOffset = (int) (getPaddingTop() + (height - scrapHeight) / 2.0f); + scrapRect.set(startOffset - scrapWidth, topOffset, startOffset, topOffset + scrapHeight); + layoutDecorated(scrap, scrapRect.left, scrapRect.top, scrapRect.right, scrapRect.bottom); + startOffset = scrapRect.left; + mFirstVisiblePosition = i; + if (getState().mItemsFrames.get(i) == null) { + getState().mItemsFrames.put(i, scrapRect); + } else { + getState().mItemsFrames.get(i).set(scrapRect); + } + } + } + + /** + * Fill right of the center view + * + * @param recycler + * @param startPosition start position to fill right + * @param startOffset layout start offset + * @param rightEdge + */ + private void fillRight(RecyclerView.Recycler recycler, int startPosition, int startOffset, int rightEdge) { + View scrap; + int topOffset; + int scrapWidth, scrapHeight; + Rect scrapRect = new Rect(); + int height = getVerticalSpace(); + for (int i = startPosition; i < getItemCount() && startOffset < rightEdge; i++) { + scrap = recycler.getViewForPosition(i); + addView(scrap); + measureChildWithMargins(scrap, 0, 0); + scrapWidth = getDecoratedMeasuredWidth(scrap); + scrapHeight = getDecoratedMeasuredHeight(scrap); + topOffset = (int) (getPaddingTop() + (height - scrapHeight) / 2.0f); + scrapRect.set(startOffset, topOffset, startOffset + scrapWidth, topOffset + scrapHeight); + layoutDecorated(scrap, scrapRect.left, scrapRect.top, scrapRect.right, scrapRect.bottom); + startOffset = scrapRect.right; + mLastVisiblePos = i; + if (getState().mItemsFrames.get(i) == null) { + getState().mItemsFrames.put(i, scrapRect); + } else { + getState().mItemsFrames.get(i).set(scrapRect); + } + } + } + + /** + * Fill top of the center view + * + * @param recycler + * @param startPosition start position to fill top + * @param startOffset layout start offset + * @param topEdge top edge of the RecycleView + */ + private void fillTop(RecyclerView.Recycler recycler, int startPosition, int startOffset, int topEdge) { + View scrap; + int leftOffset; + int scrapWidth, scrapHeight; + Rect scrapRect = new Rect(); + int width = getHorizontalSpace(); + for (int i = startPosition; i >= 0 && startOffset > topEdge; i--) { + scrap = recycler.getViewForPosition(i); + addView(scrap, 0); + measureChildWithMargins(scrap, 0, 0); + scrapWidth = getDecoratedMeasuredWidth(scrap); + scrapHeight = getDecoratedMeasuredHeight(scrap); + leftOffset = (int) (getPaddingLeft() + (width - scrapWidth) / 2.0f); + scrapRect.set(leftOffset, startOffset - scrapHeight, leftOffset + scrapWidth, startOffset); + layoutDecorated(scrap, scrapRect.left, scrapRect.top, scrapRect.right, scrapRect.bottom); + startOffset = scrapRect.top; + mFirstVisiblePosition = i; + if (getState().mItemsFrames.get(i) == null) { + getState().mItemsFrames.put(i, scrapRect); + } else { + getState().mItemsFrames.get(i).set(scrapRect); + } + } + } + + /** + * Fill bottom of the center view + * + * @param recycler + * @param startPosition start position to fill bottom + * @param startOffset layout start offset + * @param bottomEdge bottom edge of the RecycleView + */ + private void fillBottom(RecyclerView.Recycler recycler, int startPosition, int startOffset, int bottomEdge) { + View scrap; + int leftOffset; + int scrapWidth, scrapHeight; + Rect scrapRect = new Rect(); + int width = getHorizontalSpace(); + for (int i = startPosition; i < getItemCount() && startOffset < bottomEdge; i++) { + scrap = recycler.getViewForPosition(i); + addView(scrap); + measureChildWithMargins(scrap, 0, 0); + scrapWidth = getDecoratedMeasuredWidth(scrap); + scrapHeight = getDecoratedMeasuredHeight(scrap); + leftOffset = (int) (getPaddingLeft() + (width - scrapWidth) / 2.0f); + scrapRect.set(leftOffset, startOffset, leftOffset + scrapWidth, startOffset + scrapHeight); + layoutDecorated(scrap, scrapRect.left, scrapRect.top, scrapRect.right, scrapRect.bottom); + startOffset = scrapRect.bottom; + mLastVisiblePos = i; + if (getState().mItemsFrames.get(i) == null) { + getState().mItemsFrames.put(i, scrapRect); + } else { + getState().mItemsFrames.get(i).set(scrapRect); + } + } + } + + + private void fillCover(RecyclerView.Recycler recycler, RecyclerView.State state, int scrollDelta) { + if (getItemCount() == 0) { + return; + } + + if (mOrientation == HORIZONTAL) { + fillWithHorizontal(recycler, state, scrollDelta); + } else { + fillWithVertical(recycler, state, scrollDelta); + } + + + if (mItemTransformer != null) { + View child; + for (int i = 0; i < getChildCount(); i++) { + child = getChildAt(i); + mItemTransformer.transformItem(this, child, calculateToCenterFraction(child, scrollDelta)); + } + } + } + + private float calculateToCenterFraction(View child, float pendingOffset) { + int distance = calculateDistanceCenter(child, pendingOffset); + int childLength = mOrientation == GalleryLayoutManager.HORIZONTAL ? child.getWidth() : child.getHeight(); + + if (App.isDebug()) { + Log.d(TAG, "calculateToCenterFraction: distance:" + distance + ",childLength:" + childLength); + } + return Math.max(-1.f, Math.min(1.f, distance * 1.f / childLength)); + } + + /** + * @param child + * @param pendingOffset child view will scroll by + * @return + */ + private int calculateDistanceCenter(View child, float pendingOffset) { + OrientationHelper orientationHelper = getOrientationHelper(); + int parentCenter = (orientationHelper.getEndAfterPadding() - orientationHelper.getStartAfterPadding()) / 2 + orientationHelper.getStartAfterPadding(); + if (mOrientation == GalleryLayoutManager.HORIZONTAL) { + return (int) (child.getWidth() / 2 - pendingOffset + child.getLeft() - parentCenter); + } else { + return (int) (child.getHeight() / 2 - pendingOffset + child.getTop() - parentCenter); + } + + } + + /** + * @param recycler + * @param state + * @param dy + */ + private void fillWithVertical(RecyclerView.Recycler recycler, RecyclerView.State state, int dy) { + if (App.isDebug()) { + Log.d(TAG, "fillWithVertical: dy:" + dy); + } + int topEdge = getOrientationHelper().getStartAfterPadding(); + int bottomEdge = getOrientationHelper().getEndAfterPadding(); + + //1.remove and recycle the view that disappear in screen + View child; + if (getChildCount() > 0) { + if (dy >= 0) { + //remove and recycle the top off screen view + int fixIndex = 0; + for (int i = 0; i < getChildCount(); i++) { + child = getChildAt(i + fixIndex); + if (getDecoratedBottom(child) - dy < topEdge) { + if (App.isDebug()) { + Log.v(TAG, "fillWithVertical: removeAndRecycleView:" + getPosition(child) + ",bottom:" + getDecoratedBottom(child)); + } + removeAndRecycleView(child, recycler); + mFirstVisiblePosition++; + fixIndex--; + } else { + if (App.isDebug()) { + Log.d(TAG, "fillWithVertical: break:" + getPosition(child) + ",bottom:" + getDecoratedBottom(child)); + } + break; + } + } + } else { //dy<0 + //remove and recycle the bottom off screen view + for (int i = getChildCount() - 1; i >= 0; i--) { + child = getChildAt(i); + if (getDecoratedTop(child) - dy > bottomEdge) { + if (App.isDebug()) { + Log.v(TAG, "fillWithVertical: removeAndRecycleView:" + getPosition(child)); + } + removeAndRecycleView(child, recycler); + mLastVisiblePos--; + } else { + break; + } + } + } + + } + int startPosition = mFirstVisiblePosition; + int startOffset = -1; + int scrapWidth, scrapHeight; + Rect scrapRect; + int width = getHorizontalSpace(); + int leftOffset; + View scrap; + //2.Add or reattach item view to fill screen + if (dy >= 0) { + if (getChildCount() != 0) { + View lastView = getChildAt(getChildCount() - 1); + startPosition = getPosition(lastView) + 1; + startOffset = getDecoratedBottom(lastView); + } + for (int i = startPosition; i < getItemCount() && startOffset < bottomEdge + dy; i++) { + scrapRect = getState().mItemsFrames.get(i); + scrap = recycler.getViewForPosition(i); + addView(scrap); + if (scrapRect == null) { + scrapRect = new Rect(); + getState().mItemsFrames.put(i, scrapRect); + } + measureChildWithMargins(scrap, 0, 0); + scrapWidth = getDecoratedMeasuredWidth(scrap); + scrapHeight = getDecoratedMeasuredHeight(scrap); + leftOffset = (int) (getPaddingLeft() + (width - scrapWidth) / 2.0f); + if (startOffset == -1 && startPosition == 0) { + //layout the first position item in center + int top = (int) (getPaddingTop() + (getVerticalSpace() - scrapHeight) / 2.f); + scrapRect.set(leftOffset, top, leftOffset + scrapWidth, top + scrapHeight); + } else { + scrapRect.set(leftOffset, startOffset, leftOffset + scrapWidth, startOffset + scrapHeight); + } + layoutDecorated(scrap, scrapRect.left, scrapRect.top, scrapRect.right, scrapRect.bottom); + startOffset = scrapRect.bottom; + mLastVisiblePos = i; + if (App.isDebug()) { + Log.d(TAG, "fillWithVertical: add view:" + i + ",startOffset:" + startOffset + ",mLastVisiblePos:" + mLastVisiblePos + ",bottomEdge" + bottomEdge); + } + } + } else { + //dy<0 + if (getChildCount() > 0) { + View firstView = getChildAt(0); + startPosition = getPosition(firstView) - 1; //前一个View的position + startOffset = getDecoratedTop(firstView); + } + for (int i = startPosition; i >= 0 && startOffset > topEdge + dy; i--) { + scrapRect = getState().mItemsFrames.get(i); + scrap = recycler.getViewForPosition(i); + addView(scrap, 0); + if (scrapRect == null) { + scrapRect = new Rect(); + getState().mItemsFrames.put(i, scrapRect); + } + measureChildWithMargins(scrap, 0, 0); + scrapWidth = getDecoratedMeasuredWidth(scrap); + scrapHeight = getDecoratedMeasuredHeight(scrap); + leftOffset = (int) (getPaddingLeft() + (width - scrapWidth) / 2.0f); + scrapRect.set(leftOffset, startOffset - scrapHeight, leftOffset + scrapWidth, startOffset); + layoutDecorated(scrap, scrapRect.left, scrapRect.top, scrapRect.right, scrapRect.bottom); + startOffset = scrapRect.top; + mFirstVisiblePosition = i; + } + } + } + + + /** + * @param recycler + * @param state + */ + private void fillWithHorizontal(RecyclerView.Recycler recycler, RecyclerView.State state, int dx) { + int leftEdge = getOrientationHelper().getStartAfterPadding(); + int rightEdge = getOrientationHelper().getEndAfterPadding(); + if (App.isDebug()) { + Log.v(TAG, "fillWithHorizontal() called with: dx = [" + dx + "],leftEdge:" + leftEdge + ",rightEdge:" + rightEdge); + } + //1.remove and recycle the view that disappear in screen + View child; + if (getChildCount() > 0) { + if (dx >= 0) { + //remove and recycle the left off screen view + int fixIndex = 0; + for (int i = 0; i < getChildCount(); i++) { + child = getChildAt(i + fixIndex); + if (getDecoratedRight(child) - dx < leftEdge) { + removeAndRecycleView(child, recycler); + mFirstVisiblePosition++; + fixIndex--; + if (App.isDebug()) { + Log.v(TAG, "fillWithHorizontal:removeAndRecycleView:" + getPosition(child) + " mFirstVisiblePosition change to:" + mFirstVisiblePosition); + } + } else { + break; + } + } + } else { //dx<0 + //remove and recycle the right off screen view + for (int i = getChildCount() - 1; i >= 0; i--) { + child = getChildAt(i); + if (getDecoratedLeft(child) - dx > rightEdge) { + removeAndRecycleView(child, recycler); + mLastVisiblePos--; + if (App.isDebug()) { + Log.v(TAG, "fillWithHorizontal:removeAndRecycleView:" + getPosition(child) + "mLastVisiblePos change to:" + mLastVisiblePos); + } + } + } + } + + } + //2.Add or reattach item view to fill screen + int startPosition = mFirstVisiblePosition; + int startOffset = -1; + int scrapWidth, scrapHeight; + Rect scrapRect; + int height = getVerticalSpace(); + int topOffset; + View scrap; + if (dx >= 0) { + if (getChildCount() != 0) { + View lastView = getChildAt(getChildCount() - 1); + startPosition = getPosition(lastView) + 1; //start layout from next position item + startOffset = getDecoratedRight(lastView); + if (App.isDebug()) { + Log.d(TAG, "fillWithHorizontal:to right startPosition:" + startPosition + ",startOffset:" + startOffset + ",rightEdge:" + rightEdge); + } + } + for (int i = startPosition; i < getItemCount() && startOffset < rightEdge + dx; i++) { + scrapRect = getState().mItemsFrames.get(i); + scrap = recycler.getViewForPosition(i); + addView(scrap); + if (scrapRect == null) { + scrapRect = new Rect(); + getState().mItemsFrames.put(i, scrapRect); + } + measureChildWithMargins(scrap, 0, 0); + scrapWidth = getDecoratedMeasuredWidth(scrap); + scrapHeight = getDecoratedMeasuredHeight(scrap); + topOffset = (int) (getPaddingTop() + (height - scrapHeight) / 2.0f); + if (startOffset == -1 && startPosition == 0) { + // layout the first position item in center + int left = (int) (getPaddingLeft() + (getHorizontalSpace() - scrapWidth) / 2.f); + scrapRect.set(left, topOffset, left + scrapWidth, topOffset + scrapHeight); + } else { + scrapRect.set(startOffset, topOffset, startOffset + scrapWidth, topOffset + scrapHeight); + } + layoutDecorated(scrap, scrapRect.left, scrapRect.top, scrapRect.right, scrapRect.bottom); + startOffset = scrapRect.right; + mLastVisiblePos = i; + if (App.isDebug()) { + Log.d(TAG, "fillWithHorizontal,layout:mLastVisiblePos: " + mLastVisiblePos); + } + } + } else { + //dx<0 + if (getChildCount() > 0) { + View firstView = getChildAt(0); + startPosition = getPosition(firstView) - 1; //start layout from previous position item + startOffset = getDecoratedLeft(firstView); + if (App.isDebug()) { + Log.d(TAG, "fillWithHorizontal:to left startPosition:" + startPosition + ",startOffset:" + startOffset + ",leftEdge:" + leftEdge + ",child count:" + getChildCount()); + } + } + for (int i = startPosition; i >= 0 && startOffset > leftEdge + dx; i--) { + scrapRect = getState().mItemsFrames.get(i); + scrap = recycler.getViewForPosition(i); + addView(scrap, 0); + if (scrapRect == null) { + scrapRect = new Rect(); + getState().mItemsFrames.put(i, scrapRect); + } + measureChildWithMargins(scrap, 0, 0); + scrapWidth = getDecoratedMeasuredWidth(scrap); + scrapHeight = getDecoratedMeasuredHeight(scrap); + topOffset = (int) (getPaddingTop() + (height - scrapHeight) / 2.0f); + scrapRect.set(startOffset - scrapWidth, topOffset, startOffset, topOffset + scrapHeight); + layoutDecorated(scrap, scrapRect.left, scrapRect.top, scrapRect.right, scrapRect.bottom); + startOffset = scrapRect.left; + mFirstVisiblePosition = i; + } + } + } + + private int getHorizontalSpace() { + return getWidth() - getPaddingRight() - getPaddingLeft(); + } + + private int getVerticalSpace() { + return getHeight() - getPaddingBottom() - getPaddingTop(); + } + + public State getState() { + if (mState == null) { + mState = new State(); + } + return mState; + } + + private int calculateScrollDirectionForPosition(int position) { + if (getChildCount() == 0) { + return LAYOUT_START; + } + final int firstChildPos = mFirstVisiblePosition; + return position < firstChildPos ? LAYOUT_START : LAYOUT_END; + } + + @Override + public PointF computeScrollVectorForPosition(int targetPosition) { + final int direction = calculateScrollDirectionForPosition(targetPosition); + PointF outVector = new PointF(); + if (direction == 0) { + return null; + } + if (mOrientation == HORIZONTAL) { + outVector.x = direction; + outVector.y = 0; + } else { + outVector.x = 0; + outVector.y = direction; + } + return outVector; + } + + /** + * @author chensuilun + */ + class State { + /** + * Record all item view 's last position after last layout + */ + SparseArray mItemsFrames; + + /** + * RecycleView 's current scroll distance since first layout + */ + int mScrollDelta; + + public State() { + mItemsFrames = new SparseArray(); + mScrollDelta = 0; + } + } + + + @Override + public boolean canScrollHorizontally() { + return mOrientation == HORIZONTAL; + } + + + @Override + public boolean canScrollVertically() { + return mOrientation == VERTICAL; + } + + + @Override + public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) { + // When dx is positive,finger fling from right to left(←),scrollX+ + if (getChildCount() == 0 || dx == 0) { + return 0; + } + int delta = -dx; + int parentCenter = (getOrientationHelper().getEndAfterPadding() - getOrientationHelper().getStartAfterPadding()) / 2 + getOrientationHelper().getStartAfterPadding(); + View child; + if (dx > 0) { + //If we've reached the last item, enforce limits + if (getPosition(getChildAt(getChildCount() - 1)) == getItemCount() - 1) { + child = getChildAt(getChildCount() - 1); + delta = -Math.max(0, Math.min(dx, (child.getRight() - child.getLeft()) / 2 + child.getLeft() - parentCenter)); + } + } else { + //If we've reached the first item, enforce limits + if (mFirstVisiblePosition == 0) { + child = getChildAt(0); + delta = -Math.min(0, Math.max(dx, ((child.getRight() - child.getLeft()) / 2 + child.getLeft()) - parentCenter)); + } + } + if (App.isDebug()) { + Log.d(TAG, "scrollHorizontallyBy: dx:" + dx + ",fixed:" + delta); + } + getState().mScrollDelta = -delta; + fillCover(recycler, state, -delta); + offsetChildrenHorizontal(delta); + return -delta; + } + + @Override + public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) { + if (getChildCount() == 0 || dy == 0) { + return 0; + } + int delta = -dy; + int parentCenter = (getOrientationHelper().getEndAfterPadding() - getOrientationHelper().getStartAfterPadding()) / 2 + getOrientationHelper().getStartAfterPadding(); + View child; + if (dy > 0) { + //If we've reached the last item, enforce limits + if (getPosition(getChildAt(getChildCount() - 1)) == getItemCount() - 1) { + child = getChildAt(getChildCount() - 1); + delta = -Math.max(0, Math.min(dy, (getDecoratedBottom(child) - getDecoratedTop(child)) / 2 + getDecoratedTop(child) - parentCenter)); + } + } else { + //If we've reached the first item, enforce limits + if (mFirstVisiblePosition == 0) { + child = getChildAt(0); + delta = -Math.min(0, Math.max(dy, (getDecoratedBottom(child) - getDecoratedTop(child)) / 2 + getDecoratedTop(child) - parentCenter)); + } + } + if (App.isDebug()) { + Log.d(TAG, "scrollVerticallyBy: dy:" + dy + ",fixed:" + delta); + } + getState().mScrollDelta = -delta; + fillCover(recycler, state, -delta); + offsetChildrenVertical(delta); + return -delta; + } + + public OrientationHelper getOrientationHelper() { + if (mOrientation == HORIZONTAL) { + if (mHorizontalHelper == null) { + mHorizontalHelper = OrientationHelper.createHorizontalHelper(this); + } + return mHorizontalHelper; + } else { + if (mVerticalHelper == null) { + mVerticalHelper = OrientationHelper.createVerticalHelper(this); + } + return mVerticalHelper; + } + } + + /** + * @author chensuilun + */ + public static class LayoutParams extends RecyclerView.LayoutParams { + + public LayoutParams(Context c, AttributeSet attrs) { + super(c, attrs); + } + + public LayoutParams(int width, int height) { + super(width, height); + } + + public LayoutParams(ViewGroup.MarginLayoutParams source) { + super(source); + } + + public LayoutParams(ViewGroup.LayoutParams source) { + super(source); + } + + public LayoutParams(RecyclerView.LayoutParams source) { + super(source); + } + } + + + private ItemTransformer mItemTransformer; + + + public void setItemTransformer(ItemTransformer itemTransformer) { + mItemTransformer = itemTransformer; + } + + /** + * A ItemTransformer is invoked whenever a attached item is scrolled. + * This offers an opportunity for the application to apply a custom transformation + * to the item views using animation properties. + */ + public interface ItemTransformer { + + /** + * Apply a property transformation to the given item. + * + * @param layoutManager Current LayoutManager + * @param item Apply the transformation to this item + * @param fraction of page relative to the current front-and-center position of the pager. + * 0 is front and center. 1 is one full + * page position to the right, and -1 is one page position to the left. + */ + void transformItem(GalleryLayoutManager layoutManager, View item, float fraction); + } + + /** + * Listen for changes to the selected item + * + * @author chensuilun + */ + public interface OnItemSelectedListener { + /** + * @param recyclerView The RecyclerView which item view belong to. + * @param item The current selected view + * @param position The current selected view's position + */ + void onItemSelected(RecyclerView recyclerView, View item, int position); + } + + private OnItemSelectedListener mOnItemSelectedListener; + + public void setOnItemSelectedListener(OnItemSelectedListener onItemSelectedListener) { + mOnItemSelectedListener = onItemSelectedListener; + } + + public void attach(RecyclerView recyclerView) { + this.attach(recyclerView, -1); + } + + /** + * @param recyclerView + * @param selectedPosition + */ + public void attach(RecyclerView recyclerView, int selectedPosition) { + if (recyclerView == null) { + throw new IllegalArgumentException("The attach RecycleView must not null!!"); + } + mRecyclerView = recyclerView; + mInitialSelectedPosition = Math.max(0, selectedPosition); + recyclerView.setLayoutManager(this); + mSnapHelper.attachToRecyclerView(recyclerView); + recyclerView.addOnScrollListener(mInnerScrollListener); + } + + RecyclerView mRecyclerView; + + + public void setCallbackInFling(boolean callbackInFling) { + mCallbackInFling = callbackInFling; + } + + /** + * Inner Listener to listen for changes to the selected item + * + * @author chensuilun + */ + private class InnerScrollListener extends RecyclerView.OnScrollListener { + int mState; + boolean mCallbackOnIdle; + + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + super.onScrolled(recyclerView, dx, dy); + View snap = mSnapHelper.findSnapView(recyclerView.getLayoutManager()); + if (snap != null) { + int selectedPosition = recyclerView.getLayoutManager().getPosition(snap); + if (selectedPosition != mCurSelectedPosition) { + if (mCurSelectedView != null) { + mCurSelectedView.setSelected(false); + } + mCurSelectedView = snap; + mCurSelectedView.setSelected(true); + mCurSelectedPosition = selectedPosition; + if (!mCallbackInFling && mState != SCROLL_STATE_IDLE) { + if (App.isDebug()) { + Log.v(TAG, "ignore selection change callback when fling "); + } + mCallbackOnIdle = true; + return; + } + if (mOnItemSelectedListener != null) { + mOnItemSelectedListener.onItemSelected(recyclerView, snap, mCurSelectedPosition); + } + } + } + if (App.isDebug()) { + Log.v(TAG, "onScrolled: dx:" + dx + ",dy:" + dy); + } + } + + @Override + public void onScrollStateChanged(RecyclerView recyclerView, int newState) { + super.onScrollStateChanged(recyclerView, newState); + mState = newState; + if (App.isDebug()) { + Log.v(TAG, "onScrollStateChanged: " + newState); + } + if (mState == SCROLL_STATE_IDLE) { + View snap = mSnapHelper.findSnapView(recyclerView.getLayoutManager()); + if (snap != null) { + int selectedPosition = recyclerView.getLayoutManager().getPosition(snap); + if (selectedPosition != mCurSelectedPosition) { + if (mCurSelectedView != null) { + mCurSelectedView.setSelected(false); + } + mCurSelectedView = snap; + mCurSelectedView.setSelected(true); + mCurSelectedPosition = selectedPosition; + if (mOnItemSelectedListener != null) { + mOnItemSelectedListener.onItemSelected(recyclerView, snap, mCurSelectedPosition); + } + } else if (!mCallbackInFling && mOnItemSelectedListener != null && mCallbackOnIdle) { + mCallbackOnIdle = false; + mOnItemSelectedListener.onItemSelected(recyclerView, snap, mCurSelectedPosition); + } + } else { + Log.e(TAG, "onScrollStateChanged: snap null"); + } + } + } + } + + + @Override + public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) { + GallerySmoothScroller linearSmoothScroller = new GallerySmoothScroller(recyclerView.getContext()); + linearSmoothScroller.setTargetPosition(position); + startSmoothScroll(linearSmoothScroller); + } + + /** + * Implement to support {@link GalleryLayoutManager#smoothScrollToPosition(RecyclerView, RecyclerView.State, int)} + */ + private class GallerySmoothScroller extends LinearSmoothScroller { + + public GallerySmoothScroller(Context context) { + super(context); + } + + /** + * Calculates the horizontal scroll amount necessary to make the given view in center of the RecycleView + * + * @param view The view which we want to make in center of the RecycleView + * @return The horizontal scroll amount necessary to make the view in center of the RecycleView + */ + public int calculateDxToMakeCentral(View view) { + final RecyclerView.LayoutManager layoutManager = getLayoutManager(); + if (layoutManager == null || !layoutManager.canScrollHorizontally()) { + return 0; + } + final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams(); + final int left = layoutManager.getDecoratedLeft(view) - params.leftMargin; + final int right = layoutManager.getDecoratedRight(view) + params.rightMargin; + final int start = layoutManager.getPaddingLeft(); + final int end = layoutManager.getWidth() - layoutManager.getPaddingRight(); + final int childCenter = left + (int) ((right - left) / 2.0f); + final int containerCenter = (int) ((end - start) / 2.f); + return containerCenter - childCenter; + } + + /** + * Calculates the vertical scroll amount necessary to make the given view in center of the RecycleView + * + * @param view The view which we want to make in center of the RecycleView + * @return The vertical scroll amount necessary to make the view in center of the RecycleView + */ + public int calculateDyToMakeCentral(View view) { + final RecyclerView.LayoutManager layoutManager = getLayoutManager(); + if (layoutManager == null || !layoutManager.canScrollVertically()) { + return 0; + } + final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) + view.getLayoutParams(); + final int top = layoutManager.getDecoratedTop(view) - params.topMargin; + final int bottom = layoutManager.getDecoratedBottom(view) + params.bottomMargin; + final int start = layoutManager.getPaddingTop(); + final int end = layoutManager.getHeight() - layoutManager.getPaddingBottom(); + final int childCenter = top + (int) ((bottom - top) / 2.0f); + final int containerCenter = (int) ((end - start) / 2.f); + return containerCenter - childCenter; + } + + + @Override + protected void onTargetFound(View targetView, RecyclerView.State state, Action action) { + final int dx = calculateDxToMakeCentral(targetView); + final int dy = calculateDyToMakeCentral(targetView); + final int distance = (int) Math.sqrt(dx * dx + dy * dy); + final int time = calculateTimeForDeceleration(distance); + if (time > 0) { + action.update(-dx, -dy, time, mDecelerateInterpolator); + } + } + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/widget/GiftEffectView.java b/app/src/main/java/com/chwl/app/avroom/widget/GiftEffectView.java new file mode 100644 index 0000000..9a04905 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/widget/GiftEffectView.java @@ -0,0 +1,464 @@ +package com.chwl.app.avroom.widget; + +import android.animation.ObjectAnimator; +import android.content.Context; +import android.os.Handler; +import android.os.Message; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.view.animation.AccelerateDecelerateInterpolator; +import android.widget.RelativeLayout; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.bumptech.glide.load.DataSource; +import com.bumptech.glide.load.engine.GlideException; +import com.bumptech.glide.request.RequestListener; +import com.bumptech.glide.request.target.Target; +import com.chwl.app.R; +import com.chwl.app.utils.AnimLoadUtil; +import com.chwl.core.gift.GiftModel; +import com.chwl.core.gift.bean.GiftEffectInfo; +import com.chwl.core.gift.bean.GiftInfo; +import com.chwl.core.gift.bean.GiftReceiver; +import com.chwl.core.gift.bean.ShowAvatarType; +import com.chwl.core.initial.InitialModel; +import com.chwl.core.initial.bean.InitInfo; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.manager.IMNetEaseManager; +import com.chwl.core.manager.RoomEvent; +import com.chwl.library.common.glide.GlideUtils; +import com.chwl.library.common.util.OtherExtKt; +import com.netease.nim.uikit.common.util.string.StringUtil; +import com.opensource.svgaplayer.SVGACallback; +import com.opensource.svgaplayer.SVGADrawable; +import com.opensource.svgaplayer.SVGAImageView; +import com.opensource.svgaplayer.SVGAParser; +import com.opensource.svgaplayer.SVGAVideoEntity; +import com.tencent.qgame.animplayer.AnimConfig; +import com.tencent.qgame.animplayer.AnimView; +import com.tencent.qgame.animplayer.inter.IAnimListener; +import com.tencent.qgame.animplayer.util.ScaleType; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.lang.ref.WeakReference; +import java.util.HashMap; + +/** + * @author chenran + * @date 2017/10/8 + */ + +public class GiftEffectView extends RelativeLayout { + private SVGAImageView svgaImageView; + private AnimView vapAnimView; + private View svgaBg; + private GiftEffectListener giftEffectListener; + private EffectHandler effectHandler; + private boolean isAnim; + private boolean isPlayAnim; + private boolean isHideCarEffect; + + private String DOWNLOAD_TAG = "gift_effect_download"; + + private SVGAParser.ParseCompletion parseCompletion; + private SVGAParser mLocalSVGAparser; + + public GiftEffectView(Context context) { + super(context); + init(); + } + + public GiftEffectView(Context context, AttributeSet attr) { + super(context, attr); + init(); + } + + public GiftEffectView(Context context, AttributeSet attr, int i) { + super(context, attr, i); + init(); + } + + public boolean isAnim() { + return isAnim; + } + + public boolean isPlayAnim() { + return isPlayAnim; + } + + public void setGiftEffectListener(GiftEffectListener giftEffectListener) { + this.giftEffectListener = giftEffectListener; + } + + private void init() { + LayoutInflater.from(getContext()).inflate(R.layout.layout_gift_effect, this, true); + effectHandler = new EffectHandler(this); + svgaImageView = findViewById(R.id.svga_imageview); + svgaImageView.setClearsAfterStop(true); + svgaImageView.setLoops(1); + svgaBg = findViewById(R.id.svga_imageview_bg); + vapAnimView = findViewById(R.id.vap_anim_view); + mLocalSVGAparser = new SVGAParser(getContext()); + parseCompletion = new SVGAParser.ParseCompletion() { + + @Override + public void onError() { + OtherExtKt.doLog("GiftEffectView onError "); + effectHandler.sendEmptyMessage(0); + } + + @Override + public void onComplete(@NonNull SVGAVideoEntity svgaVideoEntity) { + OtherExtKt.doLog("GiftEffectView " + "onComplete"); + SVGADrawable drawable = new SVGADrawable(svgaVideoEntity); + svgaImageView.setImageDrawable(drawable); + svgaImageView.startAnimation(); + svgaBg.setVisibility(VISIBLE); + ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(svgaBg, "alpha", 0.0F, 2.0F).setDuration(1250); + objectAnimator1.setInterpolator(new AccelerateDecelerateInterpolator()); + objectAnimator1.start(); + } + }; +// svgaImageView.setVideoItem(); + svgaImageView.setCallback(new SVGACallback() { + @Override + public void onPause() { + OtherExtKt.doLog("GiftEffectView " +"onPause"); + } + + @Override + public void onFinished() { + OtherExtKt.doLog("GiftEffectView " +"onFinished"); + effectHandler.sendEmptyMessage(0); + } + + @Override + public void onRepeat() { + OtherExtKt.doLog("GiftEffectView " +"onRepeat"); + } + + @Override + public void onStep(int i, double v) { + + } + }); + vapAnimView.setScaleType(ScaleType.CENTER_CROP); + vapAnimView.setAnimListener(new IAnimListener() { + @Override + public boolean onVideoConfigReady(@NonNull AnimConfig animConfig) { + return true; + } + + @Override + public void onVideoStart() { + OtherExtKt.doLog("GiftEffectView " +"onVideoStart"); + OtherExtKt.doLog("GiftEffectView " +"drawEffect vapAnimView.setAnimListener onVideoStart "); + } + + @Override + public void onVideoRender(int i, @androidx.annotation.Nullable AnimConfig animConfig) { + } + + @Override + public void onVideoComplete() { + OtherExtKt.doLog("GiftEffectView " +"onVideoComplete"); + OtherExtKt.doLog("GiftEffectView " +"drawEffect vapAnimView.setAnimListener onVideoComplete "); + effectHandler.sendEmptyMessage(0); + } + + @Override + public void onVideoDestroy() { + OtherExtKt.doLog("GiftEffectView " +"onVideoDestroy"); + OtherExtKt.doLog("GiftEffectView " +"drawEffect vapAnimView.setAnimListener onVideoDestroy "); + effectHandler.sendEmptyMessage(0); + } + + @Override + public void onFailed(int i, @androidx.annotation.Nullable String s) { + OtherExtKt.doLog("GiftEffectView " +"onFailed i:" + i + " s:" + s); + OtherExtKt.doLog("GiftEffectView " +"drawEffect vapAnimView.setAnimListener onFailed i:" + i + " s:" + s); + effectHandler.sendEmptyMessage(0); + } + }); + } + + //xxx 播放礼物特效位置 + public void startGiftEffect(GiftEffectInfo giftEffectInfo) { + this.isAnim = true; + GiftInfo giftInfo = GiftModel.get().findGiftInfoById(giftEffectInfo.getGiftId()); + if (giftInfo == null || TextUtils.isEmpty(giftInfo.getGiftUrl())) { + giftInfo = giftEffectInfo.getGift(); + } + if (giftInfo != null) { + InitInfo initInfo = InitialModel.get().getCacheInitInfo(); + if (!isHideCarEffect && initInfo != null && giftInfo.getGoldPrice() >= initInfo.getHideCarEffectGiftPrice()) { + isHideCarEffect = true; + IMNetEaseManager.get().noticeRoomEvent(null, RoomEvent.ROOM_CAR_EFFECT_HIDE); + } + if (!AvRoomDataManager.get().mIsNeedGiftEffect || AvRoomDataManager.get().isSelfGamePlaying()) { + effectHandler.sendEmptyMessage(0); + return; + } + if (giftInfo.getOtherViewType() == 1 && !TextUtils.isEmpty(giftInfo.getViewUrl())) { + drawVAPEffect(giftInfo.getViewUrl(),giftEffectInfo); + } else if (giftInfo.isHasVggPic() && !StringUtil.isEmpty(giftInfo.getVggUrl())) { + drawSvgaEffect(giftInfo.getVggUrl(),giftEffectInfo); + } else { + effectHandler.sendEmptyMessage(0); + } + } else { + effectHandler.sendEmptyMessage(0); + } + } + + private void drawSvgaEffect(String url,GiftEffectInfo effectInfo) { + OtherExtKt.doLog("GiftEffectView " +"drawEffect drawSvgaEffect url:" + url); + + GlideUtils.instance().downloadFromUrl2(getContext(), url, new RequestListener() { + @Override + public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { + try { + String message = ""; + if (e != null) { + message = e.getMessage(); + } + OtherExtKt.doLog("GiftEffectView " +"drawEffect drawSvgaEffect onDownloadError url:" + url + " error = "+message); + effectHandler.sendEmptyMessage(0); + return true; + } catch (Exception ex) { + effectHandler.sendEmptyMessage(0); + return true; + } + } + + @Override + public boolean onResourceReady(File resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { + try { + String path = ""; + if (resource != null) { + path = resource.getPath(); + drawSvgaEffectFile(path,effectInfo); + } else { + effectHandler.sendEmptyMessage(0); + } + OtherExtKt.doLog("GiftEffectView " +"drawEffect drawSvgaEffect onDownloadCompleted url:" + url + " path:" + path); + } catch (Exception e) { + effectHandler.sendEmptyMessage(0); + } + return true; + } + + }); + } + + private void drawSvgaEffectFile(String path,GiftEffectInfo effectInfo) { + try { + OtherExtKt.doLog("GiftEffectView " +" drawEffect drawSvgaEffectFile path:" + path); + if (svgaImageView != null) { + OtherExtKt.postSafe(svgaImageView, () -> { + try { + svgaImageView.clear(); + svgaImageView.stopAnimation(); + if (effectInfo != null && effectInfo.getShowAvatarType() != ShowAvatarType.def) { + OtherExtKt.doLog("GiftEffectView " + "drawEffect drawSvgaEffectFile type != ShowAvatarType.def"); + AnimLoadUtil.INSTANCE.loadSvga(mLocalSVGAparser,svgaImageView, path, getImgMap(effectInfo), getTextMap(effectInfo), isSuccess -> { + OtherExtKt.doLog("GiftEffectView " + "drawEffect drawSvgaEffectFile loadSvga isSuccess:" + isSuccess); + if (isSuccess) { + svgaBg.setVisibility(VISIBLE); + ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(svgaBg, "alpha", 0.0F, 2.0F).setDuration(1250); + objectAnimator1.setInterpolator(new AccelerateDecelerateInterpolator()); + objectAnimator1.start(); + } else { + effectHandler.sendEmptyMessage(0); + } + + return null; + }); + } else { + OtherExtKt.doLog("GiftEffectView " + "drawEffect drawSvgaEffectFile type == ShowAvatarType.def"); + BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(path)); + mLocalSVGAparser.decodeFromInputStream(inputStream, path, parseCompletion, true, null, null); + } + } catch (FileNotFoundException e) { + effectHandler.sendEmptyMessage(0); + OtherExtKt.doLog("GiftEffectView error : "+e.getMessage()); + } + return null; + }); + } else { + OtherExtKt.doLog("GiftEffectView error : svgaImageView = null"); + effectHandler.sendEmptyMessage(0); + } + } catch (Exception e) { + e.printStackTrace(); + OtherExtKt.doLog("GiftEffectView error : "+e.getMessage()); + effectHandler.sendEmptyMessage(0); + } + } + + + + private void drawVAPEffect(String url, GiftEffectInfo effectInfo) { + OtherExtKt.doLog("GiftEffectView " +"drawEffect drawVAPEffect url:" + url); + + if (effectInfo != null && effectInfo.getShowAvatarType() != ShowAvatarType.def) { + + if (url != null) { + AnimLoadUtil.INSTANCE.loadVap(vapAnimView, url,getImgMap(effectInfo), getTextMap(effectInfo),isSuccess -> { + if (!isSuccess) { + effectHandler.sendEmptyMessage(0); + } + OtherExtKt.doLog("GiftEffectView " +"drawEffect drawVAPEffect loadVap isSuccess = "+isSuccess); + return null; + }); + } + } else { + + GlideUtils.instance().downloadFromUrl2(getContext(), url, new RequestListener() { + @Override + public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { + try { + String message = ""; + if (e != null) { + message = e.getMessage(); + } + OtherExtKt.doLog("GiftEffectView " +"drawEffect drawVAPEffect onDownloadError url:" + url + " error = "+message); + effectHandler.sendEmptyMessage(0); + return true; + } catch (Exception ex) { + effectHandler.sendEmptyMessage(0); + OtherExtKt.doLog("GiftEffectView error : "+e.getMessage()); + return true; + } + } + + @Override + public boolean onResourceReady(File resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { + String path = ""; + if (resource != null) { + path = resource.getPath(); + vapAnimView.startPlay(resource); + } else { + effectHandler.sendEmptyMessage(0); + } + OtherExtKt.doLog("GiftEffectView " +"drawEffect drawVAPEffect onDownloadCompleted url:" + url + " path:" + path); + return true; + } + }); + } + } + + private HashMap getImgMap(GiftEffectInfo effectInfo) { + HashMap imgMap = new HashMap<>(); + if (effectInfo.getShowAvatarType() == ShowAvatarType.send){ + imgMap.put("avatar1", effectInfo.getAvatar()); + }else if (effectInfo.getShowAvatarType() == ShowAvatarType.recv){ + if (OtherExtKt.isVerify(0,effectInfo.getTargetUsers())) { + GiftReceiver giftReceiver = effectInfo.getTargetUsers().get(0); + imgMap.put("avatar1", giftReceiver.getAvatar()); + } + }else if (effectInfo.getShowAvatarType() == ShowAvatarType.sendRecv){ + imgMap.put("avatar1", effectInfo.getAvatar()); + if (OtherExtKt.isVerify(0,effectInfo.getTargetUsers())) { + GiftReceiver giftReceiver = effectInfo.getTargetUsers().get(0); + imgMap.put("avatar2", giftReceiver.getAvatar()); + } + } + return imgMap; + } + + //目前id 是 uid 不是 erban ,暂时注释 + private HashMap getTextMap(GiftEffectInfo effectInfo) { + HashMap textMap = new HashMap<>(); + if (effectInfo.getShowAvatarType() == ShowAvatarType.send){ + textMap.put("name1", effectInfo.getNick()); +// textMap.put("id1", String.valueOf(effectInfo.getUid())); + }else if (effectInfo.getShowAvatarType() == ShowAvatarType.recv){ + if (OtherExtKt.isVerify(0,effectInfo.getTargetUsers())) { + GiftReceiver giftReceiver = effectInfo.getTargetUsers().get(0); + textMap.put("name1", giftReceiver.getNick()); +// textMap.put("id1", String.valueOf(giftReceiver.getUid())); + } + }else if (effectInfo.getShowAvatarType() == ShowAvatarType.sendRecv){ + textMap.put("name1", effectInfo.getNick()); +// textMap.put("id1", String.valueOf(effectInfo.getUid())); + if (OtherExtKt.isVerify(0,effectInfo.getTargetUsers())) { + GiftReceiver giftReceiver = effectInfo.getTargetUsers().get(0); + textMap.put("name2", giftReceiver.getNick()); +// textMap.put("id2", String.valueOf(giftReceiver.getUid())); + } + } + return textMap; + } + + private void deleteAnim() { + OtherExtKt.doLog("GiftEffectView " +"drawEffect 播放结束 deleteAnim "); + if (isHideCarEffect) { + isHideCarEffect = false; + IMNetEaseManager.get().noticeRoomEvent(null, RoomEvent.ROOM_CAR_EFFECT_SHOW); + } + svgaBg.setVisibility(GONE); + isAnim = false; + isPlayAnim = false; + if (giftEffectListener != null) { + giftEffectListener.onGiftEffectEnd(); + } + } + + public void release() { + OtherExtKt.doLog("GiftEffectView " +"release"); + effectHandler.removeMessages(0); + + if (mLocalSVGAparser != null) { + mLocalSVGAparser = null; + } + + if (svgaImageView != null) { + svgaImageView.clear(); + svgaImageView.stopAnimation(); + svgaImageView.setCallback(null); + } + + if (vapAnimView != null) { + vapAnimView.stopPlay(); + vapAnimView.setAnimListener(null); + } + + giftEffectListener = null; + + } + + public interface GiftEffectListener { + void onGiftEffectEnd(); + } + + private static class EffectHandler extends Handler { + private WeakReference mReference; + + EffectHandler(GiftEffectView giftEffectView) { + mReference = new WeakReference<>(giftEffectView); + } + + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + if (mReference != null) { + final GiftEffectView giftEffectView = mReference.get(); + if (giftEffectView != null) { + if (msg.what == 0) { + giftEffectView.deleteAnim(); + } + } + } + } + } + + +} diff --git a/app/src/main/java/com/chwl/app/avroom/widget/GiftV2View.java b/app/src/main/java/com/chwl/app/avroom/widget/GiftV2View.java new file mode 100644 index 0000000..975e880 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/widget/GiftV2View.java @@ -0,0 +1,1053 @@ +package com.chwl.app.avroom.widget; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.Keyframe; +import android.animation.ObjectAnimator; +import android.animation.PropertyValuesHolder; +import android.animation.ValueAnimator; +import android.app.Activity; +import android.content.Context; +import android.graphics.Path; +import android.graphics.Point; +import android.os.Handler; +import android.os.Message; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.util.Log; +import android.util.SparseArray; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import com.chwl.app.R; +import com.chwl.app.common.svga.SimpleSvgaParseCompletion; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.fansteam.bean.FansTeamMsgInfo; +import com.chwl.core.gift.GiftModel; +import com.chwl.core.gift.bean.GiftEffectInfo; +import com.chwl.core.gift.bean.GiftInfo; +import com.chwl.core.gift.bean.GiftMultiReceiverInfo; +import com.chwl.core.gift.bean.GiftReceiveInfo; +import com.chwl.core.gift.bean.GiftReceiver; +import com.chwl.core.gift.bean.LuckyBagGifts; +import com.chwl.core.gift.bean.MultiGiftReceiveInfo; +import com.chwl.core.im.custom.bean.FansTeamMsgAttachment; +import com.chwl.core.magic.MagicModel; +import com.chwl.core.magic.ObjectPool; +import com.chwl.core.magic.bean.MagicInfo; +import com.chwl.core.magic.bean.MagicReceivedInfo; +import com.chwl.core.magic.bean.MultiMagicReceivedInfo; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.core.utils.ComboUtil; +import com.chwl.library.common.util.OtherExtKt; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.ResolutionUtils; +import com.example.lib_utils.UiUtils; +import com.netease.nim.uikit.common.util.log.LogUtil; +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage; +import com.opensource.svgaplayer.SVGACallback; +import com.opensource.svgaplayer.SVGADrawable; +import com.opensource.svgaplayer.SVGAImageView; +import com.opensource.svgaplayer.SVGAParser; +import com.opensource.svgaplayer.SVGAVideoEntity; + +import java.lang.ref.WeakReference; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Random; + +import javax.annotation.Nullable; + + +/** + * 礼物特效布局 + * + * @author xiaoyu + */ + +public class GiftV2View extends FrameLayout implements GiftEffectView.GiftEffectListener { + private static final String TAG = GiftV2View.class.getSimpleName(); + private GiftEffectView giftEffectView; + private SVGAImageView mMagicExplodeView; + private int giftWidth; + private int giftHeight; + private SVGAParser mSVGAParser; + private List giftEffectInfoList; + private List mMagicReceivedInfos; + private HashMap mSVGAVideoEntityMap; + private UiHandler handler; + private boolean dettached = false; + + private Context context; + private int mScreenWidth; + private int mScreenHeight; + private Keyframe[] keyScale; + private Keyframe[] keyScaleCombo; + private Keyframe[] keyTrans; + private SvgaObjectPool mMagicViewPool; + + private boolean isRTL = false; + + public GiftV2View(Context context) { + this(context, null); + } + + public GiftV2View(Context context, AttributeSet attr) { + this(context, attr, 0); + } + + public GiftV2View(Context context, AttributeSet attr, int i) { + super(context, attr, i); + init(context); + } + + private void init(Context context) { + this.context = context; + isRTL = UiUtils.INSTANCE.isRtl(context); + mSVGAParser = new SVGAParser(context); + mSVGAVideoEntityMap = new HashMap<>(20); + LayoutInflater.from(getContext()).inflate(R.layout.layout_gift_v2_view, this, true); + mScreenWidth = ResolutionUtils.getScreenWidth(getContext()); + mScreenHeight = ResolutionUtils.getScreenHeight(getContext()); + giftWidth = UIUtil.dip2px(context, 80); + giftHeight = UIUtil.dip2px(context, 80); + + keyScale = new Keyframe[7]; + keyScale[0] = (Keyframe.ofFloat(0f, 1f)); + keyScale[1] = (Keyframe.ofFloat(0.1f, 1.3f)); + keyScale[2] = (Keyframe.ofFloat(0.2f, 1f)); + keyScale[3] = (Keyframe.ofFloat(0.3f, 1f)); + keyScale[4] = (Keyframe.ofFloat(0.5f, 2f)); + keyScale[5] = (Keyframe.ofFloat(0.8f, 2f)); + keyScale[6] = (Keyframe.ofFloat(1f, 1f)); + + keyScaleCombo = new Keyframe[4]; + keyScaleCombo[0] = (Keyframe.ofFloat(0f, 0.25f)); + keyScaleCombo[1] = (Keyframe.ofFloat(0.25f, 0.5f)); + keyScaleCombo[2] = (Keyframe.ofFloat(0.5f, 0.75f)); + keyScaleCombo[3] = (Keyframe.ofFloat(0.75f, 0.75f)); + + keyTrans = new Keyframe[3]; + keyTrans[0] = (Keyframe.ofFloat(0f, 0)); + keyTrans[1] = (Keyframe.ofFloat(0.2f, 0)); + keyTrans[2] = (Keyframe.ofFloat(0.3f, 0)); + + giftEffectInfoList = new ArrayList<>(); + mMagicReceivedInfos = new ArrayList<>(); + giftEffectView = findViewById(R.id.gift_effect_view); + mMagicExplodeView = findViewById(R.id.magic_explode_view); + giftEffectView.setGiftEffectListener(this); + handler = new UiHandler(this); + mMagicViewPool = new SvgaObjectPool(this); + } + + public void onReceiveMultiGiftMsg(MultiGiftReceiveInfo multiGiftReceiveInfo) { + if (multiGiftReceiveInfo != null) { + setVisibility(VISIBLE); + List targetUsers = multiGiftReceiveInfo.getTargetUsers(); + List targetUids = multiGiftReceiveInfo.getTargetUids(); + List giftReceiveInfos = new ArrayList<>(); + + if (OtherExtKt.isVerify(targetUsers)) { + for (GiftReceiver target : targetUsers) { + GiftReceiveInfo giftReceiveInfo = new GiftReceiveInfo(); + giftReceiveInfo.setUid(multiGiftReceiveInfo.getUid()); + giftReceiveInfo.setNick(multiGiftReceiveInfo.getNick()); + giftReceiveInfo.setAvatar(multiGiftReceiveInfo.getAvatar()); + giftReceiveInfo.setTargetUid(target.getUid()); + giftReceiveInfo.setTargetNick(target.getNick()); + giftReceiveInfo.setTargetAvatar(target.getAvatar()); + giftReceiveInfo.setGiftId(multiGiftReceiveInfo.getGiftId()); + giftReceiveInfo.setGift(multiGiftReceiveInfo.getGift()); + giftReceiveInfo.setGiftNum(multiGiftReceiveInfo.getGiftNum()); + //礼物值 + giftReceiveInfo.setGiftValueVos(multiGiftReceiveInfo.getGiftValueVos()); + giftReceiveInfo.setCurrentTime(multiGiftReceiveInfo.getCurrentTime()); + giftReceiveInfos.add(giftReceiveInfo); + } + } else { + if (OtherExtKt.isVerify(targetUids)) { + for (Long target : targetUids) { + GiftReceiveInfo giftReceiveInfo = new GiftReceiveInfo(); + giftReceiveInfo.setUid(multiGiftReceiveInfo.getUid()); + giftReceiveInfo.setNick(multiGiftReceiveInfo.getNick()); + giftReceiveInfo.setAvatar(multiGiftReceiveInfo.getAvatar()); + giftReceiveInfo.setTargetUid(target); + giftReceiveInfo.setGiftId(multiGiftReceiveInfo.getGiftId()); + giftReceiveInfo.setGift(multiGiftReceiveInfo.getGift()); + giftReceiveInfo.setGiftNum(multiGiftReceiveInfo.getGiftNum()); + //礼物值 + giftReceiveInfo.setGiftValueVos(multiGiftReceiveInfo.getGiftValueVos()); + giftReceiveInfo.setCurrentTime(multiGiftReceiveInfo.getCurrentTime()); + giftReceiveInfos.add(giftReceiveInfo); + } + } + } + + + drawGiftAnimation(giftReceiveInfos, GiftEffectInfo.GIFT_RECEIVE_TYPE_ALL); + } + } + + + private void drawMagicAnimation(List magicReceivedInfos) { + if (!AvRoomDataManager.get().mIsNeedGiftEffect || + AvRoomDataManager.get().isSelfGamePlaying()) { + return; + } + + if (magicReceivedInfos.size() > 0) { + boolean needShowExplode = false; + MagicReceivedInfo explodeSvga = null; + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo != null) { + // 算出是否需要显示爆炸动效 + for (MagicReceivedInfo magicReceivedInfo : magicReceivedInfos) { + boolean needShowExplodeEffect = magicReceivedInfo.isNeedShowExplodeEffect(); + if (needShowExplodeEffect) { + needShowExplode = true; + explodeSvga = magicReceivedInfo; + break; + } + } + + for (int i = 0; i < magicReceivedInfos.size(); i++) { + MagicReceivedInfo magicReceivedInfo = magicReceivedInfos.get(i); + SparseArray micViewPoint = AvRoomDataManager.get().mMicPointMap; + // 算出发送者和接受者的位置 + int senderPosition = AvRoomDataManager.get().getMicPosition(magicReceivedInfo.getUid()); + int receivePosition = AvRoomDataManager.get().getMicPosition(magicReceivedInfo.getTargetUid()); + + if (micViewPoint == null) { + //空的原因是麦位坐标延迟了500ms初始化 + LogUtil.print("magic micViewPoint is null"); + continue; + } + + Point senderPoint = micViewPoint.get(senderPosition); + Point receivePoint = micViewPoint.get(receivePosition); + if (receivePoint == null || isGameRoomMoreThan6People()) { //这种情况就是接收者已经不在麦上 + //礼物送到中间的位置 + receivePoint = new Point(UIUtil.getScreenWidth(context) / 2 - giftWidth / 2, + UIUtil.getScreenHeight(context) / 2); + } + + drawMagicView(senderPoint, receivePoint, magicReceivedInfo); + + //totalCoin += giftInfo.getGoldPrice() * magicReceivedInfo.getGiftNum(); + } + if (needShowExplode && mMagicReceivedInfos.add(explodeSvga)) { + if (mMagicReceivedInfos.size() == 1 && !mMagicExplodeView.isAnimating()) { + Message msg = Message.obtain(); + msg.what = 1; + msg.obj = mMagicReceivedInfos.get(0); + handler.sendMessage(msg); + } + } + } + } + } + + private void drawGiftAnimation(List giftReceiveInfos, int giftReceiveType) { + if (giftReceiveInfos.size() > 0) { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo != null) { + List targetUsers = new ArrayList<>(); + int totalCoin = 0; + + for (int i = 0; i < giftReceiveInfos.size(); i++) { + GiftReceiveInfo giftReceiveInfo = giftReceiveInfos.get(i); + SparseArray micViewPoint = AvRoomDataManager.get().mMicPointMap; + GiftInfo giftInfo = GiftModel.get().findGiftInfoById(giftReceiveInfo.getGiftId()); + if (giftInfo == null || TextUtils.isEmpty(giftInfo.getGiftUrl())) { + giftInfo = giftReceiveInfo.getGift(); + } + if (giftInfo == null) { + OtherExtKt.doLog("礼物IM消息 找不到 礼物 取消送礼特效 渲染"); + return; + } + // 算出发送者和接受者的位置 + int senderPosition = AvRoomDataManager.get().getMicPosition(giftReceiveInfo.getUid()); + int receivePosition = AvRoomDataManager.get().getMicPosition(giftReceiveInfo.getTargetUid()); + + // 离开模式给房主送礼 + if ((roomInfo.isLeaveMode() || AvRoomDataManager.get().isSingleRoom()) && + giftReceiveInfo.getTargetUid() == roomInfo.getUid()) + receivePosition = -1; + + if (micViewPoint == null) { + //产生空的原因是麦位坐标初始化有500ms延迟 + LogUtil.print("gift micViewPoint is null"); + continue; + } + Point senderPoint = micViewPoint.get(senderPosition); + Point receivePoint = micViewPoint.get(receivePosition); + + // 连击 特殊动画 + if (giftReceiveInfo.getUid() == AuthModel.get().getCurrentUid()){ + if (ComboUtil.INSTANCE.isChangePoint()) { + senderPoint = ComboUtil.INSTANCE.getPoint(); + } + } + + //设置动画结束的位置 + if (receivePoint == null || isGameRoomMoreThan6People()) { //这种情况就是接收者已经不在麦上 + //礼物送到中间的位置 + receivePoint = new Point(UIUtil.getScreenWidth(context) / 2 - giftWidth / 2, + UIUtil.getScreenHeight(context) / 2); + } + giftReceiveInfo.setGift(giftInfo); + drawGiftView(senderPoint, receivePoint, giftReceiveInfo); + + totalCoin += giftInfo.getGoldPrice() * giftReceiveInfo.getGiftNum(); + + + GiftReceiver giftReceiver = new GiftReceiver(); + giftReceiver.setUid(giftReceiveInfo.getTargetUid()); + giftReceiver.setAvatar(giftReceiveInfo.getTargetAvatar()); + giftReceiver.setNick(giftReceiveInfo.getTargetNick()); + targetUsers.add(giftReceiver); + } + GiftReceiveInfo giftReceiveInfo = giftReceiveInfos.get(0); + GiftInfo giftInfo = giftReceiveInfo.getGift(); + if (giftInfo != null && giftInfo.isEffectGift()) { + Message msg = Message.obtain(); + msg.what = 0; + GiftEffectInfo giftEffectInfo = new GiftEffectInfo(); + giftEffectInfo.setUid(giftReceiveInfo.getUid()); + giftEffectInfo.setNick(giftReceiveInfo.getNick()); + giftEffectInfo.setAvatar(giftReceiveInfo.getAvatar()); + giftEffectInfo.setGiftId(giftReceiveInfo.getGiftId()); + giftEffectInfo.setGiftNum(giftReceiveInfo.getGiftNum()); + giftEffectInfo.setGift(giftInfo); + giftEffectInfo.setTargetUsers(targetUsers); + giftEffectInfo.setGiftReceiveType(giftReceiveType); + //- 嵌套头像礼物所用字段 + giftEffectInfo.setShowAvatarType(giftInfo.getShowAvatarType()); + + msg.obj = giftEffectInfo; + handler.sendMessageDelayed(msg, 200); + } + } + } + } + + private void drawLuckyGift(GiftReceiveInfo giftReceiveInfos, int giftReceiveType, boolean isShowAnimation, String svgaUrl, int pos) { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo != null) { + List targetUsers = new ArrayList<>(); + int totalCoin = 0; + boolean isPlaySvga = false; + if (AvRoomDataManager.get().mIsNeedGiftEffect && + !AvRoomDataManager.get().isSelfGamePlaying()) { + if (svgaUrl != null && !svgaUrl.isEmpty()) { + isPlaySvga = true; + SVGAImageView imageView = playLuckyBagAnim(svgaUrl); + handler.postDelayed(() -> { + removeView(imageView); + imageView.stopAnimation(true); + }, 1800); + } + } + + if (isPlaySvga) { + handler.postDelayed(() -> drawLuckyGiftAnimation(roomInfo, giftReceiveInfos, totalCoin, targetUsers, giftReceiveType, isShowAnimation, pos), 1200); + } else { + drawLuckyGiftAnimation(roomInfo, giftReceiveInfos, totalCoin, targetUsers, giftReceiveType, isShowAnimation, pos); + } + } + } + + private void drawLuckyGiftAnimation(RoomInfo roomInfo, GiftReceiveInfo giftReceiveInfo, int totalCoin, List targetUsers, int giftReceiveType, boolean isShowAnimation, int pos) { + SparseArray micViewPoint = AvRoomDataManager.get().mMicPointMap; + GiftInfo giftInfo = GiftModel.get().findGiftInfoById(giftReceiveInfo.getGiftId()); + if (giftInfo == null || TextUtils.isEmpty(giftInfo.getGiftUrl())) { + giftInfo = giftReceiveInfo.getGift(); + } + if (giftInfo == null) { + return; + } + // 算出发送者和接受者的位置 + int senderPosition = AvRoomDataManager.get().getMicPosition(giftReceiveInfo.getUid()); + int receivePosition = AvRoomDataManager.get().getMicPosition(giftReceiveInfo.getTargetUid()); + + // 离开模式给房主送礼 + if ((roomInfo.isLeaveMode() || AvRoomDataManager.get().isSingleRoom()) && + giftReceiveInfo.getTargetUid() == roomInfo.getUid()) + receivePosition = -1; + + if (micViewPoint == null) { + //产生空的原因是麦位坐标初始化有500ms延迟 + LogUtil.print("gift micViewPoint is null"); + return; + } + + Point senderPoint = micViewPoint.get(senderPosition); + Point receivePoint = micViewPoint.get(receivePosition); + if (receivePoint == null || isGameRoomMoreThan6People()) { //这种情况就是接收者已经不在麦上 + //礼物送到中间的位置 + receivePoint = new Point(UIUtil.getScreenWidth(context) / 2 - giftWidth / 2, + UIUtil.getScreenHeight(context) / 2); + } + giftReceiveInfo.setGift(giftInfo); + drawGiftView(senderPoint, receivePoint, giftReceiveInfo); + + totalCoin += giftInfo.getGoldPrice() * giftReceiveInfo.getGiftNum(); + + + GiftReceiver giftReceiver = new GiftReceiver(); + giftReceiver.setUid(giftReceiveInfo.getTargetUid()); + giftReceiver.setAvatar(giftReceiveInfo.getTargetAvatar()); + giftReceiver.setNick(giftReceiveInfo.getTargetNick()); + targetUsers.add(giftReceiver); + if (!isShowAnimation) return; + giftInfo = giftReceiveInfo.getDisplayGift().get(pos); + if (giftInfo != null && giftInfo.isEffectGift()) { + Message msg = Message.obtain(); + msg.what = 0; + GiftEffectInfo giftEffectInfo = new GiftEffectInfo(); + giftEffectInfo.setUid(giftReceiveInfo.getUid()); + giftEffectInfo.setNick(giftReceiveInfo.getNick()); + giftEffectInfo.setAvatar(giftReceiveInfo.getAvatar()); + giftEffectInfo.setGiftId(giftReceiveInfo.getDisplayGift().get(pos).getGiftId()); + giftEffectInfo.setGiftNum(giftReceiveInfo.getGiftNum()); + giftEffectInfo.setGift(giftInfo); + giftEffectInfo.setTargetUsers(targetUsers); + giftEffectInfo.setGiftReceiveType(giftReceiveType); + + //- 嵌套头像礼物所用字段 + giftEffectInfo.setShowAvatarType(giftInfo.getShowAvatarType()); + + msg.obj = giftEffectInfo; + handler.sendMessageDelayed(msg, 200); + } + } + + private SVGAImageView playLuckyBagAnim(String svgaUrl) { + SVGAImageView imageView = new SVGAImageView(context); + String path = "svga/svga_lucky_gift.svga"; + SimpleSvgaParseCompletion parseCompletion = new SimpleSvgaParseCompletion() { + @Override + public void onComplete(@Nullable SVGAVideoEntity svgaVideoEntity) { + SVGADrawable drawable = new SVGADrawable(svgaVideoEntity); + imageView.setImageDrawable(drawable); + imageView.startAnimation(); + } + }; + if (TextUtils.isEmpty(svgaUrl)) { + SVGAParser.Companion.shareParser().decodeFromAssets(path, parseCompletion, null); + } else { + try { + SVGAParser.Companion.shareParser().decodeFromURL(new URL(svgaUrl), parseCompletion, null); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + } + FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + layoutParams.gravity = Gravity.CENTER; + imageView.setLayoutParams(layoutParams); + addView(imageView); + return imageView; + } + + + public void onReceiveGiftToMultiMsg(GiftMultiReceiverInfo giftMultiReceiverInfo) { + if (giftMultiReceiverInfo != null) { + setVisibility(VISIBLE); + List targetUsers = giftMultiReceiverInfo.getTargetUsers(); + List targetUids = giftMultiReceiverInfo.getTargetUids(); + List giftReceiveInfos = new ArrayList<>(); + if (OtherExtKt.isVerify(targetUsers)) { + for (GiftReceiver targetUser : targetUsers) { + GiftReceiveInfo giftReceiveInfo = new GiftReceiveInfo(); + giftReceiveInfo.setUid(giftMultiReceiverInfo.getUid()); + giftReceiveInfo.setGiftNum(giftMultiReceiverInfo.getGiftNum()); + giftReceiveInfo.setTargetUid(targetUser.getUid()); + giftReceiveInfo.setTargetNick(targetUser.getNick()); + giftReceiveInfo.setTargetAvatar(targetUser.getAvatar()); + giftReceiveInfo.setNick(giftMultiReceiverInfo.getNick()); + giftReceiveInfo.setGiftId(giftMultiReceiverInfo.getGiftId()); + giftReceiveInfo.setAvatar(giftMultiReceiverInfo.getAvatar()); + giftReceiveInfo.setGift(giftMultiReceiverInfo.getGift()); + //礼物值 + giftReceiveInfo.setGiftValueVos(giftMultiReceiverInfo.getGiftValueVos()); + giftReceiveInfo.setCurrentTime(giftMultiReceiverInfo.getCurrentTime()); + + giftReceiveInfos.add(giftReceiveInfo); + } + } else { + if (OtherExtKt.isVerify(targetUids)) { + for (Long target : targetUids) { + GiftReceiveInfo giftReceiveInfo = new GiftReceiveInfo(); + giftReceiveInfo.setUid(giftMultiReceiverInfo.getUid()); + giftReceiveInfo.setNick(giftMultiReceiverInfo.getNick()); + giftReceiveInfo.setAvatar(giftMultiReceiverInfo.getAvatar()); + giftReceiveInfo.setTargetUid(target); + giftReceiveInfo.setGiftId(giftMultiReceiverInfo.getGiftId()); + giftReceiveInfo.setGift(giftMultiReceiverInfo.getGift()); + giftReceiveInfo.setGiftNum(giftMultiReceiverInfo.getGiftNum()); + //礼物值 + giftReceiveInfo.setGiftValueVos(giftMultiReceiverInfo.getGiftValueVos()); + giftReceiveInfo.setCurrentTime(giftMultiReceiverInfo.getCurrentTime()); + giftReceiveInfos.add(giftReceiveInfo); + } + } + } + + drawGiftAnimation(giftReceiveInfos, GiftEffectInfo.GIFT_RECEIVE_TYPE_MULTI); + } + } + + public void onReceiveLuckyGiftToMultiMsg(LuckyBagGifts giftMultiReceiverInfo) { + if (giftMultiReceiverInfo != null) { + setVisibility(VISIBLE); + int size = Math.min(giftMultiReceiverInfo.getDisplayGift().size(), 6); + for (int i = 0; i < size; i++) { + GiftReceiveInfo giftReceiveInfo = new GiftReceiveInfo(); + giftReceiveInfo.setUid(giftMultiReceiverInfo.getUid()); + giftReceiveInfo.setTargetNick(giftMultiReceiverInfo.getUser().getNick()); + giftReceiveInfo.setTargetUid(giftMultiReceiverInfo.getUser().getUid()); + giftReceiveInfo.setGiftNum(giftMultiReceiverInfo.getGiftNum()); + giftReceiveInfo.setDisplayGift(giftMultiReceiverInfo.getDisplayGift()); + giftReceiveInfo.setNick(giftMultiReceiverInfo.getNick()); + giftReceiveInfo.setGiftId(giftMultiReceiverInfo.getGiftList().get(0).getGiftId()); + giftReceiveInfo.setGift(giftMultiReceiverInfo.getDisplayGift().get(i)); + //礼物值 + giftReceiveInfo.setGiftValueVos(giftMultiReceiverInfo.getGiftValueVos()); + giftReceiveInfo.setCurrentTime(giftMultiReceiverInfo.getCurrentTime()); + drawLuckyGift(giftReceiveInfo, GiftEffectInfo.GIFT_RECEIVE_TYPE_LUCKY, giftMultiReceiverInfo.isShowAnimation(), giftMultiReceiverInfo.getLuckyGiftSvgaUrl(), i); + } + } + } + + private boolean isCenter(MagicReceivedInfo magicReceivedInfo) { + int magicId = magicReceivedInfo.getMagicId(); + MagicInfo magicInfo = MagicModel.get().getMagicInfo(magicId); + if (magicInfo == null) return magicReceivedInfo.getPosition() == MagicInfo.POS_CENTER; + return magicInfo.getPosition() == MagicInfo.POS_CENTER; + } + + private String getValidPathAnimationUrl(int magicId, String url) { + if (!TextUtils.isEmpty(url)) return url; + MagicInfo magicInfo = MagicModel.get().getMagicInfo(magicId); + if (magicInfo == null) return ""; + return magicInfo.getPathAnim(); + } + + private String getValidExplodeAnimationUrl(int magicId, String url) { + if (!TextUtils.isEmpty(url)) return url; + MagicInfo magicInfo = MagicModel.get().getMagicInfo(magicId); + if (magicInfo == null) return ""; + return magicInfo.getExplodeAnim(); + } + + public void onReceiveGiftMsg(GiftReceiveInfo giftReceiveInfo) { + List giftReceiveInfos = new ArrayList<>(); + giftReceiveInfos.add(giftReceiveInfo); + drawGiftAnimation(giftReceiveInfos, GiftEffectInfo.GIFT_RECEIVE_TYPE_SINGLE); + } + + public void onReceiveMagicMsg(MagicReceivedInfo magicReceivedInfo) { + List magicReceivedInfos = new ArrayList<>(); + magicReceivedInfos.add(magicReceivedInfo); + drawMagicAnimation(magicReceivedInfos); + } + + public void onReceiveMultiMagicMsg(MultiMagicReceivedInfo multiMagicReceivedInfo) { + if (multiMagicReceivedInfo != null) { + setVisibility(VISIBLE); + List targetUids = multiMagicReceivedInfo.getTargetUids(); + List magicReceivedInfos = new ArrayList<>(); + for (Long targetUid : targetUids) { + MagicReceivedInfo magicReceivedInfo = new MagicReceivedInfo(); + magicReceivedInfo.setUid(multiMagicReceivedInfo.getUid()); + magicReceivedInfo.setNumber(multiMagicReceivedInfo.getNumber()); + magicReceivedInfo.setTargetUid(targetUid); + magicReceivedInfo.setNick(multiMagicReceivedInfo.getNick()); + magicReceivedInfo.setMagicId(multiMagicReceivedInfo.getMagicId()); + magicReceivedInfo.setAvatar(multiMagicReceivedInfo.getAvatar()); + // 兼容旧版魔法面板无最新魔法的问题 + magicReceivedInfo.setPathAnim(multiMagicReceivedInfo.getPathAnim()); + magicReceivedInfo.setExplodeAnim(multiMagicReceivedInfo.getExplodeAnim()); + magicReceivedInfo.setNeedShowExplodeEffect(multiMagicReceivedInfo.isNeedShowExplode()); + magicReceivedInfo.setPosition(multiMagicReceivedInfo.getPosition()); + + magicReceivedInfo.setGiftValueVos(multiMagicReceivedInfo.getGiftValueVos()); + magicReceivedInfo.setCurrentTime(multiMagicReceivedInfo.getCurrentTime()); + magicReceivedInfos.add(magicReceivedInfo); + } + drawMagicAnimation(magicReceivedInfos); + } + } + + public void onReceiveFansTeamOpenMsg(ChatRoomMessage message) { + if (message.getAttachment() instanceof FansTeamMsgAttachment) { + FansTeamMsgInfo msgInfo = ((FansTeamMsgAttachment) message.getAttachment()).getFansTeamMsgInfo(); + if (msgInfo == null) return; + + GiftInfo giftInfo = msgInfo.getGiftVo(); + if (giftInfo == null) return; + + SparseArray micViewPoint = AvRoomDataManager.get().mMicPointMap; + // 算出发送者和接受者的位置 + int senderPosition = AvRoomDataManager.get().getMicPosition(msgInfo.getUid()); + int receivePosition = AvRoomDataManager.get().getMicPosition(AvRoomDataManager.get().getRoomUid()); + + // 离开模式给房主送礼 + if ((AvRoomDataManager.get().isLeaveMode() || AvRoomDataManager.get().isSingleRoom())) { + receivePosition = -1; + } + + if (micViewPoint == null) { + //产生空的原因是麦位坐标初始化有500ms延迟 + LogUtil.print("gift micViewPoint is null"); + return; + } + + Point senderPoint = micViewPoint.get(senderPosition); + Point receivePoint = micViewPoint.get(receivePosition); + if (receivePoint == null || isGameRoomMoreThan6People()) {//这种情况就是接收者已经不在麦上 + //礼物送到中间的位置 + receivePoint = new Point(UIUtil.getScreenWidth(context) / 2 - giftWidth / 2, + UIUtil.getScreenHeight(context) / 2); + } + drawGiftView(senderPoint, receivePoint, giftInfo); + } + + } + + private void drawGiftEffect(GiftEffectInfo giftEffectInfo) { + giftEffectInfoList.add(giftEffectInfo); + OtherExtKt.doLog("GiftV2View drawEffect drawGiftEffect 特效礼物 进入播放队列 GiftId = "+giftEffectInfo.getGiftId() + " effectInfoList.Size = "+giftEffectInfoList.size()); + if (!giftEffectView.isAnim()) { + giftEffectView.startGiftEffect(giftEffectInfo); + giftEffectInfoList.remove(0); + } + } + + /** + * 获取当前是否有飘屏正在显示 + * + * @return + */ + public boolean getIsPlayAnim() { + return giftEffectView.isPlayAnim(); + } + + private void drawMagicView(Point senderPoint, Point receivePoint, MagicReceivedInfo magicReceivedInfo) { + if (!AvRoomDataManager.get().mIsNeedGiftEffect || + AvRoomDataManager.get().isSelfGamePlaying()) { + return; + } + + if (senderPoint == null || isGameRoomMoreThan6People()) + senderPoint = new Point(mScreenWidth - giftWidth, mScreenHeight - UIUtil.dip2px(context, 50)); + SVGAImageView imageView = mMagicViewPool.borrowMagicObject(senderPoint); + String animationUrl = getValidPathAnimationUrl(magicReceivedInfo.getMagicId(), + magicReceivedInfo.getPathAnim()); + if (TextUtils.isEmpty(animationUrl)) return; + startSvgaAnimation(animationUrl, new SimpleParseCompletion() { + @Override + public void onComplete(SVGAVideoEntity svgaVideoEntity) { + cacheSvgaVideoItem(animationUrl, svgaVideoEntity); + SVGADrawable drawable = new SVGADrawable(svgaVideoEntity); + imageView.setLoops(1); + imageView.setImageDrawable(drawable); + imageView.setClearsAfterStop(true); + imageView.startAnimation(); + imageView.setCallback(new SimpleSvgaCallback(GiftV2View.this, imageView)); + } + + @Override + public void onError() { + super.onError(); + } + }); + + Path path = getBezierCurvePath(senderPoint, receivePoint, isCenter(magicReceivedInfo)); + ValueAnimator pathAnimator; + // 当前版本小于21,需要 + pathAnimator = ObjectAnimator.ofFloat(imageView, View.TRANSLATION_X, View.TRANSLATION_Y, path); + pathAnimator.setDuration(1250); + pathAnimator.start(); + } + + private void startSvgaAnimation(String animation, SimpleParseCompletion parseCompletion) { + try { + SVGAVideoEntity svgaVideoEntity = popSvgaVideoItem(animation); + if (svgaVideoEntity != null) { + System.out.println(TAG + ResUtil.getString(R.string.avroom_widget_giftv2view_01)); + parseCompletion.onComplete(svgaVideoEntity); + } else { + System.out.println(TAG + ResUtil.getString(R.string.avroom_widget_giftv2view_02)); + URL url = new URL(animation); + mSVGAParser.decodeFromURL(url, parseCompletion, null); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void drawGiftView(Point senderPoint, Point receivePoint, GiftReceiveInfo giftReceiveInfo) { + if (giftReceiveInfo == null) { + return; + } + GiftInfo giftInfo = giftReceiveInfo.getGift(); + giftInfo.uid = giftReceiveInfo.getUid(); + if (giftInfo == null) { + return; + } + drawGiftView(senderPoint, receivePoint, giftInfo); + } + + private void drawGiftView(Point senderPoint, Point receivePoint, GiftInfo giftInfo) { + if (!AvRoomDataManager.get().mIsNeedGiftEffect || + AvRoomDataManager.get().isSelfGamePlaying()) { + return; + } + if (giftInfo == null) { + return; + } + final Point center = new Point(); + center.x = context.getResources().getDisplayMetrics().widthPixels / 2; + center.y = context.getResources().getDisplayMetrics().heightPixels / 2; + //设置开始播放动画的位置 + if (senderPoint == null || isGameRoomMoreThan6People()) { + senderPoint = new Point(mScreenWidth / 2 - giftWidth / 2, UIUtil.dip2px(context, 25)); + } + SVGAImageView imageView = mMagicViewPool.borrowGiftObject(senderPoint); + ImageLoadUtils.loadImage(context, giftInfo.getGiftUrl(), imageView); + + Keyframe keyTransX3 = (Keyframe.ofFloat(0.5f, center.x - senderPoint.x - giftWidth / 2)); + Keyframe keyTransX4 = (Keyframe.ofFloat(0.8f, center.x - senderPoint.x - giftWidth / 2)); + Keyframe keyTransX5 = (Keyframe.ofFloat(1f, receivePoint.x - senderPoint.x)); + if (isRTL) { + keyTransX3 = (Keyframe.ofFloat(0.5f, senderPoint.x - center.x + giftWidth / 2)); + keyTransX4 = (Keyframe.ofFloat(0.8f, senderPoint.x - center.x + giftWidth / 2)); + keyTransX5 = (Keyframe.ofFloat(1f, senderPoint.x - receivePoint.x)); + } + + Keyframe keyTransY3 = (Keyframe.ofFloat(0.5f, center.y - senderPoint.y - giftHeight / 2)); + Keyframe keyTransY4 = (Keyframe.ofFloat(0.8f, center.y - senderPoint.y - giftHeight / 2)); + Keyframe keyTransY5 = (Keyframe.ofFloat(1f, receivePoint.y - senderPoint.y)); + + PropertyValuesHolder p0 = PropertyValuesHolder.ofKeyframe("translationX", keyTrans[0], keyTrans[1], keyTrans[2], keyTransX3, keyTransX4, keyTransX5); + PropertyValuesHolder p1 = PropertyValuesHolder.ofKeyframe("translationY", keyTrans[0], keyTrans[1], keyTrans[2], keyTransY3, keyTransY4, keyTransY5); + PropertyValuesHolder p2 = PropertyValuesHolder.ofKeyframe("scaleX", keyScale); + PropertyValuesHolder p3 = PropertyValuesHolder.ofKeyframe("scaleY", keyScale); + + PropertyValuesHolder p0c = PropertyValuesHolder.ofKeyframe("translationX", keyTrans[0], keyTransX5); + PropertyValuesHolder p1c = PropertyValuesHolder.ofKeyframe("translationY", keyTrans[0], keyTransY5); + PropertyValuesHolder p2c = PropertyValuesHolder.ofKeyframe("scaleX", keyScaleCombo); + PropertyValuesHolder p3c = PropertyValuesHolder.ofKeyframe("scaleY", keyScaleCombo); + + long time; + ObjectAnimator objectAnimator; + // 连击 特殊动画 + if (ComboUtil.INSTANCE.isChangePoint() && giftInfo.uid == AuthModel.get().getCurrentUid()){ + objectAnimator = ObjectAnimator.ofPropertyValuesHolder(imageView, p2c, p3c, p1c, p0c); + time = 600; + }else { + objectAnimator = ObjectAnimator.ofPropertyValuesHolder(imageView, p2, p3, p1, p0); + time = 2000; + } + + objectAnimator.setDuration(time); + objectAnimator.start(); + OtherExtKt.doLog("礼物icon 飞行动画开始播放 礼物名 = "+giftInfo.getGiftName()); + objectAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mMagicViewPool.returnObject(imageView); + } + }); + } + + private boolean isGameRoomMoreThan6People() { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + return AvRoomDataManager.get().isOpenGame() && roomInfo != null && roomInfo.getMgMicNum() > 6; + } + + + private Path getBezierCurvePath(Point sendPoint, Point receivePoint, boolean center) { + Point endPoint = new Point(receivePoint.x - sendPoint.x, receivePoint.y - sendPoint.y); + Point control = new Point(endPoint.x / 2, -(sendPoint.y + receivePoint.y) / 2 - new Random().nextInt(200)); + Path path = new Path(); + path.moveTo(0, 0); + float v1 = new Random().nextFloat(); + int pos = new Random().nextInt(50); + pos = v1 > 0.5F ? pos : -pos; + pos = center ? 0 : pos; + path.quadTo(control.x, control.y, endPoint.x + pos, endPoint.y + pos); + return path; + } + + public void release() { + dettached = true; + giftEffectInfoList.clear(); + giftEffectView.release(); + handler.removeCallbacksAndMessages(null); + handler.removeMessages(0); + mMagicExplodeView.stopAnimation(); + mMagicExplodeView.clearAnimation(); + mMagicViewPool.shutdown(); + } + + @Override + public void onGiftEffectEnd() { + if (giftEffectInfoList != null && giftEffectInfoList.size() > 0) { + giftEffectView.startGiftEffect(giftEffectInfoList.get(0)); + giftEffectInfoList.remove(0); + } + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + release(); + System.out.println(TAG + "onDetachedFromWindow: " + dettached); + } + + private SVGAVideoEntity popSvgaVideoItem(String url) { + return mSVGAVideoEntityMap.get(url); + } + + private void cacheSvgaVideoItem(String url, SVGAVideoEntity videoEntity) { + mSVGAVideoEntityMap.put(url, videoEntity); + } + + + private static class UiHandler extends Handler { + private WeakReference mReference; + + UiHandler(GiftV2View giftV2View) { + this.mReference = new WeakReference<>(giftV2View); + } + + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + GiftV2View giftV2View = mReference.get(); + if (giftV2View == null) return; + Activity activity = (Activity) giftV2View.context; + if (activity == null || activity.isDestroyed()) return; + if (msg.what == 0) { + // 播放礼物动效 + GiftEffectInfo giftEffectInfo = (GiftEffectInfo) msg.obj; + giftV2View.drawGiftEffect(giftEffectInfo); + } else if (msg.what == 1) { + // 播放魔法svga + if (msg.obj == null) return; + MagicReceivedInfo explodeSvga = (MagicReceivedInfo) msg.obj; + String animationUrl = giftV2View.getValidExplodeAnimationUrl(explodeSvga.getMagicId(), + explodeSvga.getExplodeAnim()); + if (TextUtils.isEmpty(animationUrl)) return; + giftV2View.startSvgaAnimation(animationUrl, new SimpleParseCompletion() { + @Override + public void onComplete(SVGAVideoEntity svgaVideoEntity) { + GiftV2View giftV2View = mReference.get(); + if (giftV2View == null) return; + giftV2View.cacheSvgaVideoItem(animationUrl, svgaVideoEntity); + SVGAImageView imageView = giftV2View.mMagicExplodeView; + SVGADrawable drawable = new SVGADrawable(svgaVideoEntity); + imageView.setLoops(1); + imageView.setImageDrawable(drawable); + imageView.setClearsAfterStop(true); + imageView.startAnimation(); + imageView.setCallback(new SimpleSvgaCallback(giftV2View) { + @Override + public void onFinished() { + GiftV2View giftV2View = mReference.get(); + if (giftV2View == null) return; + // 移除上一次播放的爆炸特效 + giftV2View.mMagicReceivedInfos.remove(0); + int size = giftV2View.mMagicReceivedInfos.size(); + if (size > 0) { + Message message = Message.obtain(); + message.what = 1; + message.obj = giftV2View.mMagicReceivedInfos.get(0); + sendMessage(message); + } + } + }); + } + }); + } + } + } + + private static class SimpleSvgaCallback implements SVGACallback { + private SVGAImageView mImageView; + private WeakReference mReference; + + + SimpleSvgaCallback(GiftV2View giftV2View) { + mReference = new WeakReference<>(giftV2View); + } + + SimpleSvgaCallback(GiftV2View giftV2View, SVGAImageView imageView) { + mReference = new WeakReference<>(giftV2View); + this.mImageView = imageView; + } + + @Override + public void onPause() { + GiftV2View giftV2View = mReference.get(); + if (giftV2View == null) return; + if (mImageView == null) return; + mImageView.stopAnimation(true); + giftV2View.mMagicViewPool.returnObject(mImageView); + } + + @Override + public void onFinished() { + GiftV2View giftV2View = mReference.get(); + if (giftV2View == null) return; + if (mImageView == null) return; + mImageView.stopAnimation(true); + giftV2View.mMagicViewPool.returnObject(mImageView); + } + + @Override + public void onRepeat() { + + } + + @Override + public void onStep(int i, double v) { + + } + } + + private static class SimpleParseCompletion implements SVGAParser.ParseCompletion { + + @Override + public void onComplete(SVGAVideoEntity svgaVideoEntity) { + + } + + @Override + public void onError() { + + } + } + + private static class SvgaObjectPool extends ObjectPool { + private WeakReference mReference; + private boolean isRTL = false; + + SvgaObjectPool(GiftV2View giftV2View) { + super(); + mReference = new WeakReference<>(giftV2View); + isRTL = UiUtils.INSTANCE.isRtl(giftV2View.getContext()); + } + + private SVGAImageView cleanView(SVGAImageView imageView) { + imageView.setBackground(null); + imageView.setImageDrawable(null); + imageView.clearAnimation(); + imageView.setTranslationX(0); + imageView.setTranslationY(0); + imageView.setAlpha(1F); + imageView.setScaleX(1F); + imageView.setScaleY(1F); + imageView.setClearsAfterStop(true); + imageView.setCallback(null); + imageView.setVisibility(GONE); + return imageView; + } + + /** + * 返回一个礼物的imageView + * + * @param senderPoint - + * @return - + */ + SVGAImageView borrowGiftObject(Point senderPoint) { + GiftV2View parent = mReference.get(); + if (parent == null) return null; + SVGAImageView imageView = cleanView(super.borrowObject()); + LayoutParams params = new LayoutParams(parent.giftWidth, parent.giftHeight); + imageView.setLayoutParams(params); + if (isRTL) { + params.rightMargin = senderPoint.x; + }else{ + params.leftMargin = senderPoint.x; + } + params.topMargin = senderPoint.y; + imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE); + if (parent.indexOfChild(imageView) == -1) + parent.addView(imageView); + imageView.setVisibility(VISIBLE); + return imageView; + } + + /** + * 返回一个魔法的imageView + * + * @param senderPoint - + * @return - + */ + SVGAImageView borrowMagicObject(Point senderPoint) { + GiftV2View parent = mReference.get(); + if (parent == null) return null; + SVGAImageView imageView = cleanView(super.borrowObject()); + LayoutParams params = new LayoutParams(parent.giftWidth, parent.giftHeight); + imageView.setLayoutParams(params); + if (isRTL) { + params.rightMargin = senderPoint.x; + }else{ + params.leftMargin = senderPoint.x; + } + params.topMargin = senderPoint.y; + imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE); + imageView.setScaleX(1.5F); + imageView.setScaleY(1.5F); + if (parent.indexOfChild(imageView) == -1) + parent.addView(imageView); + imageView.setVisibility(VISIBLE); + return imageView; + } + + @Override + public void returnObject(SVGAImageView object) { + GiftV2View parent = mReference.get(); + if (parent == null || object == null) return; + int index; + if ((index = parent.indexOfChild(object)) >= 0 && object.isAttachedToWindow() && !parent.dettached) { + Log.e(TAG, ", stopAgain: " + parent.getChildCount()); + // TODO: 2018/3/23 为什么activity会在onStop之后一段时间才调用onDestroy, bug bug bug !!!!! + Context context = parent.context; + if (context instanceof Activity) { + boolean hasWindowFocus = ((Activity) context).hasWindowFocus(); + if (hasWindowFocus) { + parent.removeViewAt(index); + } + } + } + Log.e(TAG, "returnObject: " + parent.dettached); + Log.e(TAG, "parent svga image view count: " + (parent.getChildCount() - 2)); + super.returnObject(cleanView(object)); + } + + /** + * 不用直接调用这个 + */ + @Override + protected SVGAImageView createObject() { + GiftV2View parent = mReference.get(); + if (parent == null) return null; + return new SVGAImageView(parent.context); + } + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/widget/LollipopFixedWebView.java b/app/src/main/java/com/chwl/app/avroom/widget/LollipopFixedWebView.java new file mode 100644 index 0000000..9eaa3c4 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/widget/LollipopFixedWebView.java @@ -0,0 +1,38 @@ +package com.chwl.app.avroom.widget; + +import android.annotation.TargetApi; +import android.content.Context; +import android.content.res.Configuration; +import android.os.Build; +import android.util.AttributeSet; +import android.webkit.WebView; + +public class LollipopFixedWebView extends WebView { + + public LollipopFixedWebView(Context context) { + super(getFixedContext(context)); + } + + public LollipopFixedWebView(Context context, AttributeSet attrs) { + super(getFixedContext(context), attrs); + } + + public LollipopFixedWebView(Context context, AttributeSet attrs, int defStyleAttr) { + super(getFixedContext(context), attrs, defStyleAttr); + } + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + public LollipopFixedWebView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(getFixedContext(context), attrs, defStyleAttr, defStyleRes); + } + + public LollipopFixedWebView(Context context, AttributeSet attrs, int defStyleAttr, boolean privateBrowsing) { + super(getFixedContext(context), attrs, defStyleAttr, privateBrowsing); + } + + public static Context getFixedContext(Context context) { + if (Build.VERSION.SDK_INT >= 21 && Build.VERSION.SDK_INT < 23) // Android Lollipop 5.0 & 5.1 + return context.createConfigurationContext(new Configuration()); + return context; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/widget/LuckyBagBtn.kt b/app/src/main/java/com/chwl/app/avroom/widget/LuckyBagBtn.kt new file mode 100644 index 0000000..4a40244 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/widget/LuckyBagBtn.kt @@ -0,0 +1,135 @@ +package com.chwl.app.avroom.widget + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.widget.FrameLayout +import com.chwl.app.R +import com.chwl.app.avroom.bean.LuckyBagEntity +import com.chwl.app.avroom.dialog.RoomLuckyBagOpenDialog +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.databinding.ViewLuckyBagBtnBinding +import com.chwl.app.utils.RoomHelperManager +import com.chwl.core.user.UserModel +import com.chwl.core.utils.myutil.MyTimeUtils +import com.chwl.library.common.util.ClickUtils.click +import com.chwl.library.common.util.doLog +import com.chwl.library.common.util.doToast +import com.chwl.library.common.util.isVerify +import com.chwl.library.common.util.postSafe +import com.chwl.library.common.util.setVis +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch + +class LuckyBagBtn : FrameLayout{ + + constructor(context: Context) : super(context){initView(context)} + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs){initView(context)} + + + lateinit var mBinding : ViewLuckyBagBtnBinding + + var mData = mutableListOf() + private var mTimeDownJob : Job? = null + + private val needLog = true + + private var mOpenDialog :RoomLuckyBagOpenDialog ? = null + + private fun initView(context: Context) { + mBinding = ViewLuckyBagBtnBinding.inflate(LayoutInflater.from(context),this,true) + mBinding.number.setBgColor("#f33a49") + + click { + onClick() + } + } + + + private fun onClick() { + if (UserModel.get().cacheLoginUserInfo?.isRechargeUser == true) { + R.string._ver_23_Lucky_bag_Limit_tips.doToast() + return + } + mData.isVerify(0){ + mOpenDialog = RoomLuckyBagOpenDialog() + mOpenDialog?.mData = it + mOpenDialog?.mActionCallBack = object : BaseDialogFragment.Action { + override fun onAction(type: Int, data: Any?) { + if (data != null && data is LuckyBagEntity) { + mData.remove(data) + showView() + } + } + } + mOpenDialog?.show(context) + } + } + + + fun setNewData(data: List) { + mData = data.toMutableList() + mData.forEach { + it.countDownTime = System.currentTimeMillis() + } + showView() + } + + fun addData(data : LuckyBagEntity) { + mData.add(data) + val sortedBy = mData.sortedBy { it.beginTime } + mData = sortedBy.toMutableList() + showView() + } + + private fun showView() { + this.postSafe { + setVis(mData.isVerify()) + + mBinding.number.text = mData.size.toString() + mBinding.number.setVis(mData.size > 1) + + mData.isVerify(0){ + mBinding.bagImg.setImageResource(if (it.isGift) R.drawable.ic_lucky_bag_btn_gift_pic else R.drawable.ic_lucky_bag_btn_gold_pic) + "开奖时间= ${MyTimeUtils.millis2String(it.beginTime)} 开奖倒计时= ${it.countDownSecond} 记录的本地时间为= ${MyTimeUtils.millis2String(it.countDownTime)} ".doLog() + startTimeDown(it.countDownTime,it.countDownSecond) + } + } + } + + private fun startTimeDown(countDownTime: Long,countDownSecond:Int) { + val downTime = RoomHelperManager.getTimeDown(countDownTime,countDownSecond) + mTimeDownJob?.cancel() + mTimeDownJob = GlobalScope.launch { + for (time in downTime downTo 0) { + delay(1000L) + mBinding.time.postSafe{ + val timeString = RoomHelperManager.getTimeString(time) + mBinding.time.text = timeString + mBinding.time.setVis(time != 0L) + "倒计时 i=$time timeString=$timeString".doLog(needLog) + if (time == 0L) { + "开奖时间 倒计时为0 就是现在 = ${MyTimeUtils.millis2String(System.currentTimeMillis())}".doLog(needLog) + } + } + } + mTimeDownJob?.cancel() + mTimeDownJob = null + } + mTimeDownJob?.start() + } + + + override fun onDetachedFromWindow() { + mTimeDownJob?.cancel() + mTimeDownJob = null + super.onDetachedFromWindow() + } + + fun doDetach() { + mOpenDialog?.dismiss() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/widget/MagicTextView.java b/app/src/main/java/com/chwl/app/avroom/widget/MagicTextView.java new file mode 100644 index 0000000..9d5043c --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/widget/MagicTextView.java @@ -0,0 +1,329 @@ +package com.chwl.app.avroom.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.BlurMaskFilter; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Paint.Join; +import android.graphics.Paint.Style; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.Rect; +import android.graphics.Typeface; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.text.TextPaint; +import android.util.AttributeSet; +import android.util.Pair; +import android.widget.TextView; + +import com.chwl.app.R; + +import java.util.ArrayList; +import java.util.WeakHashMap; + +/** + * 该自定义view是用于显示礼物数字的 + * + * Success is the sum of small efforts, repeated day in and day out. + * 成功就是日复一日那一点点小小努力的积累。 + * AndroidGroup:158423375 + * Author:Johnny + * AuthorQQ:956595454 + * AuthorWX:Qiang_it + * AuthorPhone:nothing + * Created by 2016/9/22. + */ +public class MagicTextView extends TextView { + + private ArrayList outerShadows; + private ArrayList innerShadows; + + private WeakHashMap> canvasStore; + + private Canvas tempCanvas; + private Bitmap tempBitmap; + + private Drawable foregroundDrawable; + + private float strokeWidth; + private Integer strokeColor; + private Join strokeJoin; + private float strokeMiter; + + private int[] lockedCompoundPadding; + private boolean frozen = false; + + public MagicTextView(Context context) { + super(context); + init(null); + } + public MagicTextView(Context context, AttributeSet attrs) { + super(context, attrs); + init(attrs); + } + public MagicTextView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(attrs); + } + + public void init(AttributeSet attrs){ + outerShadows = new ArrayList(); + innerShadows = new ArrayList(); + if(canvasStore == null){ + canvasStore = new WeakHashMap>(); + } + + if(attrs != null){ + TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.MagicTextView); + + String typefaceName = a.getString( R.styleable.MagicTextView_typeface); + if(typefaceName != null) { + Typeface tf = Typeface.createFromAsset(getContext().getAssets(), String.format("fonts/%s.ttf", typefaceName)); + setTypeface(tf); + } + + if(a.hasValue(R.styleable.MagicTextView_foreground)){ + Drawable foreground = a.getDrawable(R.styleable.MagicTextView_foreground); + if(foreground != null){ + this.setForegroundDrawable(foreground); + }else{ + this.setTextColor(a.getColor(R.styleable.MagicTextView_foreground, 0xff000000)); + } + } + + if(a.hasValue(R.styleable.MagicTextView_innerShadowColor)){ + this.addInnerShadow(a.getFloat(R.styleable.MagicTextView_innerShadowRadius, 0), + a.getFloat(R.styleable.MagicTextView_innerShadowDx, 0), + a.getFloat(R.styleable.MagicTextView_innerShadowDy, 0), + a.getColor(R.styleable.MagicTextView_innerShadowColor, 0xff000000)); + } + + if(a.hasValue(R.styleable.MagicTextView_outerShadowColor)){ + this.addOuterShadow(a.getFloat(R.styleable.MagicTextView_outerShadowRadius, 0), + a.getFloat(R.styleable.MagicTextView_outerShadowDx, 0), + a.getFloat(R.styleable.MagicTextView_outerShadowDy, 0), + a.getColor(R.styleable.MagicTextView_outerShadowColor, 0xff000000)); + } + + if(a.hasValue(R.styleable.MagicTextView_mstrokeColor)){ + float strokeWidth = a.getFloat(R.styleable.MagicTextView_mstrokeWidth, 1); + int strokeColor = a.getColor(R.styleable.MagicTextView_mstrokeColor, 0xff000000); + float strokeMiter = a.getFloat(R.styleable.MagicTextView_mstrokeMiter, 10); + Join strokeJoin = null; + switch(a.getInt(R.styleable.MagicTextView_strokeJoinStyle, 0)){ + case(0): strokeJoin = Join.MITER; break; + case(1): strokeJoin = Join.BEVEL; break; + case(2): strokeJoin = Join.ROUND; break; + } + this.setStroke(strokeWidth, strokeColor, strokeJoin, strokeMiter); + } + } + } + + public void setStroke(float width, int color, Join join, float miter){ + strokeWidth = width; + strokeColor = color; + strokeJoin = join; + strokeMiter = miter; + } + + public void setStroke(float width, int color){ + setStroke(width, color, Join.MITER, 10); + } + + public void addOuterShadow(float r, float dx, float dy, int color){ + if(r == 0){ r = 0.0001f; } + outerShadows.add(new Shadow(r,dx,dy,color)); + } + + public void addInnerShadow(float r, float dx, float dy, int color){ + if(r == 0){ r = 0.0001f; } + innerShadows.add(new Shadow(r,dx,dy,color)); + } + + public void clearInnerShadows(){ + innerShadows.clear(); + } + + public void clearOuterShadows(){ + outerShadows.clear(); + } + + public void setForegroundDrawable(Drawable d){ + this.foregroundDrawable = d; + } + + public Drawable getForeground(){ + return this.foregroundDrawable == null ? this.foregroundDrawable : new ColorDrawable(this.getCurrentTextColor()); + } + + + @Override + public void onDraw(Canvas canvas){ + super.onDraw(canvas); + + freeze(); + Drawable restoreBackground = this.getBackground(); + Drawable[] restoreDrawables = this.getCompoundDrawables(); + int restoreColor = this.getCurrentTextColor(); + + this.setCompoundDrawables(null, null, null, null); + + for(Shadow shadow : outerShadows){ + this.setShadowLayer(shadow.r, shadow.dx, shadow.dy, shadow.color); + super.onDraw(canvas); + } + this.setShadowLayer(0,0,0,0); + this.setTextColor(restoreColor); + + if(this.foregroundDrawable != null && this.foregroundDrawable instanceof BitmapDrawable){ + generateTempCanvas(); + super.onDraw(tempCanvas); + Paint paint = ((BitmapDrawable) this.foregroundDrawable).getPaint(); + paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP)); + this.foregroundDrawable.setBounds(canvas.getClipBounds()); + this.foregroundDrawable.draw(tempCanvas); + canvas.drawBitmap(tempBitmap, 0, 0, null); + tempCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); + } + + if(strokeColor != null){ + TextPaint paint = this.getPaint(); +// paint.setTextAlign(Paint.Align.CENTER); + paint.setStyle(Style.STROKE); + paint.setStrokeJoin(strokeJoin); + paint.setStrokeMiter(strokeMiter); + this.setTextColor(strokeColor); + paint.setStrokeWidth(strokeWidth); + super.onDraw(canvas); + paint.setStyle(Style.FILL); + this.setTextColor(restoreColor); + } + if(innerShadows.size() > 0){ + generateTempCanvas(); + TextPaint paint = this.getPaint(); + for(Shadow shadow : innerShadows){ + this.setTextColor(shadow.color); + super.onDraw(tempCanvas); + this.setTextColor(0xFF000000); + paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); + paint.setMaskFilter(new BlurMaskFilter(shadow.r, BlurMaskFilter.Blur.NORMAL)); + + tempCanvas.save(); + tempCanvas.translate(shadow.dx, shadow.dy); + super.onDraw(tempCanvas); + tempCanvas.restore(); + canvas.drawBitmap(tempBitmap, 0, 0, null); + tempCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); + + paint.setXfermode(null); + paint.setMaskFilter(null); + this.setTextColor(restoreColor); + this.setShadowLayer(0,0,0,0); + } + } + if(restoreDrawables != null){ + this.setCompoundDrawablesWithIntrinsicBounds(restoreDrawables[0], restoreDrawables[1], restoreDrawables[2], restoreDrawables[3]); + } + this.setBackgroundDrawable(restoreBackground); + this.setTextColor(restoreColor); + unfreeze(); + } + + private void generateTempCanvas(){ + String key = String.format("%dx%d", getWidth(), getHeight()); + Pair stored = canvasStore.get(key); + if(stored != null){ + tempCanvas = stored.first; + tempBitmap = stored.second; + }else{ + tempCanvas = new Canvas(); + tempBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888); + tempCanvas.setBitmap(tempBitmap); + canvasStore.put(key, new Pair(tempCanvas, tempBitmap)); + } + } + + public void freeze(){ + lockedCompoundPadding = new int[]{ + getCompoundPaddingLeft(), + getCompoundPaddingRight(), + getCompoundPaddingTop(), + getCompoundPaddingBottom() + }; + frozen = true; + } + + public void unfreeze(){ + frozen = false; + } + + + @Override + public void requestLayout(){ + if(!frozen) super.requestLayout(); + } + + @Override + public void postInvalidate(){ + if(!frozen) super.postInvalidate(); + } + + @Override + public void postInvalidate(int left, int top, int right, int bottom){ + if(!frozen) super.postInvalidate(left, top, right, bottom); + } + + @Override + public void invalidate(){ + if(!frozen) super.invalidate(); + } + + @Override + public void invalidate(Rect rect){ + if(!frozen) super.invalidate(rect); + } + + @Override + public void invalidate(int l, int t, int r, int b){ + if(!frozen) super.invalidate(l,t,r,b); + } + + @Override + public int getCompoundPaddingLeft(){ + return !frozen ? super.getCompoundPaddingLeft() : lockedCompoundPadding[0]; + } + + @Override + public int getCompoundPaddingRight(){ + return !frozen ? super.getCompoundPaddingRight() : lockedCompoundPadding[1]; + } + + @Override + public int getCompoundPaddingTop(){ + return !frozen ? super.getCompoundPaddingTop() : lockedCompoundPadding[2]; + } + + @Override + public int getCompoundPaddingBottom(){ + return !frozen ? super.getCompoundPaddingBottom() : lockedCompoundPadding[3]; + } + + public static class Shadow{ + float r; + float dx; + float dy; + int color; + public Shadow(float r, float dx, float dy, int color){ + this.r = r; + this.dx = dx; + this.dy = dy; + this.color = color; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/widget/MessageView.java b/app/src/main/java/com/chwl/app/avroom/widget/MessageView.java new file mode 100644 index 0000000..4cd9ac3 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/widget/MessageView.java @@ -0,0 +1,3592 @@ +package com.chwl.app.avroom.widget; + +import static com.chwl.core.im.custom.bean.CustomAttachment.BOOM_FIRST; +import static com.chwl.core.im.custom.bean.CustomAttachment.BOOM_SECOND_DIALOG; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_FAIRY; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_GIFT_COMPOUND; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_RED_PACKAGE; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_ROOM_ALBUM; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_ROOM_TEMPLATE; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_BOX_ME; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_CONVERT_L1; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_CONVERT_L2; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_CONVERT_L3; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_DRAW_BALL_L1; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_DRAW_BALL_L2; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_DRAW_BALL_L3; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_DRAW_GIFT_L1; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_DRAW_GIFT_L2; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_DRAW_GIFT_L3; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_DRAW_GIFT_L4; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_DRAW_GIFT_L5; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_FANS_TEAM_JOIN; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_GIFT_COMPOUND; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUPER_LUCKY_GIFT_TEMPLATE; +import static com.chwl.core.redpackage.RedPackageTypeKt.ALL_DIAMOND; +import static com.chwl.core.redpackage.RedPackageTypeKt.ALL_GIFT; +import static com.chwl.core.redpackage.RedPackageTypeKt.ROOM_DIAMOND; +import static com.chwl.core.redpackage.RedPackageTypeKt.ROOM_GIFT; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Context; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +import android.text.Editable; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.TextUtils; +import android.text.method.LinkMovementMethod; +import android.text.style.ForegroundColorSpan; +import android.util.AttributeSet; +import android.util.Log; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; +import androidx.core.content.res.ResourcesCompat; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.SimpleItemAnimator; + +import com.alibaba.fastjson2.JSON; +import com.bumptech.glide.request.target.Target; +import com.chwl.app.R; +import com.chwl.app.UIHelper; +import com.chwl.app.avroom.activity.AVRoomActivity; +import com.chwl.app.avroom.bean.LuckyBagEntity; +import com.chwl.app.avroom.dialog.RoomTeamPKResultDialog; +import com.chwl.app.avroom.room_album.UnlockRoomAlbumPhotoDialog; +import com.chwl.app.common.widget.OriginalDrawStatusClickSpan; +import com.chwl.app.photo.BigPhotoActivity; +import com.chwl.app.photo.PagerOption; +import com.chwl.app.sadmin.utils.SaAttachmentToMsgUtil; +import com.chwl.app.ui.user.activity.ShowPhotoActivity; +import com.chwl.app.ui.utils.CpUtils; +import com.chwl.app.ui.utils.ImageLoadKt; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.app.ui.utils.ImageLoadUtilsV2; +import com.chwl.app.ui.widget.DividerItemDecoration; +import com.chwl.app.ui.widget.MyItemAnimator; +import com.chwl.app.ui.widget.RecyclerViewNoViewpagerScroll; +import com.chwl.app.ui.widget.TextSpannableBuilder; +import com.chwl.app.ui.widget.UserInfoDialog; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.utils.ObjectTypeHelper; +import com.chwl.app.utils.RegexUtil; +import com.chwl.core.DemoCache; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.bean.attachmsg.RoomQueueMsgAttachment; +import com.chwl.core.decoration.car.bean.CarInfo; +import com.chwl.core.fansteam.bean.FansTeamMsgInfo; +import com.chwl.core.gift.GiftModel; +import com.chwl.core.gift.bean.BoomMsgDialogBean; +import com.chwl.core.gift.bean.GiftInfo; +import com.chwl.core.gift.bean.GiftList; +import com.chwl.core.gift.bean.GiftReceiveInfo; +import com.chwl.core.gift.bean.GiftReceiver; +import com.chwl.core.gift.bean.LuckyBagGifts; +import com.chwl.core.gift.bean.LuckyBagNoticeInfo; +import com.chwl.core.gift.bean.RoomPicScreenBean; +import com.chwl.core.gift.bean.RoomUserEnterRoomBean; +import com.chwl.core.gift.toolbox.GiftToolbox; +import com.chwl.core.helper.ImHelperUtils; +import com.chwl.core.home.event.FollowRoomEvent; +import com.chwl.core.home.model.CollectionRoomModel; +import com.chwl.core.im.custom.bean.AuctionAttachment; +import com.chwl.core.im.custom.bean.BoomMsgAttachment; +import com.chwl.core.im.custom.bean.CarveUpGoldAttachment; +import com.chwl.core.im.custom.bean.CleanScreenAttachment; +import com.chwl.core.im.custom.bean.CustomAttachment; +import com.chwl.core.im.custom.bean.DatingAttachment; +import com.chwl.core.im.custom.bean.FaceAttachment; +import com.chwl.core.im.custom.bean.FairyMsgAttachment; +import com.chwl.core.im.custom.bean.FansTeamMsgAttachment; +import com.chwl.core.im.custom.bean.GiftAttachment; +import com.chwl.core.im.custom.bean.GiftBatchAttachment; +import com.chwl.core.im.custom.bean.GiftCompoundAttachment; +import com.chwl.core.im.custom.bean.GiftCompoundMsgBean; +import com.chwl.core.im.custom.bean.JoinMiniWorldAttachment; +import com.chwl.core.im.custom.bean.JoinMiniWorldNoticeAttachment; +import com.chwl.core.im.custom.bean.MagicAllMicAttachment; +import com.chwl.core.im.custom.bean.MagicAttachment; +import com.chwl.core.im.custom.bean.MagicBatchAttachment; +import com.chwl.core.im.custom.bean.MonsterHuntingResultAttachment; +import com.chwl.core.im.custom.bean.MonsterStatusAttachment; +import com.chwl.core.im.custom.bean.MultiGiftAttachment; +import com.chwl.core.im.custom.bean.MultiLuckyGiftAttachment; +import com.chwl.core.im.custom.bean.NobleAttachment; +import com.chwl.core.im.custom.bean.RedPackageLuckyBagAttachment; +import com.chwl.core.im.custom.bean.RedPackageRoomMsgAttachment; +import com.chwl.core.im.custom.bean.RoomAlbumAttachment; +import com.chwl.core.im.custom.bean.RoomAlbumMsgInfo; +import com.chwl.core.im.custom.bean.RoomBoxPrizeAttachment; +import com.chwl.core.im.custom.bean.RoomFollowOwnerAttachment; +import com.chwl.core.im.custom.bean.RoomFollowOwnerAttachment2; +import com.chwl.core.im.custom.bean.RoomLuckySeaAttachment; +import com.chwl.core.im.custom.bean.RoomLuckySeaMsgBean; +import com.chwl.core.im.custom.bean.RoomNoticeAttachment; +import com.chwl.core.im.custom.bean.RoomPhoto; +import com.chwl.core.im.custom.bean.RoomPicScreenMsgAttachment; +import com.chwl.core.im.custom.bean.RoomReceivedLuckyGiftAttachment; +import com.chwl.core.im.custom.bean.RoomTipAttachment; +import com.chwl.core.im.custom.bean.RoomUserEnterRoomMsgAttachment; +import com.chwl.core.im.custom.bean.TarotAttachment; +import com.chwl.core.im.custom.bean.TarotMsgBean; +import com.chwl.core.im.custom.bean.TemplateMessageAttachment; +import com.chwl.core.im.custom.bean.User; +import com.chwl.core.im.custom.bean.VipMessageAttachment; +import com.chwl.core.im.custom.bean.WelcomeAttachment; +import com.chwl.core.level.UserLevelResourceType; +import com.chwl.core.magic.MagicModel; +import com.chwl.core.magic.bean.MagicInfo; +import com.chwl.core.magic.bean.MagicMultiReceiverInfo; +import com.chwl.core.magic.bean.MagicReceivedInfo; +import com.chwl.core.magic.bean.MagicReceiver; +import com.chwl.core.magic.bean.MultiMagicReceivedInfo; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.manager.IMNetEaseManager; +import com.chwl.core.miniworld.bean.MiniWorldInWorldInfo; +import com.chwl.core.monsterhunting.bean.MonsterDataBean; +import com.chwl.core.monsterhunting.bean.MonsterHuntingResult; +import com.chwl.core.noble.NobleUtil; +import com.chwl.core.noble.bean.NobleInfo; +import com.chwl.core.praise.PraiseModel; +import com.chwl.core.redpackage.bean.RedEnvelopeRoomMsg; +import com.chwl.core.redpackage.bean.RedPackageLuckyBag; +import com.chwl.core.room.anotherroompk.ShowUserInfoDialogEvent; +import com.chwl.core.room.bean.DatingNotifyInfo; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.core.room.bean.RoomMessageViewNoticeInfo; +import com.chwl.core.room.bean.WelcomeInfo; +import com.chwl.core.room.face.DynamicFaceModel; +import com.chwl.core.room.face.FaceInfo; +import com.chwl.core.room.face.FaceReceiveInfo; +import com.chwl.core.room.model.AvRoomModel; +import com.chwl.core.room.pk.attachment.RoomPkAttachment; +import com.chwl.core.room.pk.bean.PKTeamInfo; +import com.chwl.core.room.pk.bean.RoomPKInvitedUpMicMember; +import com.chwl.core.room.pk.bean.RoomPkData; +import com.chwl.core.room.queuing_mic.attachment.QueuingMicAttachment; +import com.chwl.core.room.queuing_mic.bean.QueuingMicInfo; +import com.chwl.core.treasurefairy.bean.FairyMsgInfoBean; +import com.chwl.core.user.UserModel; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.core.utils.ExtensionUtil; +import com.chwl.core.utils.LogUtils; +import com.chwl.core.utils.extension.StringExtensionKt; +import com.chwl.core.utils.myutil.MyJsonUtils; +import com.chwl.core.utils.net.DontWarnObserver; +import com.chwl.core.utils.net.RxHelper; +import com.chwl.core.vip.bean.VipMessageInfo; +import com.chwl.library.common.util.OtherExtKt; +import com.chwl.library.common.util.Utils; +import com.chwl.library.rxbus.RxBus; +import com.chwl.library.utils.FormatUtils; +import com.chwl.library.utils.JavaUtil; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; +import com.chwl.library.utils.SizeUtils; +import com.example.lib_utils.UiUtils; +import com.example.lib_utils.ktx.ResourcesKtxKt; +import com.example.lib_utils.spannable.SpannableTextBuilder; +import com.netease.nim.uikit.business.uinfo.UserInfoHelper; +import com.netease.nim.uikit.common.ui.span.RadiusBackgroundSpan; +import com.netease.nim.uikit.common.util.log.LogUtil; +import com.netease.nim.uikit.common.util.sys.ScreenUtil; +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage; +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessageExtension; +import com.netease.nimlib.sdk.chatroom.model.ChatRoomNotificationAttachment; +import com.netease.nimlib.sdk.msg.attachment.MsgAttachment; +import com.netease.nimlib.sdk.msg.constant.MsgTypeEnum; +import com.netease.nimlib.sdk.msg.constant.NotificationType; +import com.netease.nimlib.sdk.msg.model.IMMessage; + +import org.greenrobot.eventbus.EventBus; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import io.reactivex.Single; +import io.reactivex.SingleSource; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.functions.Consumer; +import io.reactivex.functions.Function; +import kotlin.Unit; +import kotlin.jvm.functions.Function0; + +/** + * 直播間消息界面 + * + * @author xiaoyu + */ +public class MessageView extends FrameLayout { + + private static final String TAG = "MessageView"; + private final static int MAX_MESSAGE_SIZE = 2000;//公屏最多展示條數 + private final static int BLOCK_MAX_MESSAGE_SIZE = MAX_MESSAGE_SIZE * 3 / 2;//在查看消息停住的時候 最多消息條數. + private static final int LOAD_MESSAGE_COUNT = 10; + private final int textColor = 0x80ffffff; + private final List atMessages = new ArrayList<>(); + private final List allMessages = new LinkedList<>(); + private final List giftMessages = new LinkedList<>(); + private final List chatMessages = new LinkedList<>(); + private RecyclerView messageListView; + private TextView tvBottomTip; + private TextView tvAtTip; + private MessageAdapter mMessageAdapter; + private LinearLayoutManager layoutManger; + private Disposable disposable; + private int paddingWidth; + private int paddingHeight; + private int whiteColor; + private int greyColor; + private int roomTipNickColor; + private int roomTipColor; + private int roomBlueColor; + private int badgeWidth; + private int badgeHeight; + private int sysIconHeight; + private int smallFace; + private int bigFace; + private int expLevelWidth; + private int expLevelHeight; + private int giftLength; + private int boomWidth; + private int boomHeight; + private volatile boolean needAutoScroll = true;//是否自動滾動到底部 + private Consumer clickConsumer; + private OnClick onClick; + + private OnMsgLongClickListener onLongClickListener; + private TemplateMessageAdapter templateMessageAdapter; + + //分类 + private String mMsgType; + + public void setMsgType(String msgType) { + mMsgType = msgType; + + if (isAll()) { + mMessageAdapter.setData(allMessages); + } else if (isGift()) { + mMessageAdapter.setData(giftMessages); + } else if (isChat()) { + mMessageAdapter.setData(chatMessages); + } + checkShowAtTip(); + mMessageAdapter.notifyDataSetChanged(); + messageListView.post(() -> { + needAutoScroll = true; + if (mMessageAdapter.getItemCount() - 1 >= 0) { + messageListView.scrollToPosition(mMessageAdapter.getItemCount() - 1); + } + }); + } + + private boolean isAll() { + return mMsgType.equals(ResUtil.getString(R.string.all)); + } + + private boolean isChat() { + return mMsgType.equals(ResUtil.getString(R.string.send_msg)); + } + + private boolean isGift() { + return mMsgType.equals(ResUtil.getString(R.string.send_gift_tab_title)); + } + + //todo do 消息类型分类 需要进一步判断 + private boolean isChatMsg(ChatRoomMessage msg) { + CustomAttachment attachment = (CustomAttachment) msg.getAttachment(); + if (attachment == null) { + return (msg.getMsgType() == MsgTypeEnum.text); + } else { + int first = attachment.getFirst(); + int second = attachment.getSecond(); + return (msg.getMsgType() == MsgTypeEnum.text) || (first == CustomAttachment.ROOM_PIC_SCREEN_FIRST && second == CustomAttachment.ROOM_PIC_SCREEN_SECOND); + } + } + + //todo do 消息类型分类 需要进一步判断 + private boolean isGiftMsg(ChatRoomMessage msg) { + if (msg.getMsgType() == MsgTypeEnum.custom) { + CustomAttachment attachment = (CustomAttachment) msg.getAttachment(); + if (attachment == null) { + return false; + } else { + int first = attachment.getFirst(); + int second = attachment.getSecond(); + return (first != BOOM_FIRST + && first != CustomAttachment.CUSTOM_MSG_HEADER_TYPE_AUCTION + && first != CustomAttachment.CUSTOM_MSG_HEADER_TYPE_ROOM_TIP + && first != CustomAttachment.CUSTOM_MSG_HEADER_TYPE_FACE + && first != CustomAttachment.CUSTOM_MESS_HEAD_NOBLE + && first != CustomAttachment.CUSTOM_MSG_HEADER_TYPE_QUEUE + && first != CustomAttachment.CUSTOM_MSG_HEADER_TYPE_SUPER_ADMIN + && first != CustomAttachment.CUSTOM_MSG_HEADER_TYPE_KICK_MIC + && first != CustomAttachment.CUSTOM_MSG_UPDATE_ROOM_INFO + && first != CustomAttachment.CUSTOM_MSG_QUEUING_MIC + && first != CustomAttachment.CUSTOM_MESS_HEAD_ROOM_PK + && first != CustomAttachment.CUSTOM_MSG_SIGN_IN + && first != CustomAttachment.CUSTOM_MSG_MINI_WORLD + && first != CustomAttachment.CUSTOM_MSG_HEADER_TYPE_PUBLIC_SCREEN + && first != CustomAttachment.CUSTOM_MSG_HEADER_TYPE_FOLLOW_ROOM + && first != CustomAttachment.CUSTOM_MSG_DATING + && first != CustomAttachment.CUSTOM_MSG_VIP + && first != CustomAttachment.CUSTOM_MSG_FANS_TEAM + && first != CustomAttachment.CUSTOM_MSG_ROOM_ALBUM + && first != CustomAttachment.CUSTOM_MSG_ROOM_TEMPLATE + && first != CustomAttachment.ROOM_PIC_SCREEN_FIRST + ); + } + } else { + return false; + } + } + + private boolean isCurrType(ChatRoomMessage msg) { + boolean isType = false; + if (isAll()) { + isType = true; + } else if (isChat()) { + isType = isChatMsg(msg); + } else if (isGift()) { + isType = isGiftMsg(msg); + } + return isType; + } + + public MessageView(Context context) { + this(context, null); + } + + public MessageView(Context context, AttributeSet attr) { + this(context, attr, 0); + } + + public MessageView(Context context, AttributeSet attr, int i) { + super(context, attr, i); + init(context); + } + + public void setOnLongClickListener(OnMsgLongClickListener onLongClickListener) { + this.onLongClickListener = onLongClickListener; + } + + public void setClickConsumer(Consumer clickConsumer) { + this.clickConsumer = clickConsumer; + } + + public void setOnClick(OnClick onClick) { + this.onClick = onClick; + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + List tmpList = AvRoomDataManager.get().getChatRoomMessages(); + if (!ListUtils.isListEmpty(tmpList)) { + this.allMessages.addAll(tmpList); + addMsgByType(tmpList, false); + } + if (mMessageAdapter.getItemCount() - 1 >= 0) { + messageListView.scrollToPosition(mMessageAdapter.getItemCount() - 1); + } + disposable = AvRoomDataManager.get().getChatRoomMsgProcessor() + .subscribe(this::onCurrentRoomReceiveNewMsg); + } + + private void addMsgByType(List list, boolean isHistory) { + if (OtherExtKt.isVerify(list)) { + for (ChatRoomMessage chatRoomMessage : list) { + if (!isHistory) { + if (isChatMsg(chatRoomMessage)) { + chatMessages.add(chatRoomMessage); + } else if (isGiftMsg(chatRoomMessage)) { + giftMessages.add(chatRoomMessage); + } + } else { + if (isChatMsg(chatRoomMessage)) { + chatMessages.add(!chatMessages.isEmpty() ? 1 : 0, chatRoomMessage); + } else if (isGiftMsg(chatRoomMessage)) { + giftMessages.add(!giftMessages.isEmpty() ? 1 : 0, chatRoomMessage); + } + } + } + } + } + + private void addMsgByType(ChatRoomMessage chatRoomMessage, boolean isHistory) { + if (!isHistory) { + if (isChatMsg(chatRoomMessage)) { + chatMessages.add(chatRoomMessage); + } else if (isGiftMsg(chatRoomMessage)) { + giftMessages.add(chatRoomMessage); + } + } else { + if (isChatMsg(chatRoomMessage)) { + chatMessages.add(!chatMessages.isEmpty() ? 1 : 0, chatRoomMessage); + } else if (isGiftMsg(chatRoomMessage)) { + giftMessages.add(!giftMessages.isEmpty() ? 1 : 0, chatRoomMessage); + } + } + } + + + @Override + protected void onDetachedFromWindow() { + if (disposable != null) disposable.dispose(); + super.onDetachedFromWindow(); + } + + @SuppressLint("ClickableViewAccessibility") + private void init(Context context) { + whiteColor = ContextCompat.getColor(context, R.color.white); + greyColor = ContextCompat.getColor(context, R.color.white_transparent_50); + roomTipNickColor = ContextCompat.getColor(context, R.color.color_FEE057); + roomTipColor = ContextCompat.getColor(context, R.color.color_FEE057); + roomBlueColor = ContextCompat.getColor(context, R.color.color_00EAFF); + paddingWidth = Utils.dip2px(context, 11); + paddingHeight = Utils.dip2px(context, 6); + badgeWidth = Utils.dip2px(context, 15); + badgeHeight = Utils.dip2px(context, 15); + sysIconHeight = Utils.dip2px(context, 14); + smallFace = Utils.dip2px(context, 22); + bigFace = Utils.dip2px(context, 30); + //經驗等級圖片後臺已經更換尺寸了,公屏同步下,尺寸是36:18 + expLevelHeight = Utils.dip2px(context, 18); + expLevelWidth = expLevelHeight * 36 / 18;//expLevelHeight * 114 / 45 + giftLength = Utils.dip2px(context, 35); + boomWidth = Utils.dip2px(context, 41); + boomHeight = Utils.dip2px(context, 60); + // 內容區域 + layoutManger = new LinearLayoutManager(context, RecyclerView.VERTICAL, false); + FrameLayout.LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + messageListView = new RecyclerViewNoViewpagerScroll(context); + messageListView.setLayoutParams(params); + messageListView.setFadingEdgeLength(60); + messageListView.setVerticalFadingEdgeEnabled(true); + messageListView.setOverScrollMode(OVER_SCROLL_NEVER); + messageListView.setHorizontalScrollBarEnabled(false); + addView(messageListView); + messageListView.setLayoutManager(layoutManger); + messageListView.addItemDecoration(new DividerItemDecoration(context, layoutManger.getOrientation(), 16, R.color.transparent)); + mMessageAdapter = new MessageAdapter(getContext()); + mMessageAdapter.setData(allMessages); + messageListView.setAdapter(mMessageAdapter); + messageListView.setItemAnimator(new MyItemAnimator()); + messageListView.getItemAnimator().setAddDuration(0); + messageListView.getItemAnimator().setChangeDuration(0); + messageListView.getItemAnimator().setMoveDuration(0); + messageListView.getItemAnimator().setRemoveDuration(0); + ((SimpleItemAnimator) messageListView.getItemAnimator()).setSupportsChangeAnimations(false); + + // 底部有新消息 + tvBottomTip = new TextView(context); + FrameLayout.LayoutParams params1 = new LayoutParams( + Utils.dip2px(context, 115F), Utils.dip2px(context, 27)); + params1.gravity = Gravity.BOTTOM; + params1.leftMargin = UIUtil.getScreenWidth(context) / 2 - UIUtil.dip2px(context, 115 / 2); + tvBottomTip.setBackgroundResource(R.drawable.bg_messge_view_bottom_tip); + tvBottomTip.setGravity(Gravity.CENTER); + tvBottomTip.setText(context.getString(R.string.message_view_bottom_tip)); + tvBottomTip.setTextColor(context.getResources().getColor(R.color.appColor)); + tvBottomTip.setLayoutParams(params1); + tvBottomTip.setVisibility(GONE); + tvBottomTip.setOnClickListener(v -> { + tvBottomTip.setVisibility(GONE); + needAutoScroll = true; + if (mMessageAdapter.getItemCount() - 1 >= 0) { + messageListView.smoothScrollToPosition(mMessageAdapter.getItemCount() - 1); + } + + }); + addView(tvBottomTip); + + //有人@我 + tvAtTip = new TextView(context); + FrameLayout.LayoutParams params2 = new LayoutParams( + Utils.dip2px(context, 115F), Utils.dip2px(context, 27)); + params2.gravity = Gravity.BOTTOM; + params2.leftMargin = UIUtil.getScreenWidth(context) / 2 - UIUtil.dip2px(context, 115 / 2); + tvAtTip.setBackgroundResource(R.drawable.bg_messge_view_bottom_tip); + tvAtTip.setGravity(Gravity.CENTER); + tvAtTip.setText(context.getString(R.string.message_view_bottom_tip)); + tvAtTip.setTextColor(context.getResources().getColor(R.color.color_FD85C9)); + tvAtTip.setLayoutParams(params2); + tvAtTip.setVisibility(GONE); + tvAtTip.setOnClickListener(v -> { + if (!atMessages.isEmpty()) { + int scrollIndex = -1; + + if (isAll()) { + scrollIndex = allMessages.indexOf(atMessages.remove(0)); + } else if (isChat()) { + scrollIndex = chatMessages.indexOf(atMessages.remove(0)); + } + + if (scrollIndex != -1 && scrollIndex < mMessageAdapter.getItemCount()) { + messageListView.smoothScrollToPosition(scrollIndex); + } + } + needAutoScroll = false; + checkShowAtTip(); + }); + addView(tvAtTip); + + messageListView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + + } + + @Override + public void onScrollStateChanged(final RecyclerView recyclerView, int newState) { + super.onScrollStateChanged(recyclerView, newState); + if (newState == RecyclerView.SCROLL_STATE_DRAGGING) { +// Logger.e(TAG, "onScrollStateChanged: SCROLL_STATE_DRAGGING"); + needAutoScroll = false; + } + if (newState == RecyclerView.SCROLL_STATE_IDLE) { +// Logger.e(TAG, "onScrollStateChanged: SCROLL_STATE_IDLE"); + + int lastVisibleItemPosition = layoutManger.findLastVisibleItemPosition(); + + if (lastVisibleItemPosition == RecyclerView.NO_POSITION) { +// Logger.e(TAG, "lastCompletelyVisibleItemPosition : RecyclerView.NO_POSITION"); + needAutoScroll = true; + } else if (!atMessages.isEmpty() && atMessages.remove(allMessages.get(lastVisibleItemPosition))) { + checkShowAtTip(); + } +// Log.e(TAG, "lastVisibleItemPosition:" + lastVisibleItemPosition +// + " mMessageAdapter.getItemCount()-1:" + (recyclerView.getAdapter().getItemCount()-1) +// + " dis:"+ (lastVisibleItemPosition-(recyclerView.getAdapter().getItemCount()-1))); + if (lastVisibleItemPosition >= recyclerView.getAdapter().getItemCount() - 3) { + //最後一個顯示出來了 +// Logger.e(TAG, ResUtil.getString(R.string.avroom_widget_messageview_01)); + needAutoScroll = true; + tvBottomTip.setVisibility(GONE); + keepSizeUnderLimit(); + } else { +// Logger.e(TAG, ResUtil.getString(R.string.avroom_widget_messageview_02)); +// needAutoScroll = false; + } + } + } + }); + + } + + private TemplateMessageAdapter getTemplateMessageAdapter() { + if (templateMessageAdapter == null) { + templateMessageAdapter = new TemplateMessageAdapter(uid -> { + if (clickConsumer != null) { + Single.just(String.valueOf(uid)).subscribe(clickConsumer); + } + }); + } + return templateMessageAdapter; + } + + public void onCurrentRoomReceiveNewMsg(List messages) { + if (messages == null) return; + if (messages.size() == 1) { + addMessages(messages.get(0)); + } else { + addHistoryMessages(messages); + } + } + + /** + * 添加公屏消息請使用 {@link AvRoomDataManager#addChatRoomMessage(ChatRoomMessage)} + */ + private void addMessages(ChatRoomMessage msg) { + if (msg == null) return; + allMessages.add(msg); + //通知adapter 刷新 + addMsgByType(msg, false); + if (mMessageAdapter.getItemCount() - 1 >= 0 && isCurrType(msg)) { + mMessageAdapter.notifyItemInserted(mMessageAdapter.getItemCount() - 1); + } + showTipsOrScrollToBottom(isCurrType(msg)); + checkAtMe(msg, false); + keepSizeUnderLimit(); + } + + private void addHistoryMessages(List messages) { + allMessages.addAll(allMessages.size() > 0 ? 1 : 0, messages); + mMessageAdapter.notifyDataSetChanged(); + if (mMessageAdapter.getItemCount() - 1 >= 0) { + messageListView.scrollToPosition(mMessageAdapter.getItemCount() - 1); + } + for (ChatRoomMessage message : messages) { + addMsgByType(message, true); + checkAtMe(message, true); + } + } + + private void keepSizeUnderLimit() { + while (allMessages.size() > MAX_MESSAGE_SIZE) { + Log.i("keepSizeUnderLimit", "size" + allMessages.size()); + ChatRoomMessage message = allMessages.remove(0); + if (isAll()) { + if (atMessages.remove(message)) { + checkShowAtTip(); + } + } + mMessageAdapter.notifyItemRemoved(0); + } + + while (chatMessages.size() > MAX_MESSAGE_SIZE) { + chatMessages.remove(0); + if (isChat()) { + mMessageAdapter.notifyItemRemoved(0); + } + } + + while (giftMessages.size() > MAX_MESSAGE_SIZE) { + giftMessages.remove(0); + if (isGift()) { + mMessageAdapter.notifyItemRemoved(0); + } + } + } + + private void checkShowAtTip() { + tvAtTip.setText(getContext().getString(R.string.message_at_tip, atMessages.size())); + tvAtTip.setVisibility(atMessages.size() == 0 ? GONE : VISIBLE); + } + + private void checkAtMe(ChatRoomMessage msg, boolean history) { + if (msg.getMsgType() != MsgTypeEnum.text) return; + List atUids = ExtensionUtil.getListExtension(msg, UserInfo.AT_UIDS); + List atNames = ExtensionUtil.getListExtension(msg, UserInfo.AT_NAMES); + if (!ListUtils.isListEmpty(atUids) && !ListUtils.isListEmpty(atNames)) { + for (int i = 0; i < atUids.size(); i++) { + String uid = atUids.get(i); + // 只有當被 @ 人的數組中包含自己的時候才會去變色 + if (Objects.equals(uid, String.valueOf(AuthModel.get().getCurrentUid()))) { + Map atMap = DemoCache.readAtMsgUuid(); + if (atMap == null || !atMap.containsKey(msg.getUuid())) { + if (!atMessages.contains(msg) && (!needAutoScroll || history)) { + atMessages.add(msg); + checkShowAtTip(); + } + DemoCache.saveAtMsgUuid(msg.getUuid()); + } + } + } + } + } + + private void showTipsOrScrollToBottom(boolean needScroll) { + if (!needAutoScroll) { + tvBottomTip.setVisibility(VISIBLE); + //超過某值後自動滾動下去 + if (mMessageAdapter.getItemCount() > BLOCK_MAX_MESSAGE_SIZE) { + messageListView.smoothScrollToPosition(mMessageAdapter.getItemCount() - 1); + } + return; + } + + if (needScroll) { + if (mMessageAdapter.getItemCount() - 1 >= 0) { + messageListView.smoothScrollToPosition(mMessageAdapter.getItemCount() - 1); + } + } + + } + + public void release() { + + } + + + /** + * 修改關註狀態 + * + * @param position + * @param b + */ + public void changeFollowStatus(int position, boolean b) { + ChatRoomMessage chatRoomMessage = allMessages.get(position); + if (!(chatRoomMessage.getAttachment() instanceof RoomFollowOwnerAttachment)) { + return; + } + RoomFollowOwnerAttachment roomFollowOwnerAttachment = (RoomFollowOwnerAttachment) chatRoomMessage.getAttachment(); + roomFollowOwnerAttachment.setFollow(true); + mMessageAdapter.notifyItemChanged(position); + + } + + /** + * 修改加入話題的狀態 + * + * @param position + * @param b + */ + public void changeJoinMiniWorldStatus(int position, boolean b) { + ChatRoomMessage chatRoomMessage = allMessages.get(position); + if (!(chatRoomMessage.getAttachment() instanceof JoinMiniWorldAttachment)) { + return; + } + JoinMiniWorldAttachment joinMiniWorldAttachment = (JoinMiniWorldAttachment) chatRoomMessage.getAttachment(); +// joinMiniWorldAttachment.setJoined(true); + mMessageAdapter.notifyItemChanged(position); + } + + public void clear() { + if (mMessageAdapter != null) { + allMessages.clear(); + chatMessages.clear(); + giftMessages.clear(); + mMessageAdapter.notifyDataSetChanged(); + } + if (tvBottomTip != null) { + needAutoScroll = true; + tvBottomTip.setVisibility(GONE); + } + } + + public void setNeedAutoScroll(boolean needAutoScroll) { + this.needAutoScroll = needAutoScroll; + } + + public RecyclerView getMessageListView() { + return messageListView; + } + + public interface OnClick { + /** + * 點擊關註 + * + * @param position + */ + void onFollowClick(int position); + + void onJoinMiniWorldClick(int position); + + /** + * 公屏查看公告 + */ + void onShowRoomIntroduction(); + + } + + + private class MessageAdapter extends RecyclerView.Adapter implements OnClickListener { + + private Context mContext; + private List data; + + public MessageAdapter(Context mContext) { + this.mContext = mContext; + } + + public void setData(List data) { + this.data = data; + } + + @Override + public int getItemViewType(int position) { + ChatRoomMessage chatRoomMessage = data.get(position); + if (chatRoomMessage.getMsgType() == MsgTypeEnum.custom) { + MsgAttachment attachment = chatRoomMessage.getAttachment(); + if (attachment instanceof CustomAttachment) { + if (((CustomAttachment) attachment).getFirst() == CustomAttachment.CUSTOM_MSG_ROOM_ALBUM) { + return CustomAttachment.CUSTOM_MSG_ROOM_ALBUM; + }if (((CustomAttachment) attachment).getFirst() == CustomAttachment.CUSTOM_MSG_RED_PACKAGE) { + return CustomAttachment.CUSTOM_MSG_RED_PACKAGE; + }if (((CustomAttachment) attachment).getFirst() == CustomAttachment.ROOM_PIC_SCREEN_FIRST) { + if (((CustomAttachment) attachment).getSecond() == CustomAttachment.ROOM_PIC_SCREEN_SECOND) { + return CustomAttachment.ROOM_PIC_SCREEN_SECOND; + }else if (((CustomAttachment) attachment).getSecond() == CustomAttachment.ROOM_MSG_USER_ENTER_ROOM) { + return CustomAttachment.ROOM_MSG_USER_ENTER_ROOM; + } + } + } + } + + return super.getItemViewType(position); + } + + @Override + public MessageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + if (viewType == CustomAttachment.CUSTOM_MSG_ROOM_ALBUM) { + return new MessageViewHolder(LayoutInflater.from(parent.getContext()) + .inflate(R.layout.layout_msg_view_holder_room_album, parent, false)); + + } + + if (viewType == CustomAttachment.CUSTOM_MSG_RED_PACKAGE) { + return new MessageViewHolder(LayoutInflater.from(parent.getContext()) + .inflate(R.layout.layout_msg_view_holder_room_lucky_bag, parent, false)); + + } + + if (viewType == CustomAttachment.ROOM_PIC_SCREEN_SECOND) { + return new MessageViewHolder(LayoutInflater.from(parent.getContext()) + .inflate(R.layout.layout_msg_view_holder_room_pic_screen, parent, false)); + + } + + if (viewType == CustomAttachment.ROOM_MSG_USER_ENTER_ROOM) { + View inflate = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_msg_view_holder_room_user_enter, parent, false); + View cpTv = inflate.findViewById(R.id.cpTv); + OtherExtKt.postSafe(cpTv, (Function0) () -> { + //262:60 + double wh = 60.0 / 262.0; + int height = (int) (cpTv.getWidth() * wh); + OtherExtKt.setViewWH(cpTv,cpTv.getWidth(),height,false); + return null; + }); + return new MessageViewHolder(inflate); + + } + + return new MessageViewHolder(LayoutInflater.from(parent.getContext()) + .inflate(R.layout.list_item_chatrrom_msg, parent, false)); + } + + @Override + public void onBindViewHolder(MessageViewHolder holder, int position) { + convert(holder, data.get(position)); + } + + @Override + public int getItemCount() { + return data.size(); + } + + protected void convert(MessageViewHolder baseViewHolder, ChatRoomMessage chatRoomMessage) { + if (chatRoomMessage == null) return; + TextView tvContent = baseViewHolder.tvContent; + if (tvContent != null) { + tvContent.setLineSpacing(0, 1); + tvContent.setTextColor(Color.WHITE); + tvContent.setOnClickListener(this); + tvContent.setOnLongClickListener(null); + tvContent.setTag(chatRoomMessage); + tvContent.setGravity(Gravity.START | Gravity.CENTER_VERTICAL); + if (UiUtils.INSTANCE.isRtl(tvContent.getContext())) { + tvContent.setTextDirection(View.TEXT_DIRECTION_RTL); + } + clearBackground(tvContent); + } + try { + if (chatRoomMessage.getMsgType() == MsgTypeEnum.tip) { + String contentText = chatRoomMessage.getContent(); + // 房間通告 + if (ResUtil.getString(R.string.avroom_widget_messageview_03).equals(contentText)) { + setUpdateGiftEffectMsg(tvContent); + } else if (ResUtil.getString(R.string.yizhuan_xchat_android_constants_xchatconstants_08).equals(contentText) || contentText.contains(IMNetEaseManager.ROOM_INTRO_TAG)) { + tvContent.setTextColor(ContextCompat.getColor(mContext, R.color.white)); + tvContent.setText(contentText); + } else if (ResUtil.getString(R.string.yizhuan_xchat_android_constants_xchatconstants_09).equals(contentText) || + contentText.contains(ResUtil.getString(R.string.yizhuan_xchat_android_constants_xchatconstants_011)) || + contentText.contains(ResUtil.getString(R.string.yizhuan_xchat_android_constants_xchatconstants_010)) || + contentText.contains(ResUtil.getString(R.string.yizhuan_xchat_android_constants_xchatconstants_012))) { + //相親模式提示文案用特殊的顏色 + tvContent.setTextColor(ContextCompat.getColor(mContext, R.color.color_fe5d7f)); + tvContent.setText(contentText); + } else { + tvContent.setTextColor(ContextCompat.getColor(mContext, R.color.color_white)); + tvContent.setText(chatRoomMessage.getContent()); + tvContent.setBackgroundResource(R.drawable.shape_room_message_tip_bg); + } + } else if (chatRoomMessage.getMsgType() == MsgTypeEnum.text) { + setMsgText(chatRoomMessage, tvContent); + setVIPMessageBackground(chatRoomMessage, tvContent); + } else if (chatRoomMessage.getMsgType() == MsgTypeEnum.notification) { + // 加上勛章 +// setMsgNotification(chatRoomMessage, tvContent, baseViewHolder.getAdapterPosition()); +// setVIPMessageBackground(chatRoomMessage, tvContent); + } else if (chatRoomMessage.getMsgType() == MsgTypeEnum.custom) { + CustomAttachment attachment = (CustomAttachment) chatRoomMessage.getAttachment(); + int first = attachment.getFirst(); + int second = attachment.getSecond(); + if (first == CustomAttachment.CUSTOM_MSG_HEADER_TYPE_AUCTION) { + setMsgAuction(chatRoomMessage, tvContent, attachment); + } else if (first == CustomAttachment.CUSTOM_MSG_HEADER_TYPE_ROOM_TIP) { + setMsgRoomTip(tvContent, (RoomTipAttachment) attachment, chatRoomMessage); + } else if (first == CustomAttachment.CUSTOM_MSG_HEADER_TYPE_GIFT) { + setVIPMessageBackground(chatRoomMessage, tvContent); + if (second == CustomAttachment.CUSTOM_MSG_SUB_TYPE_SEND_GIFT) { + // 加上勛章 + setMsgHeaderGift(tvContent, (GiftAttachment) attachment, chatRoomMessage); + } else if (second == CustomAttachment.CUSTOM_MSG_SUB_TYPE_SEND_LUCKY_GIFT) { + setMsgBatchLuckyBagGift(tvContent, (MultiLuckyGiftAttachment) attachment, chatRoomMessage); + } + } else if (first == CustomAttachment.CUSTOM_MSG_HEADER_TYPE_MULTI_GIFT) { + if (second == CustomAttachment.CUSTOM_MSG_SUB_TYPE_SEND_MULTI_GIFT) { + // 加上勛章 + setMsgMultiGift(tvContent, (MultiGiftAttachment) attachment, chatRoomMessage); + } else if (second == CustomAttachment.CUSTOM_MSG_SUB_TYPE_SEND_ALL_MIC_LUCKY_GIFT) { + //福袋禮物公屏 + setMsgAllMicLuckyBagGift(tvContent, (MultiLuckyGiftAttachment) attachment, chatRoomMessage); + } else if (second == CustomAttachment.CUSTOM_MSG_SUB_TYPE_BATCH_SEND_GIFT) { + setMsgBatchGift(tvContent, (GiftBatchAttachment) attachment, chatRoomMessage); + } else if (second == CustomAttachment.CUSTOM_MSG_SUB_TYPE_SEND_MULTI_LUCK_GIFT) { + setMsgBatchLuckyBagGift(tvContent, (MultiLuckyGiftAttachment) attachment, chatRoomMessage); + } + setVIPMessageBackground(chatRoomMessage, tvContent); + } else if (first == CustomAttachment.CUSTOM_MSG_HEADER_TYPE_FACE) { + tvContent.setLineSpacing(Utils.dip2px(mContext, 6), 1); + // 加上勛章 + setMsgFace(tvContent, (FaceAttachment) attachment, chatRoomMessage); + // 設置貴族氣泡 + List faceReceiveInfos = ((FaceAttachment) attachment).getFaceReceiveInfos(); + if (faceReceiveInfos.size() == 1 && chatRoomMessage.getFromAccount().equals(String.valueOf(faceReceiveInfos.get(0).getUid()))) + setVIPMessageBackground(chatRoomMessage, tvContent); + } else if (first == CustomAttachment.CUSTOM_MESS_HEAD_NOBLE) { + // 開通或續費貴族通知 + setMsgNobleOpenOrRenewText(chatRoomMessage, tvContent); + } else if (first == CustomAttachment.CUSTOM_MSG_HEADER_TYPE_SEND_MAGIC) { + if (second == CustomAttachment.CUSTOM_MSG_SUB_TYPE_SEND_SINGLE_MAGIC) { + setSingleMagicMsg(tvContent, (MagicAttachment) attachment, chatRoomMessage); + } else if (second == CustomAttachment.CUSTOM_MSG_SUB_TYPE_SEND_MULTI_MAGIC) { + setAllMicMagicMsg(tvContent, (MagicAllMicAttachment) attachment, chatRoomMessage); + } else if (second == CustomAttachment.CUSTOM_MSG_SUB_TYPE_BATCH_SEND_MAGIC) { + setMsgBatchMagic(tvContent, (MagicBatchAttachment) attachment, chatRoomMessage); + } + setVIPMessageBackground(chatRoomMessage, tvContent); + } else if (first == CustomAttachment.CUSTOM_MSG_HEADER_TYPE_QUEUE) { + if (second == CustomAttachment.CUSTOM_MSG_HEADER_TYPE_QUEUE_INVITE || TextUtils.isEmpty(((RoomQueueMsgAttachment) attachment).handleNick)) { + if (AvRoomDataManager.get().isQueuingMicro()) { + setInviteUpMicMsg(tvContent, (RoomQueueMsgAttachment) attachment); + } else { + tvContent.setVisibility(GONE); + } + } else { + setKickMsg(tvContent, (RoomQueueMsgAttachment) attachment); + } + } else if (first == CustomAttachment.CUSTOM_MSG_HEADER_TYPE_SUPER_ADMIN) { + //超管 + CharSequence charSequence = SaAttachmentToMsgUtil.formatSuperAdminInfo(attachment, + tvContent, greyColor, roomTipColor); + if (charSequence != null) { + tvContent.setText(charSequence); + } + } else if (first == CustomAttachment.CUSTOM_MSG_HEADER_TYPE_KICK_MIC) { + if (second == CustomAttachment.CUSTOM_MSG_SUB_TYPE_SEND_KICK_ROOM) { + setKickRoomMsg(tvContent, (RoomQueueMsgAttachment) attachment); + } else if (second == CustomAttachment.CUSTOM_MSG_SUB_TYPE_SEND_ADD_BLACK) { + setAddBlackMsg(tvContent, (RoomQueueMsgAttachment) attachment); + } + } else if (first == CustomAttachment.CUSTOM_MSG_HEADER_TYPE_MONSTER_HUNTING) { + switch (second) { + case CustomAttachment.CUSTOM_MSG_SUB_TYPE_MONSTER_HUNTING: + MonsterDataBean dataBean = ((MonsterStatusAttachment) attachment).getDataBean(); + setMonsterNotifyMessage(tvContent, dataBean.getNotifyMessage()); + break; + case CustomAttachment.CUSTOM_NOTI_SUB_GAME_RESULT: + MonsterHuntingResult result = ((MonsterHuntingResultAttachment) attachment).getResult(); + setMonsterNotifyMessage(tvContent, result.getMonster().getNotifyMessage()); + break; + } + } else if (first == CustomAttachment.CUSTOM_MSG_UPDATE_ROOM_INFO) { + if (second == CustomAttachment.CUSTOM_MSG_UPDATE_ROOM_INFO_AUDIO) { + setUpdateAudioMsg(tvContent); + } else if (second == CustomAttachment.CUSTOM_MSG_UPDATE_ROOM_INFO_GIFT) { + setUpdateGiftEffectMsg(tvContent); + } else if (second == CustomAttachment.CUSTOM_MSG_UPDATE_ROOM_INFO_CLOSE_SCREEN) { + String content = chatRoomMessage.getContent(); + setUpdateScreenMsg(tvContent, content); + } else if (second == CustomAttachment.CUSTOM_MSG_UPDATE_ROOM_INFO_NOTICE) { + setUpdateRoomPureModeMsg(tvContent, chatRoomMessage); + } else if (second == CustomAttachment.CUSTOM_MSG_UPDATE_ROOM_INFO_CLEAN_SCREEN) { + setCleanScreenMsg(tvContent, chatRoomMessage); + } + } else if (first == CustomAttachment.CUSTOM_MSG_DRAGON_BAR) { + if (second == CustomAttachment.CUSTOM_MSG_DRAGON_BAR_END) { + setDragonBarMsg(chatRoomMessage, tvContent); + } else if (second == CustomAttachment.CUSTOM_MSG_DRAGON_BAR_CANCEL) { + setDragonBarCancelMsg(chatRoomMessage, tvContent); + } else if (second == CustomAttachment.CUSTOM_MSG_DRAGON_BAR_RUNAWAY) { + setDragonBarRunawayMsg(chatRoomMessage, tvContent); + } + } else if (first == CustomAttachment.CUSTOM_MSG_BOX) { + setBoxMeMsg(chatRoomMessage, tvContent); + } else if (first == CustomAttachment.CUSTOM_MSG_LUCKY_SEA) { + setLuckySeaMsg(chatRoomMessage, tvContent); + } else if (first == CustomAttachment.CUSTOM_MSG_RADISH) { + setRadishMeMsg(chatRoomMessage, tvContent); + } else if (first == CustomAttachment.CUSTOM_MSG_QUEUING_MIC) { + switch (second) { + case CustomAttachment.CUSTOM_MSG_SUB_QUEUING_MIC_NON_EMPTY: + break; + case CustomAttachment.CUSTOM_MSG_SUB_QUEUING_MIC_EMPTY: + break; + case CustomAttachment.CUSTOM_MSG_SUB_QUEUING_MIC_MODE_OPEN: + startQueuingMicModeMsg(tvContent); + break; + case CustomAttachment.CUSTOM_MSG_SUB_QUEUING_MIC_MODE_CLOSE: + stopQueuingMicModeMsg(tvContent); + break; + case CustomAttachment.CUSTOM_MSG_SUB_QUEUING_MIC_FREE_MIC_OPEN: + switchToFreeMicMsg(tvContent, chatRoomMessage); + break; + case CustomAttachment.CUSTOM_MSG_SUB_QUEUING_MIC_FREE_MIC_CLOSE: + switchToLockMicMsg(tvContent, chatRoomMessage); + break; + } + } else if (first == CustomAttachment.CUSTOM_MESS_HEAD_ROOM_PK) { + switch (second) { + case CustomAttachment.CUSTOM_MESS_SUB_ROOM_PK_EMPTY: + break; + case CustomAttachment.CUSTOM_MESS_SUB_ROOM_PK_NON_EMPTY: + break; + case CustomAttachment.CUSTOM_MESS_SUB_ROOM_PK_MODE_OPEN: + openRoomPKModeMsg((RoomPkAttachment) attachment, tvContent); + break; + case CustomAttachment.CUSTOM_MESS_SUB_ROOM_PK_MODE_CLOSE: + stopRoomPkModeMsg(tvContent); + break; + case CustomAttachment.CUSTOM_MESS_SUB_ROOM_PK_MODE_START: + startRoomPk((RoomPkAttachment) attachment, tvContent); + break; + case CustomAttachment.CUSTOM_MESS_SUB_ROOM_PK_RE_START: + restartRoomPKModeMsg((RoomPkAttachment) attachment, tvContent); + break; + case CustomAttachment.CUSTOM_MESS_SUB_ROOM_PK_RESULT: + roomPkResult((RoomPkAttachment) attachment, tvContent); + break; + case CustomAttachment.CUSTOM_MESS_SUB_ROOM_PK_INVITE: + invitePK((RoomPkAttachment) attachment, tvContent); + break; + } + } else if (first == CustomAttachment.CUSTOM_MSG_SIGN_IN + && second == CustomAttachment.CUSTOM_MSG_SUB_CARVE_UP_GOLD_SECOND_LEVEL) { + //二級瓜分鉆石 + setCarveUpGoldMsg(chatRoomMessage, tvContent); + } else if (first == CustomAttachment.CUSTOM_MSG_MINI_WORLD) { + switch (second) { + case CustomAttachment.CUSTOM_MSG_GROUP_CHAT_ROOM_JOIN_TIP: + setJoinMiniWorldTips(baseViewHolder.getAdapterPosition(), chatRoomMessage, tvContent); + break; + case CustomAttachment.CUSTOM_MSG_GROUP_ROOM_JOIN_NOTICE: + setJoinedMiniWorldNoticeMessage(baseViewHolder.getAdapterPosition(), chatRoomMessage, tvContent); + break; + case CustomAttachment.CUSTOM_MSG_ROOM_FOLLOW: + setRoomFollowOwner(baseViewHolder.getAdapterPosition(), chatRoomMessage, tvContent); + setVIPMessageBackground(chatRoomMessage, tvContent); + break; + case CustomAttachment.CUSTOM_MSG_ROOM_FOLLOW_2: + setRoomFollowOwner2(baseViewHolder.getAdapterPosition(), chatRoomMessage, tvContent); + break; + default: + tvContent.setTextColor(Color.WHITE); + tvContent.setText(tvContent.getResources().getText(R.string.not_support_message_tip)); + break; + } + } else if (first == CustomAttachment.CUSTOM_MSG_HEADER_TYPE_PUBLIC_SCREEN) { + if (second == CustomAttachment.CUSTOM_MSG_SUB_TYPE_PUBLIC_SCREEN_WELCOME) { + //麥上用戶對你的歡迎語 + setMicWelcomeContent(chatRoomMessage, tvContent, baseViewHolder.getAdapterPosition()); + } + } else if (first == CustomAttachment.CUSTOM_MSG_HEADER_TYPE_FOLLOW_ROOM) { + if (second == CustomAttachment.CUSTOM_MSG_SUB_TYPE_FOLLOW_ROOM_SUCCESS) { + //收藏了房間 + setFollowRoomTip(tvContent, (RoomTipAttachment) attachment, chatRoomMessage); + setVIPMessageBackground(chatRoomMessage, tvContent); + } + } else if (first == CUSTOM_MSG_RED_PACKAGE) { + if (second == CustomAttachment.CUSTOM_MSG_SUB_RED_PACKAGE_RECEIVE_ROOM_MSG) { + setRedPackageMsg(chatRoomMessage, tvContent); + }else if (second == CustomAttachment.CUSTOM_MSG_SUB_RED_PACKAGE_RECEIVE_ROOM_LUCKY_BAG){ + setRedPackageMsgByLuckyBag(baseViewHolder,chatRoomMessage); + } + + } else if (first == CustomAttachment.ROOM_PIC_SCREEN_FIRST) { + + if (second == CustomAttachment.ROOM_PIC_SCREEN_SECOND) { + setRoomPicScreen(baseViewHolder,chatRoomMessage); + } else if (second == CustomAttachment.ROOM_MSG_USER_ENTER_ROOM) { + setUserEnterRoom(baseViewHolder,chatRoomMessage,baseViewHolder.getAdapterPosition()); + } + + }else if (first == CustomAttachment.CUSTOM_MSG_DATING) { + setDatingMsg(chatRoomMessage, tvContent, second); + } else if (first == CustomAttachment.CUSTOM_MESS_TAROT) { + setTarotMsg(chatRoomMessage, tvContent); + } else if (first == CustomAttachment.CUSTOM_MSG_VIP) { + setVipMsg(chatRoomMessage, tvContent); + } else if (first == CustomAttachment.CUSTOM_MSG_FANS_TEAM) { + setFansTeamMsg(chatRoomMessage, tvContent); + } else if (first == CustomAttachment.CUSTOM_MSG_LUCKY_GIFT) { + setLuckyGiftServerNotifyMsg(chatRoomMessage, tvContent); + } else if (first == CUSTOM_MSG_GIFT_COMPOUND) { + setGiftCompoundMsg(chatRoomMessage, tvContent); + } else if (first == CUSTOM_MSG_FAIRY) { + setFairyMsg(chatRoomMessage, tvContent); + } else if (first == CUSTOM_MSG_ROOM_ALBUM) { + setRoomAlbumMsg(chatRoomMessage, baseViewHolder); + }else if (first == CUSTOM_MSG_ROOM_TEMPLATE) { + TemplateMessageAttachment templateMessageAttachment = (TemplateMessageAttachment) chatRoomMessage.getAttachment(); + if (templateMessageAttachment != null) { + getTemplateMessageAdapter().convert(tvContent, templateMessageAttachment.getTemplateMessage()); + } else { + getTemplateMessageAdapter().convert(tvContent, null); + } + } else if (first == CUSTOM_MSG_SUPER_LUCKY_GIFT_TEMPLATE) { + TemplateMessageAttachment templateMessageAttachment = (TemplateMessageAttachment) chatRoomMessage.getAttachment(); + if (templateMessageAttachment != null) { + getTemplateMessageAdapter().convert(tvContent, templateMessageAttachment.getTemplateMessage()); + } else { + getTemplateMessageAdapter().convert(tvContent, null); + } + } else if (first == BOOM_FIRST) { + if (second == BOOM_SECOND_DIALOG) { + BoomMsgAttachment boomMsgAttachment = (BoomMsgAttachment) chatRoomMessage.getAttachment(); + setMsgBoom(tvContent, boomMsgAttachment); + } + } else { + tvContent.setTextColor(Color.WHITE); + tvContent.setText(tvContent.getResources().getText(R.string.not_support_message_tip)); + } + } + } catch (UnsupportedOperationException e) { + e.printStackTrace(); + if (tvContent != null) { + clearBackground(tvContent); + tvContent.setTextColor(Color.WHITE); + tvContent.setText(tvContent.getResources().getText(R.string.not_support_message_tip)); + } + } + } + + private void setRoomAlbumMsg(ChatRoomMessage chatRoomMessage, MessageViewHolder baseViewHolder) { + RoomAlbumAttachment attachment = (RoomAlbumAttachment) chatRoomMessage.getAttachment(); + RoomAlbumMsgInfo mRoomAlbumMsgInfo = attachment.getMRoomAlbumMsgInfo(); + + if (mRoomAlbumMsgInfo == null) { + return; + } + + RoomPhoto roomPhoto = mRoomAlbumMsgInfo.getRoomPhoto(); + User user = mRoomAlbumMsgInfo.getUser(); + boolean isMyself = UserModel.get().isMyseft(user.getUid()); + + ImageView ivUserLevel = baseViewHolder.itemView.findViewById(R.id.iv_user_level); + ImageView ivUserCharm = baseViewHolder.itemView.findViewById(R.id.iv_user_charm); + ImageView ivPhoto = baseViewHolder.itemView.findViewById(R.id.iv_photo); + ImageView ivGift = baseViewHolder.itemView.findViewById(R.id.iv_gift); + ImageView ivDiamond = baseViewHolder.itemView.findViewById(R.id.iv_diamond); + TextView tvNick = baseViewHolder.itemView.findViewById(R.id.tv_nick); + TextView tvValue = baseViewHolder.itemView.findViewById(R.id.tv_value); + TextView tvUnlock = baseViewHolder.itemView.findViewById(R.id.tv_unlock); + View vBottomMask = baseViewHolder.itemView.findViewById(R.id.v_bottom_mask); + + ImageLoadUtilsV2.loadImage2(ivUserLevel, mRoomAlbumMsgInfo.getUserLevel().getExperUrl(), Target.SIZE_ORIGINAL); + ImageLoadUtilsV2.loadImage2(ivUserCharm, mRoomAlbumMsgInfo.getUserLevel().getCharmUrl(), Target.SIZE_ORIGINAL); + tvNick.setText(user.getNick()); + tvUnlock.setText(R.string.unlock_mic); + tvUnlock.setBackgroundResource(R.drawable.bg_9168fa_6); + + if (roomPhoto.getType() == 1) { + vBottomMask.setVisibility(View.INVISIBLE); + ivGift.setVisibility(View.INVISIBLE); + ivDiamond.setVisibility(View.INVISIBLE); + tvValue.setVisibility(View.INVISIBLE); + tvUnlock.setVisibility(View.INVISIBLE); + ImageLoadUtilsV2.loadImage(ivPhoto, roomPhoto.getPhotoUrl()); + } else { + vBottomMask.setVisibility(View.VISIBLE); + ivGift.setVisibility(View.VISIBLE); + ivDiamond.setVisibility(View.VISIBLE); + tvValue.setVisibility(View.VISIBLE); + tvUnlock.setVisibility(View.VISIBLE); + + if (isMyself) { + tvUnlock.setVisibility(View.INVISIBLE); + } + + if (isMyself || hadUnlock(roomPhoto.getId())) { + ImageLoadUtilsV2.loadImage(ivPhoto, roomPhoto.getPhotoUrl()); + tvUnlock.setText(R.string.unlocked); + tvUnlock.setBackgroundResource(R.drawable.bg_9e9ea8_6); + } else { + ImageLoadUtils.loadImageWithBlur(mContext, roomPhoto.getPhotoUrl(), ivPhoto, 25, 4); + } + + ImageLoadUtilsV2.loadImage(ivGift, roomPhoto.getGiftUrl()); + tvValue.setText(String.valueOf(roomPhoto.getTotalGoldPrice())); + } + + ivPhoto.setOnClickListener(v -> { + if (roomPhoto.getType() == 2 && !isMyself && !hadUnlock(roomPhoto.getId())) { + unlockRoomPhoto(baseViewHolder.getAbsoluteAdapterPosition(), roomPhoto); + return; + } + + BigPhotoActivity.start((Activity) mContext, ObjectTypeHelper.pathToCustomItems(roomPhoto.getPhotoUrl()), + 0, new PagerOption()); + }); + + baseViewHolder.itemView.setOnClickListener(v -> { + if (roomPhoto.getType() == 2 && !isMyself && !hadUnlock(roomPhoto.getId())) { + unlockRoomPhoto(baseViewHolder.getAbsoluteAdapterPosition(), roomPhoto); + } + }); + + + tvUnlock.setOnClickListener(v -> unlockRoomPhoto(baseViewHolder.getAbsoluteAdapterPosition(), roomPhoto)); + } + + + private void unlockRoomPhoto(int position, RoomPhoto roomPhoto) { + UnlockRoomAlbumPhotoDialog unlockRoomAlbumPhotoDialog = UnlockRoomAlbumPhotoDialog.Companion + .newInstance(roomPhoto.getId(), roomPhoto.getGiftUrl(), roomPhoto.getGiftName(), roomPhoto.getTotalGoldPrice()); + unlockRoomAlbumPhotoDialog.setOnUnlockRoomPhotoListener(giftReceiveInfo -> { + giftReceiveInfo.setRoomAlbum(true); + GiftToolbox.sendGiftRoomMessage(giftReceiveInfo); + + AvRoomDataManager.get().addUnlockedRoomAlbumPhoto(roomPhoto.getId()); + notifyItemChanged(position); + }); + unlockRoomAlbumPhotoDialog.show(mContext); + + } + + private boolean hadUnlock(int photoId) { + List unlockedIds = AvRoomDataManager.get().getUnlockedRoomAlbumPhotos(); + return unlockedIds.contains(photoId); + } + + private void setFairyMsg(ChatRoomMessage chatRoomMessage, TextView tvContent) { + if (chatRoomMessage.getAttachment() instanceof FairyMsgAttachment) { + FairyMsgAttachment attachment = (FairyMsgAttachment) chatRoomMessage.getAttachment(); + FairyMsgInfoBean fairyMsgInfo = attachment.getFairyMsgInfo(); + if (fairyMsgInfo == null) return; + TextSpannableBuilder builder = null; + switch (attachment.getSecond()) { + case CUSTOM_MSG_SUB_DRAW_GIFT_L1: + case CUSTOM_MSG_SUB_DRAW_GIFT_L2: + case CUSTOM_MSG_SUB_DRAW_BALL_L1: + builder = builderDrawMsg(tvContent, fairyMsgInfo, "厲害了!"); + break; + case CUSTOM_MSG_SUB_DRAW_GIFT_L3: + case CUSTOM_MSG_SUB_DRAW_GIFT_L4: + case CUSTOM_MSG_SUB_DRAW_GIFT_L5: + case CUSTOM_MSG_SUB_DRAW_BALL_L2: + case CUSTOM_MSG_SUB_DRAW_BALL_L3: + builder = builderDrawMsg(tvContent, fairyMsgInfo, "好運爆棚!"); + break; + case CUSTOM_MSG_SUB_CONVERT_L1: + builder = builderConvertMsg(tvContent, fairyMsgInfo, "初級召喚"); + break; + case CUSTOM_MSG_SUB_CONVERT_L2: + builder = builderConvertMsg(tvContent, fairyMsgInfo, "史詩召喚"); + break; + case CUSTOM_MSG_SUB_CONVERT_L3: + builder = builderConvertMsg(tvContent, fairyMsgInfo, "傳說召喚"); + break; + } + + if (builder != null) { +// if (GoldBoxHelper.isShowFairy()) { +// builder.append(" 去參加!", new OriginalDrawStatusClickSpan(Color.parseColor("#FFBC51")) { +// @Override +// public void onClick(@NonNull View widget) { +// HomeFairyActivity.start(mContext); +// } +// }); +// } + tvContent.setOnClickListener(null); + tvContent.setMovementMethod(new LinkMovementMethod()); + tvContent.setText(builder.build()); + } + } + + } + + private TextSpannableBuilder builderConvertMsg(TextView textView, @NonNull FairyMsgInfoBean fairyMsgInfo, String type) { + return new TextSpannableBuilder(textView) + .append("厲害了!", new ForegroundColorSpan(whiteColor)) + .append(StringExtensionKt.subAndReplaceDot(fairyMsgInfo.getNick(), 7), new OriginalDrawStatusClickSpan(roomTipNickColor, false) { + + @Override + public void onClick(@NonNull View widget) { + RxBus.get().post(new ShowUserInfoDialogEvent(String.valueOf(fairyMsgInfo.getUid()))); + } + }) + .append("在奪寶精靈中 " + type, new ForegroundColorSpan(whiteColor)) + .append(fairyMsgInfo.getRewardShowValue() + "鉆" + fairyMsgInfo.getRewardName(), new ForegroundColorSpan(roomTipColor)); + } + + private TextSpannableBuilder builderDrawMsg(TextView textView, @NonNull FairyMsgInfoBean fairyMsgInfo, String desc) { + TextSpannableBuilder builder = new TextSpannableBuilder(textView) + .append(desc, new ForegroundColorSpan(whiteColor)) + .append(StringExtensionKt.subAndReplaceDot(fairyMsgInfo.getNick(), 7), new OriginalDrawStatusClickSpan(roomTipNickColor, false) { + + @Override + public void onClick(@NonNull View widget) { + RxBus.get().post(new ShowUserInfoDialogEvent(String.valueOf(fairyMsgInfo.getUid()))); + } + }) + .append(" 在奪寶精靈中獲得 ", new ForegroundColorSpan(whiteColor)) + .append(fairyMsgInfo.getRewardName(), new ForegroundColorSpan(Color.WHITE)); + if (fairyMsgInfo.getRewardNum() > 1) { + builder.append(" x" + fairyMsgInfo.getRewardNum(), new ForegroundColorSpan(roomTipNickColor)); + } + return builder; + } + + @SuppressLint("CheckResult") + private void setGiftCompoundMsg(ChatRoomMessage chatRoomMessage, TextView tvContent) { + if (chatRoomMessage.getAttachment() instanceof GiftCompoundAttachment) { + GiftCompoundAttachment giftCompoundAttachment = (GiftCompoundAttachment) chatRoomMessage.getAttachment(); + if (giftCompoundAttachment.getSecond() == CUSTOM_MSG_SUB_GIFT_COMPOUND) { + GiftCompoundMsgBean msgInfo = giftCompoundAttachment.getMsgBean(); + TextSpannableBuilder text = new TextSpannableBuilder(tvContent); + text.append( + msgInfo.getNick(), + new ForegroundColorSpan(roomTipNickColor), + new OriginalDrawStatusClickSpan() { + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(String.valueOf(msgInfo.getUid())).subscribe(clickConsumer); + } + } + } + ) + .append(msgInfo.getMsg(), new ForegroundColorSpan(whiteColor)) + .append(msgInfo.getGiftName(), new ForegroundColorSpan(roomTipNickColor)); + tvContent.setText(text.build()); + tvContent.setOnClickListener(null); + tvContent.setMovementMethod(new LinkMovementMethod()); + } + } else { + tvContent.setTextColor(Color.WHITE); + tvContent.setText(tvContent.getResources().getText(R.string.not_support_message_tip)); + } + } + + @SuppressLint("CheckResult") + private void setFansTeamMsg(ChatRoomMessage chatRoomMessage, TextView tvContent) { + if (chatRoomMessage.getAttachment() instanceof FansTeamMsgAttachment) { + FansTeamMsgAttachment fansTeamMsgAttachment = (FansTeamMsgAttachment) chatRoomMessage.getAttachment(); + if (fansTeamMsgAttachment.getSecond() == CUSTOM_MSG_SUB_FANS_TEAM_JOIN) { + FansTeamMsgInfo msgInfo = fansTeamMsgAttachment.getFansTeamMsgInfo(); + TextSpannableBuilder text = new TextSpannableBuilder(tvContent); + text.append(ResUtil.getString(R.string.avroom_widget_messageview_04), new ForegroundColorSpan(whiteColor)) + .append(msgInfo.getNickname(), new ForegroundColorSpan(roomTipNickColor), + new OriginalDrawStatusClickSpan() { + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(String.valueOf(msgInfo.getUid())).subscribe(clickConsumer); + } + } + }) + .append(ResUtil.getString(R.string.avroom_widget_messageview_05), new ForegroundColorSpan(whiteColor)); + tvContent.setText(text.build()); + tvContent.setOnClickListener(null); + tvContent.setMovementMethod(new LinkMovementMethod()); + } + } else { + tvContent.setTextColor(Color.WHITE); + tvContent.setText(tvContent.getResources().getText(R.string.not_support_message_tip)); + } + } + + + @SuppressLint("CheckResult") + private void setVipMsg(ChatRoomMessage chatRoomMessage, TextView tvContent) { + if (chatRoomMessage.getAttachment() instanceof VipMessageAttachment) { + VipMessageAttachment datingAttachment = (VipMessageAttachment) chatRoomMessage.getAttachment(); + VipMessageInfo notifyInfo = datingAttachment.getVipMessageInfo(); + TextSpannableBuilder text = new TextSpannableBuilder(tvContent); + int second = datingAttachment.getSecond(); + switch (second) { + case CustomAttachment.CUSTOM_MSG_VIP_ROOM_OPEN: + text.append(ResUtil.getString(R.string.avroom_widget_messageview_06), new ForegroundColorSpan(whiteColor)) + .append(notifyInfo.getNick() + "(" + notifyInfo.getErbanNo() + ")", new ForegroundColorSpan(roomTipNickColor), + new OriginalDrawStatusClickSpan() { + + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(String.valueOf(notifyInfo.getUid())).subscribe(clickConsumer); + } + } + }) + .append(ResUtil.getString(R.string.avroom_widget_messageview_07), new ForegroundColorSpan(whiteColor)) + .append(notifyInfo.getCurrVipName(), new ForegroundColorSpan(roomTipColor)) + .append(ResUtil.getString(R.string.avroom_widget_messageview_08), new ForegroundColorSpan(whiteColor)); + break; + case CustomAttachment.CUSTOM_MSG_VIP_ROOM_UPGRADE: + case CustomAttachment.CUSTOM_MSG_VIP_ROOM_ALL_UPGRADE: + text.append(ResUtil.getString(R.string.avroom_widget_messageview_09), new ForegroundColorSpan(whiteColor)) + .append(notifyInfo.getNick() + "(" + notifyInfo.getErbanNo() + ")", new ForegroundColorSpan(roomTipNickColor), + new OriginalDrawStatusClickSpan() { + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(String.valueOf(notifyInfo.getUid())).subscribe(clickConsumer); + } + } + }) + .append(ResUtil.getString(R.string.avroom_widget_messageview_010), new ForegroundColorSpan(whiteColor)) + .append(notifyInfo.getCurrVipName(), new ForegroundColorSpan(roomTipColor)); + break; + } + tvContent.setText(text.build()); + tvContent.setOnClickListener(null); + tvContent.setMovementMethod(new LinkMovementMethod()); + } else { + tvContent.setTextColor(Color.WHITE); + tvContent.setText(tvContent.getResources().getText(R.string.not_support_message_tip)); + } + } + + private void setLuckyGiftServerNotifyMsg(ChatRoomMessage chatRoomMessage, TextView tvContent) { + RoomReceivedLuckyGiftAttachment attachment = (RoomReceivedLuckyGiftAttachment) chatRoomMessage.getAttachment(); + if (attachment.getSecond() == CustomAttachment.CUSTOM_MSG_LUCKY_GIFT_SERVER_NOTIFY) { + LuckyBagNoticeInfo noticeInfo = attachment.getLuckyBagNoticeInfo(); + String nickName = RegexUtil.getPrintableString(noticeInfo.getNick()); + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(ResUtil.getString(R.string.avroom_widget_messageview_011), new ForegroundColorSpan(textColor)) + .append(nickName, new ForegroundColorSpan(roomTipNickColor)) + .append(ResUtil.getString(R.string.avroom_widget_messageview_012), new ForegroundColorSpan(textColor)) + .append(noticeInfo.getRoomTitle() + "", new ForegroundColorSpan(roomTipNickColor)) + .append(ResUtil.getString(R.string.avroom_widget_messageview_013), new ForegroundColorSpan(textColor)) + .append(noticeInfo.getLuckyBagName(), new ForegroundColorSpan(roomTipNickColor)) + .append(ResUtil.getString(R.string.avroom_widget_messageview_014), new ForegroundColorSpan(textColor)) + .append(noticeInfo.getGiftName() + "", new ForegroundColorSpan(roomTipNickColor)); + tvContent.setText(text.build()); + } + } + + private void setDatingMsg(ChatRoomMessage chatRoomMessage, TextView tvContent, int second) { + if (chatRoomMessage.getAttachment() instanceof DatingAttachment) { + DatingAttachment datingAttachment = (DatingAttachment) chatRoomMessage.getAttachment(); + DatingNotifyInfo notifyInfo = datingAttachment.getDatingNotifyInfo(); + TextSpannableBuilder text = new TextSpannableBuilder(tvContent); + switch (second) { + case CustomAttachment.CUSTOM_MSG_SUB_DATING_SELECT: + text.append(ResUtil.getString(R.string.avroom_widget_messageview_015), new ForegroundColorSpan(whiteColor)) + .append((notifyInfo.getTargetPosition() + 1) + ResUtil.getString(R.string.avroom_widget_messageview_016) + (notifyInfo.getTargetGender() == 1 ? ResUtil.getString(R.string.avroom_widget_messageview_017) : ResUtil.getString(R.string.avroom_widget_messageview_018)) + ResUtil.getString(R.string.avroom_widget_messageview_019), new ForegroundColorSpan(whiteColor)) + .append(notifyInfo.getTargetNickname(), new ForegroundColorSpan(roomTipNickColor), + new OriginalDrawStatusClickSpan() { + + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(String.valueOf(notifyInfo.getTargetUid())).subscribe(clickConsumer); + } + } + }) + .append(ResUtil.getString(R.string.avroom_widget_messageview_020), new ForegroundColorSpan(whiteColor)); + break; + case CustomAttachment.CUSTOM_MSG_SUB_DATING_PUBLISH_LIKE: + if (notifyInfo.getHasSelectUser()) { + text.append(notifyInfo.getNickname(), new ForegroundColorSpan(roomTipNickColor), + new OriginalDrawStatusClickSpan() { + + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(String.valueOf(notifyInfo.getUid())).subscribe(clickConsumer); + } + } + }) + .append(ResUtil.getString(R.string.avroom_widget_messageview_021), new ForegroundColorSpan(whiteColor)) + .append(notifyInfo.getTargetNickname(), new ForegroundColorSpan(roomTipNickColor), + new OriginalDrawStatusClickSpan() { + + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(String.valueOf(notifyInfo.getTargetUid())).subscribe(clickConsumer); + } + } + }); + } else { + text.append(notifyInfo.getNickname(), new ForegroundColorSpan(roomTipNickColor), + new OriginalDrawStatusClickSpan() { + + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(String.valueOf(notifyInfo.getUid())).subscribe(clickConsumer); + } + } + }) + .append(ResUtil.getString(R.string.avroom_widget_messageview_022), new ForegroundColorSpan(whiteColor)); + } + break; + case CustomAttachment.CUSTOM_MSG_SUB_DATING_PUBLISH_HEART: + text.append(ResUtil.getString(R.string.avroom_widget_messageview_023), new ForegroundColorSpan(whiteColor)) + .append(notifyInfo.getNickname(), new ForegroundColorSpan(roomTipNickColor), + new OriginalDrawStatusClickSpan() { + + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(String.valueOf(notifyInfo.getUid())).subscribe(clickConsumer); + } + } + }) + .append(ResUtil.getString(R.string.avroom_widget_messageview_024), new ForegroundColorSpan(whiteColor)) + .append(notifyInfo.getTargetNickname(), new ForegroundColorSpan(roomTipNickColor), + new OriginalDrawStatusClickSpan() { + + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(String.valueOf(notifyInfo.getTargetUid())).subscribe(clickConsumer); + } + } + }) + .append(ResUtil.getString(R.string.avroom_widget_messageview_025), new ForegroundColorSpan(whiteColor)); + break; + } + tvContent.setText(text.build()); + tvContent.setOnClickListener(null); + tvContent.setMovementMethod(new LinkMovementMethod()); + } else { + tvContent.setTextColor(Color.WHITE); + tvContent.setText(tvContent.getResources().getText(R.string.not_support_message_tip)); + } + + } + + private void setTarotMsg(ChatRoomMessage chatRoomMessage, TextView tvContent) { + TarotAttachment attachment = (TarotAttachment) chatRoomMessage.getAttachment(); + TarotMsgBean tarotMsgBean = attachment.getTarotMsgBean(); + String nickName = RegexUtil.getPrintableString(tarotMsgBean.getNick()); + TextSpannableBuilder text = new TextSpannableBuilder(tvContent); + switch (attachment.getSecond()) { + case CustomAttachment.CUSTOM_MESS_TAROT_SUCCESS: + text.append(ResUtil.getString(R.string.avroom_widget_messageview_026), new ForegroundColorSpan(textColor)) + .append(nickName, new ForegroundColorSpan(roomTipNickColor)) + .append(" " + tarotMsgBean.getDrawMsgText(), new ForegroundColorSpan(textColor)) + .append(tarotMsgBean.getDrawGoldNum() + ResUtil.getString(R.string.avroom_widget_messageview_027), new ForegroundColorSpan(roomTipColor)); + tvContent.setText(text.build()); + break; + case CustomAttachment.CUSTOM_MESS_TAROT_JUNIOR_PRIZE_WINNING: + case CustomAttachment.CUSTOM_MESS_TAROT_INTERMEDIATE_PRIZE_WINNING: + case CustomAttachment.CUSTOM_MESS_TAROT_SENIOR_PRIZE_WINNING: + text.append(ResUtil.getString(R.string.avroom_widget_messageview_026), new ForegroundColorSpan(textColor)) + .append(nickName, new ForegroundColorSpan(roomTipNickColor)) + .append(ResUtil.getString(R.string.avroom_widget_messageview_0160), new ForegroundColorSpan(textColor)) + .append(tarotMsgBean.getDrawGoldNum() + ResUtil.getString(R.string.avroom_widget_messageview_027), new ForegroundColorSpan(roomTipColor)); + tvContent.setText(text.build()); + break; + } + } + + /** + * 提示已經加入的話題的通知 + * + * @param adapterPosition + * @param chatRoomMessage + * @param tvContent + */ + private void setJoinedMiniWorldNoticeMessage(int adapterPosition, ChatRoomMessage chatRoomMessage, TextView tvContent) { + if (!(chatRoomMessage.getAttachment() instanceof JoinMiniWorldNoticeAttachment)) { + return; + } + JoinMiniWorldNoticeAttachment joinMiniWorldNoticeAttachment = (JoinMiniWorldNoticeAttachment) chatRoomMessage.getAttachment(); + String nick = TextUtils.isEmpty(joinMiniWorldNoticeAttachment.getNick()) ? "" : joinMiniWorldNoticeAttachment.getNick(); + String worldName = TextUtils.isEmpty(joinMiniWorldNoticeAttachment.getWorldName()) ? "" : joinMiniWorldNoticeAttachment.getWorldName(); + TextSpannableBuilder append = new TextSpannableBuilder(tvContent) + .append(ResUtil.getString(R.string.avroom_widget_messageview_028)) + .append(" " + nick + " ", new OriginalDrawStatusClickSpan() { + @Override + public void onClick(@NonNull View widget) { + UserInfoDialog.showNewUserInfoDialog(mContext, joinMiniWorldNoticeAttachment.getUid()); + } + }, new ForegroundColorSpan(roomTipNickColor)) + .append(ResUtil.getString(R.string.avroom_widget_messageview_029)) + .append(" 【" + worldName + "】 ", new ForegroundColorSpan(roomTipNickColor), new OriginalDrawStatusClickSpan() { + @Override + public void onClick(@NonNull View widget) { + if (onClick != null) { + onClick.onJoinMiniWorldClick(adapterPosition); + } + } + }); + + tvContent.setText(append.build()); + tvContent.setOnClickListener(null); + tvContent.setMovementMethod(new LinkMovementMethod()); + } + + private void setRedPackageMsg(ChatRoomMessage chatRoomMessage, TextView tvContent) { + if (chatRoomMessage.getAttachment() instanceof RedPackageRoomMsgAttachment) { + RedPackageRoomMsgAttachment attachment = (RedPackageRoomMsgAttachment) chatRoomMessage.getAttachment(); + RedEnvelopeRoomMsg roomMsg = attachment.getRedEnvelopeRoomMsg(); + String openNickname = RegexUtil.getPrintableString(roomMsg.getOpenRedEnvelopeUserNick()); + String sendNickname = RegexUtil.getPrintableString(roomMsg.getRedEnvelopeMasterNick()); + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(openNickname, new ForegroundColorSpan(roomTipNickColor), new OriginalDrawStatusClickSpan() { + + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(roomMsg.getOpenRedEnvelopeId()).subscribe(clickConsumer); + } + } + }) + .append(ResUtil.getString(R.string.avroom_widget_messageview_030), new ForegroundColorSpan(textColor)) + .append(sendNickname, new ForegroundColorSpan(roomTipColor), new OriginalDrawStatusClickSpan() { + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(String.valueOf(roomMsg.getRedEnvelopeMasterId())).subscribe(clickConsumer); + } + } + }); + switch (roomMsg.getRedEnvelopeType()) { + case ALL_DIAMOND: + case ROOM_DIAMOND: + text.append(ResUtil.getString(R.string.avroom_widget_messageview_031), new ForegroundColorSpan(textColor)) + .append((int) roomMsg.getAmount() + ResUtil.getString(R.string.avroom_widget_messageview_027), new ForegroundColorSpan(roomTipColor)); + tvContent.setText(text.build()); + break; + case ALL_GIFT: + case ROOM_GIFT: + text.append(ResUtil.getString(R.string.avroom_widget_messageview_033), new ForegroundColorSpan(textColor)) + .append((int) roomMsg.getAmount() + ResUtil.getString(R.string.avroom_widget_messageview_027), new ForegroundColorSpan(roomTipColor)) + .append(ResUtil.getString(R.string.avroom_widget_messageview_035), new ForegroundColorSpan(textColor)); + tvContent.setText(text.build()); + } + tvContent.setOnClickListener(null); + tvContent.setMovementMethod(new LinkMovementMethod()); + } + + } + + //幸运礼包 + private void setRedPackageMsgByLuckyBag(MessageViewHolder baseViewHolder,ChatRoomMessage chatRoomMessage) { + try { + MsgAttachment attachment = chatRoomMessage.getAttachment(); + if (attachment instanceof RedPackageLuckyBagAttachment) { + RedPackageLuckyBag redPackageLuckyBag = ((RedPackageLuckyBagAttachment) attachment).getRedPackageLuckyBag(); + if (redPackageLuckyBag!= null) { + ImageView avatar = baseViewHolder.itemView.findViewById(R.id.avatar); + TextView nick = baseViewHolder.itemView.findViewById(R.id.nick); + TextView content = baseViewHolder.itemView.findViewById(R.id.content); + ImageView bg = baseViewHolder.itemView.findViewById(R.id.bg); + + ImageLoadKt.loadAvatar(avatar, redPackageLuckyBag.getSendUserAvatar()); + nick.setText(redPackageLuckyBag.getSendUserNick()); + if (redPackageLuckyBag.getRedEnvelopeType().equals(LuckyBagEntity.Type.GIFT)) { + bg.setImageResource(R.drawable.ic_lucky_bag_msg_gift_bg); + content.setText(ResourcesKtxKt.getString(R.string._ver_24_lucky_bag_room_notify_gift)); + } else { + bg.setImageResource(R.drawable.ic_lucky_bag_msg_gold_bg); + content.setText(ResourcesKtxKt.getString(R.string._ver_24_lucky_bag_room_notify_coin)); + } + + } + } + } catch (Exception e) { + + } + } + + //房间公屏-图片消息 + private void setRoomPicScreen(MessageViewHolder baseViewHolder,ChatRoomMessage chatRoomMessage) { + try { + ImageView avatar = baseViewHolder.itemView.findViewById(R.id.pic); + LinearLayout rootBg = baseViewHolder.itemView.findViewById(R.id.rootBg); + TextView tvContent = baseViewHolder.itemView.findViewById(R.id.tvContent); + + TextSpannableBuilder text = new TextSpannableBuilder(tvContent); + MsgAttachment attachment = chatRoomMessage.getAttachment(); + if (attachment instanceof RoomPicScreenMsgAttachment) { + RoomPicScreenBean data = ((RoomPicScreenMsgAttachment) attachment).getRoomPicScreenBean(); + if (data!= null) { + addTag(text, tvContent,rootBg + ,String.valueOf(data.uid) + ,data.experUrl + ,data.charmUrl + ,data.vipIcon + ,data.inRoomNameplateWord + ,data.inRoomNameplatePic + ,data.androidBubbleUrl + ,data.isOfficial() + ,data.newUser + ); + String targetUid = String.valueOf(data.uid); + + String nickName = (data.uid == AuthModel.get().getCurrentUid()) ? ResUtil.getString(R.string.avroom_widget_messageview_0116) : data.nick; + text.append(nickName, new ForegroundColorSpan(greyColor)).append(": ", new ForegroundColorSpan(getResources().getColor(R.color.white))); + + ImageLoadUtils.load(data.getPicUrl(),avatar); + + avatar.setOnClickListener(v -> { + ShowPhotoActivity.start(v.getContext(),data.getPicUrl()); + }); + + if (Objects.equals(targetUid, String.valueOf(AuthModel.get().getCurrentUid()))) { + tvContent.setOnLongClickListener(null); + } else { + String finalNickName = nickName; + tvContent.setOnLongClickListener(v -> { + if (onLongClickListener != null) { + onLongClickListener.onLongClick(v, targetUid, finalNickName); + } + return true; + }); + } + tvContent.setText(text.build()); + } + } + } catch (Exception e) { + OtherExtKt.doLog("bug "+e.getMessage()); + } + } + + //房间公屏-进房提示消息 / cp进房提示消息 / cp上麦消息 + private void setUserEnterRoom(MessageViewHolder baseViewHolder, ChatRoomMessage chatRoomMessage, int position) { + try { + TextView tvContent = baseViewHolder.tvContent; + TextView tvCpContent = baseViewHolder.itemView.findViewById(R.id.cpTv); + if (tvContent != null && tvCpContent != null ) { + + OtherExtKt.setAutoSizeModel(tvCpContent,8,14); + + TextSpannableBuilder text = new TextSpannableBuilder(tvContent); + MsgAttachment attachment = chatRoomMessage.getAttachment(); + if (attachment instanceof RoomUserEnterRoomMsgAttachment){ + RoomUserEnterRoomBean data = ((RoomUserEnterRoomMsgAttachment) attachment).userEnterRoomBean; + if (data != null) { + + String targetUid = String.valueOf(data.uid); + + if (data.isDef()) { + tvContent.setVisibility(VISIBLE); + tvCpContent.setVisibility(GONE); + addTag(text, tvContent, tvContent + , String.valueOf(data.uid) + , data.experUrl + , data.charmUrl + , data.vipIcon + , data.inRoomNameplateWord + , data.inRoomNameplatePic + , data.androidBubbleUrl + , data.isOfficial() + , data.newUser + ); + //xx 来了 + int fromType = data.fromType; + long fromUid = data.fromUid; + String fromNick = data.fromNick; + // 座駕 + String carName = data.carName; + carName = TextUtils.isEmpty(carName) ? "" : "\"" + carName + "\""; + text.append(data.nick, new ForegroundColorSpan(roomTipColor), + new OriginalDrawStatusClickSpan() { + @Override + public void onClick(@NonNull View view) { + if (clickConsumer != null) { + Single.just(targetUid).doOnSuccess(clickConsumer).subscribe(); + } + } + }); + + text.append(TextUtils.isEmpty(carName) ? "" : ResUtil.getString(R.string.avroom_widget_messageview_0150), new ForegroundColorSpan(greyColor)) + .append(carName, new ForegroundColorSpan(roomTipColor)); + String enterText = ResUtil.getString(R.string.avroom_widget_messageview_0151); + if (fromType == AVRoomActivity.FROM_TYPE_RECOMMEND) { + enterText = ResUtil.getString(R.string.avroom_widget_messageview_0152); + } + if (fromType == AVRoomActivity.FROM_TYPE_USER || fromType == AVRoomActivity.FROM_TYPE_HELLO) { + String finalFromUid = String.valueOf(fromUid); + text.append(ResUtil.getString(R.string.avroom_widget_messageview_0153), new ForegroundColorSpan(whiteColor)) + .append(fromNick, new ForegroundColorSpan(roomTipColor), + new OriginalDrawStatusClickSpan() { + @Override + public void onClick(@NonNull View view) { + if (clickConsumer != null) { + Single.just(finalFromUid).doOnSuccess(clickConsumer).subscribe(); + } + } + }); + enterText = ResUtil.getString(R.string.avroom_widget_messageview_0154); + } + + if (fromType == AVRoomActivity.FROM_TYPE_GAME_RECOMMEND) { + String finalFromUid = String.valueOf(fromUid); + text.append(ResUtil.getString(R.string.avroom_widget_messageview_0155), new ForegroundColorSpan(whiteColor)) + .append(fromNick, new ForegroundColorSpan(roomTipColor), + new OriginalDrawStatusClickSpan() { + @Override + public void onClick(@NonNull View view) { + if (clickConsumer != null) { + Single.just(finalFromUid).doOnSuccess(clickConsumer).subscribe(); + } + } + }); + enterText = ResUtil.getString(R.string.avroom_widget_messageview_0156); + } + + text.append(enterText, new ForegroundColorSpan(whiteColor)); + + //如果自己在麥上,增加一個歡迎ta的按鈕,並且這條消息不是自己的 + if (AvRoomDataManager.get().isOwnerOnMic() && !UserModel.get().isMyseft(targetUid) && !ExtensionUtil.isWelcomeLocal(chatRoomMessage)) { + text.append(ResourcesCompat.getDrawable(getResources(), R.drawable.icon_room_welcome, null), UIUtil.dip2px(mContext, 47), UIUtil.dip2px(mContext, 17), + new OriginalDrawStatusClickSpan() { + @Override + public void onClick(@NonNull View view) { + ExtensionUtil.setWelcomeLocal(chatRoomMessage, true); + mMessageAdapter.notifyItemChanged(position); + long targetUid = data.uid; + Single.zip(AvRoomModel.get().getWelcomeConfig(targetUid), UserModel.get().getUserInfo(targetUid), (roomWelcomeConfig, info) -> { + WelcomeInfo welcomeInfo = new WelcomeInfo(); + welcomeInfo.setContent(roomWelcomeConfig.getMsg()); + welcomeInfo.setTargetUid(targetUid); + welcomeInfo.setTargetNick(info.getNick()); + welcomeInfo.setFans(roomWelcomeConfig.isFans()); + return welcomeInfo; + }) + .observeOn(AndroidSchedulers.mainThread()) + .flatMap((Function>) welcomeInfo -> { + WelcomeAttachment attachment = new WelcomeAttachment(); + attachment.setWelcomeInfo(welcomeInfo); + return ImHelperUtils.sendChatRoomMessage(attachment); + }) + //添加到自己的公屏 + .doOnSuccess(chatRoomMessage -> IMNetEaseManager.get().addMessages(chatRoomMessage)) + .doOnError(throwable -> { + LogUtil.e("send welcome msg failed, error: " + throwable.getMessage()); + }) + .subscribe(); + } + }); + } + tvContent.setText(text.build()); + tvContent.setOnClickListener(null); + tvContent.setMovementMethod(new LinkMovementMethod()); + } else { + //cp背景 + + tvCpContent.setVisibility(VISIBLE); + tvContent.setVisibility(GONE); + String cpNameStr = CpUtils.INSTANCE.getCpLevelUpStr(data.cpLevel); + String message = ""; + String nickStr = StringExtensionKt.subAndReplaceDot(data.nick,7); + String cpNickStr = StringExtensionKt.subAndReplaceDot(data.cpNick,7); + + List textStyles = new ArrayList<>(); + SpannableTextBuilder.TextStyleBean cpNick = new SpannableTextBuilder.TextStyleBean(); + cpNick.setTextColor(ResourcesKtxKt.getColor(R.color.color_FFDF66)); + cpNick.setText(cpNickStr); + + SpannableTextBuilder.TextStyleBean nick = new SpannableTextBuilder.TextStyleBean(); + nick.setTextColor(ResourcesKtxKt.getColor(R.color.color_FFDF66)); + nick.setText(nickStr); + + + + if (data.isCpInRoom()) { + message = ResourcesKtxKt.getString(R.string._ver_24_cpInRoomTips, cpNickStr,cpNameStr, nickStr); + tvCpContent.setBackgroundResource(R.drawable.ic_msg_room_msg_cp_bg_enter); + + textStyles.add(cpNick); + textStyles.add(nick); + + } else if (data.isCpUpMic()) { + message = ResourcesKtxKt.getString(R.string._ver_24_cpUpMicTips, cpNameStr, nickStr,cpNickStr); + tvCpContent.setBackgroundResource(R.drawable.ic_msg_room_msg_cp_bg_mic); + textStyles.add(nick); + textStyles.add(cpNick); + } + + new SpannableTextBuilder(tvCpContent).appendText(message).addTextStyleList(textStyles).apply(); + } + } + } + } // 270 + + } catch (Exception e) { + OtherExtKt.doLog("bug "+e.getMessage()); + } + } + + + /** + * 提示加入話題 + * + * @param adapterPosition + * @param chatRoomMessage + * @param tvContent + */ + private void setJoinMiniWorldTips(int adapterPosition, ChatRoomMessage chatRoomMessage, TextView tvContent) { + if (!(chatRoomMessage.getAttachment() instanceof JoinMiniWorldAttachment)) { + return; + } + tvContent.setTextColor(Color.WHITE); + JoinMiniWorldAttachment joinMiniWorldAttachment = (JoinMiniWorldAttachment) chatRoomMessage.getAttachment(); + MiniWorldInWorldInfo miniWorldInWorldInfo = joinMiniWorldAttachment.getMiniWorldInfo(); + if (miniWorldInWorldInfo == null) { + throw new UnsupportedOperationException(); + } + tvContent.setMovementMethod(new LinkMovementMethod()); + } + + /** + * 房間公屏提示關註房主 + * + * @param chatRoomMessage + * @param tvContent + */ + private void setRoomFollowOwner(int position, ChatRoomMessage chatRoomMessage, TextView tvContent) { + if (!(chatRoomMessage.getAttachment() instanceof RoomFollowOwnerAttachment)) { + return; + } + tvContent.setTextColor(Color.WHITE); + RoomFollowOwnerAttachment roomFollowOwnerAttachment = (RoomFollowOwnerAttachment) chatRoomMessage.getAttachment(); + UserInfo userInfo = roomFollowOwnerAttachment.getUserInfo(); + String nick; + if (userInfo == null) { + nick = " "; + } else { + nick = userInfo.getNick(); + } + + boolean follow = roomFollowOwnerAttachment.isFollow(); + TextSpannableBuilder append = new TextSpannableBuilder(tvContent) + .append(ResUtil.getString(R.string.avroom_widget_messageview_036)) + .append(" " + nick + " ", new OriginalDrawStatusClickSpan() { + @Override + public void onClick(@NonNull View widget) { + UserInfoDialog.showNewUserInfoDialog(mContext, userInfo.getUid()); + } + }, new ForegroundColorSpan(roomTipNickColor)) + .append(ResUtil.getString(R.string.avroom_widget_messageview_037)) + .append(follow ? ResUtil.getString(R.string.avroom_widget_messageview_038) : ResUtil.getString(R.string.avroom_widget_messageview_039), + new RadiusBackgroundSpan(follow ? Color.parseColor("#4cFFFFFF") : ContextCompat.getColor(tvContent.getContext(), R.color.color_67D7D7), SizeUtils.dp2px(tvContent.getContext(), 8), follow ? Color.parseColor("#D8FFFFFF") : Color.WHITE, (int) (tvContent.getTextSize() - SizeUtils.sp2px(tvContent.getContext(), 2) - .5f), SizeUtils.dp2px(tvContent.getContext(), 8), SizeUtils.dp2px(tvContent.getContext(), 4)), + follow ? null : new OriginalDrawStatusClickSpan() { + @Override + public void onClick(@NonNull View widget) { + if (onClick != null) { + onClick.onFollowClick(position); + } + } + }); + tvContent.setText(append.build()); + tvContent.setMovementMethod(new LinkMovementMethod()); + } + + /** + * 房間公屏提示關註房主 + * + * @param chatRoomMessage + * @param tvContent + */ + private void setRoomFollowOwner2(int position, ChatRoomMessage chatRoomMessage, TextView tvContent) { + if (!(chatRoomMessage.getAttachment() instanceof RoomFollowOwnerAttachment2)) { + return; + } + tvContent.setTextColor(Color.WHITE); + RoomFollowOwnerAttachment2 roomFollowOwnerAttachment = (RoomFollowOwnerAttachment2) chatRoomMessage.getAttachment(); + TextSpannableBuilder append = new TextSpannableBuilder(tvContent) + .append(mContext.getResources().getDrawable(R.drawable.bg_follow), ScreenUtil.dip2px(190), ScreenUtil.dip2px(40)); + tvContent.setText(append.build()); + } + + private void invitePK(RoomPkAttachment attachment, TextView tvContent) { + Map micMemberMap = attachment.getRoomPKInvitedUpMicMemberMap(); + + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(ResUtil.getString(R.string.avroom_widget_messageview_041)); + boolean isHaveInTeam = false; + Iterator> iterator = micMemberMap.entrySet().iterator(); + while (iterator.hasNext()) { + RoomPKInvitedUpMicMember value = iterator.next().getValue(); + //沒有隊伍的不提示 + if (value.getGroupType() == PKTeamInfo.TEAM_NONE) { + continue; + } + + isHaveInTeam = true; + text.append(value.getNick(), new ForegroundColorSpan(roomTipColor), + new OriginalDrawStatusClickSpan() { + + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(value.getUid()).subscribe(clickConsumer); + } + } + }) + .append(ResUtil.getString(R.string.avroom_widget_messageview_042)); + if (value.getGroupType() == PKTeamInfo.TEAM_RED) { + text.append(ResUtil.getString(R.string.avroom_widget_messageview_043), new ForegroundColorSpan(tvContent.getResources().getColor(R.color.color_FB3D74))) + .append(","); + } else if (value.getGroupType() == PKTeamInfo.TEAM_BLUE) { + text.append(ResUtil.getString(R.string.avroom_widget_messageview_044), new ForegroundColorSpan(tvContent.getResources().getColor(R.color.color_3291FC))) + .append(","); + } else { + text.append(ResUtil.getString(R.string.avroom_widget_messageview_045), new ForegroundColorSpan(whiteColor)) + .append(","); + } + } + if (isHaveInTeam) { + Editable msg = text.builder; + msg.delete(msg.length() - 1, msg.length()); + tvContent.setText(msg); + tvContent.setOnClickListener(null); + } + } + + private void openRoomPKModeMsg(RoomPkAttachment attachment, TextView tvContent) { + RoomPkData roomPkData = attachment.getRoomPkData(); + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(String.format(Locale.getDefault(), ResUtil.getString(R.string.avroom_widget_messageview_046), + roomPkData.getDuration()), + new ForegroundColorSpan(whiteColor)); + switch (roomPkData.getVoteMode()) { + case RoomPkData.VOTE_MODE_GIFT: + text.append(ResUtil.getString(R.string.avroom_widget_messageview_047), new ForegroundColorSpan(whiteColor)); + break; + + case RoomPkData.VOTE_MODE_PERSON: + text.append(ResUtil.getString(R.string.avroom_widget_messageview_048), new ForegroundColorSpan(whiteColor)); + break; + } + text.append(ResUtil.getString(R.string.avroom_widget_messageview_049), new ForegroundColorSpan(whiteColor)); + tvContent.setText(text.build()); + } + + private void stopRoomPkModeMsg(TextView tvContent) { + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(ResUtil.getString(R.string.avroom_widget_messageview_050), new ForegroundColorSpan(whiteColor)) + .append(ResUtil.getString(R.string.avroom_widget_messageview_051), new ForegroundColorSpan(greyColor)) + .append(ResUtil.getString(R.string.avroom_widget_messageview_052), new ForegroundColorSpan(whiteColor)); + tvContent.setText(text.build()); + } + + private void startRoomPk(RoomPkAttachment attachment, TextView textView) { + RoomPkData roomPkData = attachment.getRoomPkData(); + TextSpannableBuilder text = new TextSpannableBuilder(textView) + .append(String.format(Locale.getDefault(), + ResUtil.getString(R.string.avroom_widget_messageview_053), roomPkData.getDuration()), + new ForegroundColorSpan(greyColor)); + textView.setText(text.build()); + } + + private void restartRoomPKModeMsg(RoomPkAttachment attachment, TextView tvContent) { + RoomPkData roomPkData = attachment.getRoomPkData(); + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(String.format(Locale.getDefault(), ResUtil.getString(R.string.avroom_widget_messageview_054), + roomPkData.getDuration()), + new ForegroundColorSpan(whiteColor)); + switch (roomPkData.getVoteMode()) { + case RoomPkData.VOTE_MODE_GIFT: + text.append(ResUtil.getString(R.string.avroom_widget_messageview_055), new ForegroundColorSpan(whiteColor)); + break; + + case RoomPkData.VOTE_MODE_PERSON: + text.append(ResUtil.getString(R.string.avroom_widget_messageview_056), new ForegroundColorSpan(whiteColor)); + break; + } + text.append(ResUtil.getString(R.string.avroom_widget_messageview_057), new ForegroundColorSpan(whiteColor)); + tvContent.setText(text.build()); + } + + private void roomPkResult(RoomPkAttachment attachment, TextView textView) { + RoomPkData roomPkData = attachment.getRoomPkData(); + TextSpannableBuilder text = new TextSpannableBuilder(textView) + .append(ResUtil.getString(R.string.avroom_widget_messageview_058), new ForegroundColorSpan(whiteColor)); + Map teamMap = new HashMap<>(); + PKTeamInfo blueTeam = null; + PKTeamInfo redTeam = null; + if (roomPkData.getTeams() != null) { + for (PKTeamInfo roomPkTeam : roomPkData.getTeams()) { + teamMap.put(String.valueOf(roomPkTeam.getTeam()), roomPkTeam); + } + blueTeam = teamMap.get(String.valueOf(PKTeamInfo.TEAM_BLUE)); + redTeam = teamMap.get(String.valueOf(PKTeamInfo.TEAM_RED)); + } + switch (roomPkData.getResult()) { + case RoomPkData.PK_RESULT_DRAW: + text.append(ResUtil.getString(R.string.avroom_widget_messageview_059), new ForegroundColorSpan(whiteColor)); + if (blueTeam != null && redTeam != null) { + text.append(String.format(Locale.getDefault(), ResUtil.getString(R.string.avroom_widget_messageview_060), + FormatUtils.formatPKValue(blueTeam.getScore()), + FormatUtils.formatPKValue(redTeam.getScore())), + new ForegroundColorSpan(whiteColor)); + + UserInfo redProtector = redTeam.getProtector(); + UserInfo blueProtector = blueTeam.getProtector(); + if (redProtector == null || redProtector.getUid() == 0 + || blueProtector == null || blueProtector.getUid() == 0) { + break; + } + text.append(String.format(Locale.getDefault(), ResUtil.getString(R.string.avroom_widget_messageview_061), blueProtector.getNick()), + new ForegroundColorSpan(whiteColor)) + .append(String.format(Locale.getDefault(), ResUtil.getString(R.string.avroom_widget_messageview_062), + FormatUtils.formatPKValue(blueTeam.getProtecScore())), + new ForegroundColorSpan(whiteColor)) + .append(String.format(Locale.getDefault(), ResUtil.getString(R.string.avroom_widget_messageview_063), redProtector.getNick()), + new ForegroundColorSpan(whiteColor)) + .append(String.format(Locale.getDefault(), ResUtil.getString(R.string.avroom_widget_messageview_064), + FormatUtils.formatPKValue(redTeam.getProtecScore())), + new ForegroundColorSpan(whiteColor)); + } + break; + + case PKTeamInfo.TEAM_BLUE: + text.append(ResUtil.getString(R.string.avroom_widget_messageview_065), new ForegroundColorSpan(whiteColor)); + if (blueTeam != null && redTeam != null) { + text.append(String.format(Locale.getDefault(), ResUtil.getString(R.string.avroom_widget_messageview_066), + FormatUtils.formatPKValue(blueTeam.getScore()), + FormatUtils.formatPKValue(redTeam.getScore())), + new ForegroundColorSpan(whiteColor)); + + UserInfo blueProtector = blueTeam.getProtector(); + if (blueProtector == null) { + text.append(String.format(Locale.getDefault(), ResUtil.getString(R.string.avroom_widget_messageview_067), + FormatUtils.formatPKValue(blueTeam.getScore())), + new ForegroundColorSpan(whiteColor)); + + } else { + text.append(String.format(Locale.getDefault(), ResUtil.getString(R.string.avroom_widget_messageview_068), blueProtector.getNick()), + new ForegroundColorSpan(whiteColor)) + .append(String.format(Locale.getDefault(), ResUtil.getString(R.string.avroom_widget_messageview_069), + FormatUtils.formatPKValue(blueTeam.getProtecScore())), + new ForegroundColorSpan(whiteColor)); + } + } + break; + + case PKTeamInfo.TEAM_RED: + text.append(ResUtil.getString(R.string.avroom_widget_messageview_070), new ForegroundColorSpan(whiteColor)); + if (blueTeam != null && redTeam != null) { + text.append(String.format(Locale.getDefault(), ResUtil.getString(R.string.avroom_widget_messageview_071), + FormatUtils.formatPKValue(redTeam.getScore()), + FormatUtils.formatPKValue(blueTeam.getScore())), + new ForegroundColorSpan(whiteColor)); + + UserInfo redProtector = redTeam.getProtector(); + if (redProtector == null) { + text.append(String.format(Locale.getDefault(), ResUtil.getString(R.string.avroom_widget_messageview_072), + FormatUtils.formatPKValue(redTeam.getScore())), + new ForegroundColorSpan(whiteColor)); + } else { + text.append(String.format(Locale.getDefault(), ResUtil.getString(R.string.avroom_widget_messageview_073), redProtector.getNick()), + new ForegroundColorSpan(whiteColor)) + .append(String.format(Locale.getDefault(), ResUtil.getString(R.string.avroom_widget_messageview_074), + FormatUtils.formatPKValue(redTeam.getProtecScore())), + new ForegroundColorSpan(whiteColor)); + } + + } + break; + } + textView.setText(text.build()); + } + + private void startQueuingMicModeMsg(TextView tvContent) { + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(ResUtil.getString(R.string.avroom_widget_messageview_075), new ForegroundColorSpan(whiteColor)) + .append(ResUtil.getString(R.string.avroom_widget_messageview_076), new ForegroundColorSpan(greyColor)) + .append(ResUtil.getString(R.string.avroom_widget_messageview_077), new ForegroundColorSpan(whiteColor)); + tvContent.setText(text.build()); + } + + private void stopQueuingMicModeMsg(TextView tvContent) { + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(ResUtil.getString(R.string.avroom_widget_messageview_078), new ForegroundColorSpan(whiteColor)) + .append(ResUtil.getString(R.string.avroom_widget_messageview_079), new ForegroundColorSpan(greyColor)) + .append(ResUtil.getString(R.string.avroom_widget_messageview_080), new ForegroundColorSpan(whiteColor)); + tvContent.setText(text.build()); + } + + private void switchToFreeMicMsg(TextView tvContent, ChatRoomMessage chatRoomMessage) { + QueuingMicAttachment attachment = (QueuingMicAttachment) chatRoomMessage.getAttachment(); + QueuingMicInfo queuingMicInfo = attachment.getQueuingMicInfo(); + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(ResUtil.getString(R.string.avroom_widget_messageview_081), new ForegroundColorSpan(whiteColor)) + .append(String.format(Locale.getDefault(), ResUtil.getString(R.string.avroom_widget_messageview_082), + JavaUtil.str2int(queuingMicInfo.getMicPos()) + 1), new ForegroundColorSpan(greyColor)) + .append(ResUtil.getString(R.string.avroom_widget_messageview_083), new ForegroundColorSpan(whiteColor)); + tvContent.setText(text.build()); + } + + private void switchToLockMicMsg(TextView tvContent, ChatRoomMessage chatRoomMessage) { + QueuingMicAttachment attachment = (QueuingMicAttachment) chatRoomMessage.getAttachment(); + QueuingMicInfo queuingMicInfo = attachment.getQueuingMicInfo(); + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(ResUtil.getString(R.string.avroom_widget_messageview_084), new ForegroundColorSpan(whiteColor)) + .append(String.format(Locale.getDefault(), ResUtil.getString(R.string.avroom_widget_messageview_085), + JavaUtil.str2int(queuingMicInfo.getMicPos()) + 1), new ForegroundColorSpan(greyColor)) + .append(ResUtil.getString(R.string.avroom_widget_messageview_086), new ForegroundColorSpan(whiteColor)); + tvContent.setText(text.build()); + } + + private void setDragonBarRunawayMsg(ChatRoomMessage chatRoomMessage, TextView tvContent) { + ChatRoomMessageExtension extension = chatRoomMessage.getChatRoomMessageExtension(); + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(extension == null ? ResUtil.getString(R.string.avroom_widget_messageview_087) : RegexUtil.getPrintableString(extension.getSenderNick()), new ForegroundColorSpan(Color.WHITE), + new OriginalDrawStatusClickSpan() { + + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(chatRoomMessage.getFromAccount()).subscribe(clickConsumer); + } + } + }) + .append(ResUtil.getString(R.string.avroom_widget_messageview_088), new ForegroundColorSpan(roomTipColor)); + tvContent.setText(text.build()); + tvContent.setOnClickListener(null); + tvContent.setMovementMethod(new LinkMovementMethod()); + } + + private void setDragonBarCancelMsg(ChatRoomMessage chatRoomMessage, TextView tvContent) { + ChatRoomMessageExtension extension = chatRoomMessage.getChatRoomMessageExtension(); + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(extension == null ? ResUtil.getString(R.string.avroom_widget_messageview_089) : RegexUtil.getPrintableString(extension.getSenderNick()), new ForegroundColorSpan(Color.WHITE), + new OriginalDrawStatusClickSpan() { + + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(chatRoomMessage.getFromAccount()).subscribe(clickConsumer); + } + } + }) + .append(ResUtil.getString(R.string.avroom_widget_messageview_090), new ForegroundColorSpan(roomTipColor)); + tvContent.setText(text.build()); + tvContent.setOnClickListener(null); + tvContent.setMovementMethod(new LinkMovementMethod()); + } + + private void setDragonBarMsg(ChatRoomMessage chatRoomMessage, TextView tvContent) { + try { + ChatRoomMessageExtension extension = chatRoomMessage.getChatRoomMessageExtension(); + + FaceAttachment attachment = (FaceAttachment) chatRoomMessage.getAttachment(); + FaceReceiveInfo faceReceiveInfo = attachment.getFaceReceiveInfos().get(0); + FaceInfo faceInfoById = DynamicFaceModel.get().findFaceInfoById(faceReceiveInfo.getFaceId()); + String msg = ""; + for (Integer integer : faceReceiveInfo.getResultIndexes()) { + msg = msg + (integer + 1 - faceInfoById.getResultIndexStart()) + ","; + } + msg = msg.substring(0, msg.length() - 1); + // 內容 + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(extension == null ? ResUtil.getString(R.string.avroom_widget_messageview_091) : RegexUtil.getPrintableString(extension.getSenderNick()), new ForegroundColorSpan(Color.WHITE), + new OriginalDrawStatusClickSpan() { + + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(chatRoomMessage.getFromAccount()).subscribe(clickConsumer); + } + } + }) + .append(ResUtil.getString(R.string.avroom_widget_messageview_092) + msg, new ForegroundColorSpan(roomTipColor)); + tvContent.setText(text.build()); + tvContent.setOnClickListener(null); + tvContent.setMovementMethod(new LinkMovementMethod()); + } catch (Exception e) { + } + } + + private void setBoxMeMsg(ChatRoomMessage chatRoomMessage, TextView tvContent) { + RoomBoxPrizeAttachment attachment = (RoomBoxPrizeAttachment) chatRoomMessage.getAttachment(); + // 內容 + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append("厲害了 ", new ForegroundColorSpan(greyColor)) + .append(attachment.getNick() + " ", new ForegroundColorSpan(roomTipColor)) + .append("通過歡樂砸蛋" + "獲得 ", new ForegroundColorSpan(greyColor)) + .append(attachment.getPrizeName(), new ForegroundColorSpan(Color.WHITE)); + if (attachment.getPrizeNum() > 1) { + text.append(" x" + attachment.getPrizeNum() + " ", new ForegroundColorSpan(roomTipColor)); + } + if (attachment.getSecond() == CUSTOM_MSG_SUB_BOX_ME) { + text.append("(僅自己可見)", new ForegroundColorSpan(Color.WHITE)); + } + tvContent.setText(text.build()); + } + + private void setLuckySeaMsg(ChatRoomMessage chatRoomMessage, TextView tvContent) { + RoomLuckySeaAttachment attachment = (RoomLuckySeaAttachment) chatRoomMessage.getAttachment(); + RoomLuckySeaMsgBean bean = attachment.getRoomLuckySeaMsgInfo(); + // 內容 + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(ResUtil.getString(R.string.congratulation), new ForegroundColorSpan(greyColor)) + .append(bean.getNick(), new ForegroundColorSpan(roomTipNickColor), + new OriginalDrawStatusClickSpan() { + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(String.valueOf(bean.getUid())).subscribe(clickConsumer); + } + } + }) + .append( + ResUtil.getString(R.string.in_the_star_kitchen_draw), + new ForegroundColorSpan(greyColor) + ) + .append( + String.valueOf(bean.getItemMultiple()), + new ForegroundColorSpan(whiteColor) + ) + .append( + ResUtil.getString(R.string.times_reward_get), + new ForegroundColorSpan(greyColor) + ) + .append( + String.valueOf(bean.getDiamonds()), + new ForegroundColorSpan(whiteColor) + ) + .append( + ResUtil.getString(R.string.diamond_point), + new ForegroundColorSpan(greyColor) + ); + tvContent.setText(text.build()); + tvContent.setOnClickListener(null); + tvContent.setMovementMethod(new LinkMovementMethod()); + } + + private void setRadishMeMsg(ChatRoomMessage chatRoomMessage, TextView tvContent) { + RoomBoxPrizeAttachment attachment = (RoomBoxPrizeAttachment) chatRoomMessage.getAttachment(); + // 內容 + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(ResUtil.getString(R.string.avroom_widget_messageview_097), new ForegroundColorSpan(greyColor)) + .append(attachment.getNick() + " ", new ForegroundColorSpan(roomTipColor)) + .append(attachment.getBoxTypeStr() + ResUtil.getString(R.string.avroom_widget_messageview_098), new ForegroundColorSpan(greyColor)) + .append(attachment.getPrizeName(), new ForegroundColorSpan(Color.WHITE)); + if (attachment.getPrizeNum() > 1) { + text.append(" x" + attachment.getPrizeNum() + " ", new ForegroundColorSpan(roomTipColor)); + } + tvContent.setText(text.build()); + } + + private void setUpdateAudioMsg(TextView tvContent) { + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(ResUtil.getString(R.string.avroom_widget_messageview_099), new ForegroundColorSpan(roomTipColor)) + .append(ResUtil.getString(R.string.avroom_widget_messageview_0100), new ForegroundColorSpan(greyColor)); + tvContent.setText(text.build()); + } + + private void setUpdateGiftEffectMsg(TextView tvContent) { + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(ResUtil.getString(R.string.avroom_widget_messageview_0101), new ForegroundColorSpan(roomTipColor)) + .append(ResUtil.getString(R.string.avroom_widget_messageview_0102), new ForegroundColorSpan(greyColor)); + tvContent.setText(text.build()); + } + + private void setUpdateScreenMsg(TextView tvContent, String contentText) { + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(ResUtil.getString(R.string.avroom_widget_messageview_0103), new ForegroundColorSpan(roomTipColor)) + .append(contentText, new ForegroundColorSpan(greyColor)); + tvContent.setText(text.build()); + } + + private void setUpdateRoomPureModeMsg(TextView tvContent, IMMessage message) { + RoomNoticeAttachment attachment = (RoomNoticeAttachment) message.getAttachment(); + RoomMessageViewNoticeInfo messageViewNoticeInfo = attachment.getRoomMessageViewNoticeInfo(); + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(ResUtil.getString(R.string.avroom_widget_messageview_0104), new ForegroundColorSpan(roomTipColor)) + .append(messageViewNoticeInfo.getTips(), new ForegroundColorSpan(greyColor)); + tvContent.setText(text.build()); + } + + private void setCleanScreenMsg(TextView tvContent, IMMessage message) { + CleanScreenAttachment attachment = (CleanScreenAttachment) message.getAttachment(); + // 內容 + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(attachment.getRoleType() == 1 ? ResUtil.getString(R.string.avroom_widget_messageview_0105) : ResUtil.getString(R.string.avroom_widget_messageview_0106), new ForegroundColorSpan(Color.WHITE)) + .append("(" + attachment.getNick() + ") ", new ForegroundColorSpan(roomTipColor), + new OriginalDrawStatusClickSpan() { + + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(String.valueOf(attachment.getUid())).subscribe(clickConsumer); + } + } + }) + .append(ResUtil.getString(R.string.avroom_widget_messageview_0107), new ForegroundColorSpan(Color.WHITE)); + tvContent.setText(text.build()); + tvContent.setOnClickListener(null); + tvContent.setMovementMethod(new LinkMovementMethod()); + } + + private void setMonsterNotifyMessage(TextView tvContent, String notifyMessage) { + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(notifyMessage, new ForegroundColorSpan(ContextCompat.getColor(getContext(), R.color.color_34D08B))); + tvContent.setText(text.build()); + } + + /** + * 排麥模式中,用戶被管理員抱上麥 + * 格式:管理員/房主將{用戶昵稱}抱上麥 + * + * @param tvContent + * @param attachment + */ + private void setInviteUpMicMsg(TextView tvContent, RoomQueueMsgAttachment attachment) { + String targetNick = RegexUtil.getPrintableString(attachment.targetNick); + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(ResUtil.getString(R.string.avroom_widget_messageview_0108), new ForegroundColorSpan(greyColor)) + .append(targetNick, new ForegroundColorSpan(roomTipColor)) + .append(ResUtil.getString(R.string.avroom_widget_messageview_0109), new ForegroundColorSpan(greyColor)); + tvContent.setText(text.build()); + } + + private void setKickMsg(TextView tvContent, RoomQueueMsgAttachment attachment) { + String nick = RegexUtil.getPrintableString(attachment.handleNick); + String targetNick = RegexUtil.getPrintableString(attachment.targetNick); + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(targetNick, new ForegroundColorSpan(roomTipColor), new OriginalDrawStatusClickSpan() { + + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(attachment.uid).subscribe(clickConsumer); + } + } + }) + .append(ResUtil.getString(R.string.avroom_widget_messageview_0110), new ForegroundColorSpan(greyColor)) + .append(nick, new ForegroundColorSpan(roomTipColor), new OriginalDrawStatusClickSpan() { + + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(attachment.handleUid + "").subscribe(clickConsumer); + } + } + }) + .append(ResUtil.getString(R.string.avroom_widget_messageview_0111), new ForegroundColorSpan(greyColor)); + tvContent.setText(text.build()); + tvContent.setOnClickListener(null); + tvContent.setMovementMethod(new LinkMovementMethod()); + } + + private void setKickRoomMsg(TextView tvContent, RoomQueueMsgAttachment attachment) { + String nick = RegexUtil.getPrintableString(attachment.handleNick); + String targetNick = RegexUtil.getPrintableString(attachment.targetNick); + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(targetNick, new ForegroundColorSpan(roomTipColor), new OriginalDrawStatusClickSpan() { + + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(attachment.uid).subscribe(clickConsumer); + } + } + }) + .append(ResUtil.getString(R.string.avroom_widget_messageview_0112), new ForegroundColorSpan(greyColor)) + .append(nick, new ForegroundColorSpan(roomTipColor), new OriginalDrawStatusClickSpan() { + + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(attachment.handleUid + "").subscribe(clickConsumer); + } + } + }) + .append(ResUtil.getString(R.string.avroom_widget_messageview_0113), new ForegroundColorSpan(greyColor)); + tvContent.setText(text.build()); + tvContent.setOnClickListener(null); + tvContent.setMovementMethod(new LinkMovementMethod()); + } + + private void setAddBlackMsg(TextView tvContent, RoomQueueMsgAttachment attachment) { + String nick = RegexUtil.getPrintableString(attachment.handleNick); + String targetNick = RegexUtil.getPrintableString(attachment.targetNick); + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(targetNick, new ForegroundColorSpan(roomTipColor), new OriginalDrawStatusClickSpan() { + + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null && !TextUtils.isEmpty(attachment.uid)) { + Single.just(attachment.uid).subscribe(clickConsumer); + } + } + }) + .append(ResUtil.getString(R.string.avroom_widget_messageview_0114), new ForegroundColorSpan(greyColor)) + .append(nick, new ForegroundColorSpan(roomTipColor), new OriginalDrawStatusClickSpan() { + + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null && !TextUtils.isEmpty(attachment.uid)) { + Single.just(attachment.handleUid + "").subscribe(clickConsumer); + } + } + }) + .append(ResUtil.getString(R.string.avroom_widget_messageview_0115), new ForegroundColorSpan(greyColor)); + tvContent.setText(text.build()); + tvContent.setOnClickListener(null); + tvContent.setMovementMethod(new LinkMovementMethod()); + } + + /** + * {badge}{level}xxx: 文字內容 + * + * @param chatRoomMessage - + * @param tvContent - + */ + private void setMsgText(ChatRoomMessage chatRoomMessage, TextView tvContent) { + ChatRoomMessageExtension extension = chatRoomMessage.getChatRoomMessageExtension(); + TextSpannableBuilder text = new TextSpannableBuilder(tvContent); + addCommonTag(chatRoomMessage, text, tvContent); + String nickName = extension == null ? ResUtil.getString(R.string.avroom_widget_messageview_0116) : RegexUtil.getPrintableString(extension.getSenderNick()); + + if (UserInfoHelper.isDefNick(nickName)) { + HashMap map = UserInfoHelper.getChatRoomMessageUserInfo(chatRoomMessage, chatRoomMessage.getFromAccount()); + if (map != null) { + Object nick = map.get(UserInfo.NICK); + if (nick != null && nick instanceof String) { + nickName = nick.toString(); + } + } + } + + text.append(nickName, new ForegroundColorSpan(greyColor)).append(": " + chatRoomMessage.getContent(), new ForegroundColorSpan(getResources().getColor(R.color.white))); + List atUids = ExtensionUtil.getListExtension(chatRoomMessage, UserInfo.AT_UIDS); + List atNames = ExtensionUtil.getListExtension(chatRoomMessage, UserInfo.AT_NAMES); + if (!ListUtils.isListEmpty(atUids) && !ListUtils.isListEmpty(atNames)) { + for (int i = 0; i < atUids.size(); i++) { + String name = atNames.get(i); + String uid = atUids.get(i); + // 只有當被 @ 人的數組中包含自己的時候才會去變色 + if (Objects.equals(uid, String.valueOf(AuthModel.get().getCurrentUid()))) { + Pattern pattern = Pattern.compile(Pattern.quote(name)); + Matcher matcher = pattern.matcher(text.build().toString()); + while (matcher.find()) { + int start = matcher.start(); + int end = matcher.end(); + text.build().setSpan(new ForegroundColorSpan(getContext().getResources().getColor(R.color.color_FD85C9)), + start, end, Spannable.SPAN_INCLUSIVE_INCLUSIVE); + } + } + } + } + + if (Objects.equals(chatRoomMessage.getFromAccount(), String.valueOf(AuthModel.get().getCurrentUid()))) { + tvContent.setOnLongClickListener(null); + } else { + String finalNickName = nickName; + tvContent.setOnLongClickListener(v -> { + if (onLongClickListener != null) { + onLongClickListener.onLongClick(v, chatRoomMessage.getFromAccount(), finalNickName); + } + return true; + }); + } + tvContent.setText(text.build()); + } + + + private void clearBackground(TextView textView) { + // 清除文字 + textView.setText(""); + // 清除聊天氣泡 + textView.setBackgroundResource(R.drawable.shape_room_message_bg); + textView.setPadding(paddingWidth, paddingHeight, paddingWidth, paddingHeight); + } + + public void setVIPMessageBackground(ChatRoomMessage chatRoomMessage, View view) { + String androidBubbleUrl = NobleUtil.getResource(UserInfo.BUBBLE_URL_ANDROID, chatRoomMessage); + if (TextUtils.isEmpty(androidBubbleUrl)) return; + view.setPadding(paddingWidth, ScreenUtil.dip2px(10), paddingWidth, ScreenUtil.dip2px(10)); + ImageLoadUtils.loadNinePatchBg(view, androidBubbleUrl); + } + + + //xxx 公屏消息 添加铭牌 + private void addCommonTag(ChatRoomMessage chatRoomMessage, @NonNull TextSpannableBuilder builder, TextView tvContent) { + + ChatRoomMessageExtension extension = chatRoomMessage.getChatRoomMessageExtension(); + String experUrl = NobleUtil.getLevel(UserLevelResourceType.EXPER_URL, chatRoomMessage); + String charmUrl = NobleUtil.getLevel(UserLevelResourceType.CHARM_URL, chatRoomMessage); + boolean isOfficial = NobleUtil.getIsOfficial(UserInfo.IS_OFFICIAL, chatRoomMessage); + String vipIcon = NobleUtil.getResource(UserInfo.VIP_ICON, chatRoomMessage); + builder.append(isOfficial ? ResourcesCompat.getDrawable(getResources(), R.mipmap.ic_user_official_13dp, null) : null, badgeWidth, badgeHeight) + .append(getNewUserDrawable(chatRoomMessage), badgeWidth, badgeHeight) + .append(AvRoomDataManager.get().isSuperAdmin(chatRoomMessage.getFromAccount()) ? ResourcesCompat.getDrawable(getResources(), R.drawable.ic_room_super_admin, null) : null, SizeUtils.dp2px(tvContent.getContext(), 23), expLevelHeight); + + // 官方主播認證 + String tvOfficialMask = NobleUtil.getLevel(UserInfo.OAC_NAME, chatRoomMessage).trim(); + String ivOfficialMask = NobleUtil.getLevel(UserInfo.OAC_ICON, chatRoomMessage); + if (!TextUtils.isEmpty(tvOfficialMask) && !TextUtils.isEmpty(ivOfficialMask) && extension != null) { // extension != null 表示自己 + builder.appendBgAndContent(ivOfficialMask, tvOfficialMask); + } else if (!TextUtils.isEmpty(ivOfficialMask)) { + builder.append(ivOfficialMask, SizeUtils.dp2px(tvContent.getContext(), 62), expLevelHeight); + } + //等級 + builder.append(experUrl, expLevelHeight); + builder.append(charmUrl, expLevelHeight); + //vip + builder.append(vipIcon, expLevelHeight); + //佩戴銘牌 + String tvNamePlate = NobleUtil.getNamePlate(UserInfo.NAMEPLATE_WORD, chatRoomMessage).trim(); + String ivNamePlate = NobleUtil.getNamePlate(UserInfo.NAMEPLATE_PIC, chatRoomMessage); + if (!TextUtils.isEmpty(tvNamePlate) && !TextUtils.isEmpty(ivNamePlate)) { // extension != null 表示自己 + builder.appendBgAndContent(ivNamePlate, tvNamePlate); + } else if (!TextUtils.isEmpty(ivNamePlate)) { + builder.append(ivNamePlate, expLevelHeight); + } + + } + + private void addTag(@NonNull TextSpannableBuilder builder, TextView tvContent, View bgView + , String account + , String experUrl + , String charmUrl + , String vipIcon + , String tvNamePlate + , String ivNamePlate + , String androidBubbleUrl + , boolean isOfficial + , boolean newUser + ) { + + builder.append(isOfficial ? ResourcesCompat.getDrawable(getResources(), R.mipmap.ic_user_official_13dp, null) : null, badgeWidth, badgeHeight) + .append(newUser? ResourcesCompat.getDrawable(getResources(), R.drawable.ic_new_user, null) : null, badgeWidth, badgeHeight) + .append(AvRoomDataManager.get().isSuperAdmin(account) ? ResourcesCompat.getDrawable(getResources(), R.drawable.ic_room_super_admin, null) : null, SizeUtils.dp2px(tvContent.getContext(), 23), expLevelHeight); + + //等級 + builder.append(experUrl, expLevelHeight); + builder.append(charmUrl, expLevelHeight); + //vip + builder.append(vipIcon, expLevelHeight); + //佩戴銘牌 + if (!TextUtils.isEmpty(tvNamePlate) && !TextUtils.isEmpty(ivNamePlate)) { // extension != null 表示自己 + builder.appendBgAndContent(ivNamePlate, tvNamePlate); + } else if (!TextUtils.isEmpty(ivNamePlate)) { + builder.append(ivNamePlate, expLevelHeight); + } + + if (bgView !=null && OtherExtKt.isVerify(androidBubbleUrl)){ + bgView.setPadding(paddingWidth, ScreenUtil.dip2px(10), paddingWidth, ScreenUtil.dip2px(10)); + ImageLoadUtils.loadNinePatchBg(bgView, androidBubbleUrl); + } + } + + /** + * 暫時已拋棄 + * + * @param chatRoomMessage - + * @param tvContent - + * @param attachment - + */ + private void setMsgAuction(ChatRoomMessage chatRoomMessage, TextView tvContent, CustomAttachment attachment) { + String senderNick = chatRoomMessage.getChatRoomMessageExtension().getSenderNick(); + senderNick = senderNick == null ? "" : senderNick; + AuctionAttachment auctionAttachment = (AuctionAttachment) attachment; + TextSpannableBuilder builder = new TextSpannableBuilder(tvContent); + if (attachment.getSecond() == CustomAttachment.CUSTOM_MSG_SUB_TYPE_AUCTION_START) { + builder.append(ResUtil.getString(R.string.avroom_widget_messageview_0117), new ForegroundColorSpan(roomTipNickColor)); + } else if (attachment.getSecond() == CustomAttachment.CUSTOM_MSG_SUB_TYPE_AUCTION_FINISH) { + if (auctionAttachment.getAuctionInfo().getCurMaxUid() > 0) { + senderNick = UserInfoHelper.getUserDisplayName(auctionAttachment.getAuctionInfo().getCurMaxUid() + ""); + String voiceActorNick = UserInfoHelper.getUserDisplayName(auctionAttachment.getAuctionInfo().getAuctUid() + ""); + builder.append(senderNick, new ForegroundColorSpan(roomTipNickColor)) + .append(ResUtil.getString(R.string.avroom_widget_messageview_0118) + auctionAttachment.getAuctionInfo().getRivals().get(0).getAuctMoney() + ResUtil.getString(R.string.avroom_widget_messageview_0119)) + .append(voiceActorNick, new ForegroundColorSpan(roomTipNickColor)); + } else + builder.append(ResUtil.getString(R.string.avroom_widget_messageview_0120), new ForegroundColorSpan(roomTipNickColor)); + } else { + builder.append(senderNick, new ForegroundColorSpan(roomTipNickColor)) + .append(ResUtil.getString(R.string.avroom_widget_messageview_0121) + auctionAttachment.getAuctionInfo().getRivals().get(0).getAuctMoney() + ResUtil.getString(R.string.avroom_widget_messageview_027)); + } + tvContent.setText(builder.build()); + } + + /** + * xxx 分享了房間 + * xxx 關註了房主 + * + * @param tvContent - + * @param roomTipAttachment - + */ + private void setMsgRoomTip(TextView tvContent, RoomTipAttachment roomTipAttachment, ChatRoomMessage chatRoomMessage) { + if (TextUtils.isEmpty(roomTipAttachment.getNick())) roomTipAttachment.setNick(""); + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(getNewUserDrawable(chatRoomMessage), badgeWidth, badgeHeight) + .append(RegexUtil.getPrintableString(roomTipAttachment.getNick()), new ForegroundColorSpan(roomTipColor)) + .append(roomTipAttachment.getSecond() == CustomAttachment.CUSTOM_MSG_SUB_TYPE_ROOM_TIP_SHARE_ROOM ? + ResUtil.getString(R.string.avroom_widget_messageview_0123) : ResUtil.getString(R.string.avroom_widget_messageview_0124), new ForegroundColorSpan(greyColor)); + tvContent.setText(text.build()); + } + + /** + * xxx 收藏了房間 + * + * @param tvContent - + * @param roomTipAttachment - + */ + private void setFollowRoomTip(TextView tvContent, RoomTipAttachment roomTipAttachment, ChatRoomMessage chatRoomMessage) { + if (TextUtils.isEmpty(roomTipAttachment.getNick())) roomTipAttachment.setNick(""); + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(getNewUserDrawable(chatRoomMessage), badgeWidth, badgeHeight) + .append(RegexUtil.getPrintableString(roomTipAttachment.getNick()), new ForegroundColorSpan(roomTipColor)) + .append(ResUtil.getString(R.string.avroom_widget_messageview_0125), new ForegroundColorSpan(greyColor)); + tvContent.setText(text.build()); + } + + /** + * {badge}{level} xxx 出 運氣表情 + *

+ * {badge}{level} xxx 出 + * 表情1 表情2 表情3 表情4 表情5 + * + * @param faceAttachment - + * @param chatRoomMessage - + */ + private void setMsgFace(TextView tvContent, FaceAttachment faceAttachment, ChatRoomMessage chatRoomMessage) { + TextSpannableBuilder builder = new TextSpannableBuilder(tvContent); + + String experUrl = NobleUtil.getLevel(UserLevelResourceType.EXPER_URL, chatRoomMessage); + String charmUrl = NobleUtil.getLevel(UserLevelResourceType.CHARM_URL, chatRoomMessage); + String vipIcon = NobleUtil.getResource(UserInfo.VIP_ICON, chatRoomMessage); + + List faceReceiveInfos = faceAttachment.getFaceReceiveInfos(); + FaceReceiveInfo faceReceiveInfo; + FaceInfo faceInfo; + for (int i = 0; i < faceReceiveInfos.size(); i++) { + faceReceiveInfo = faceReceiveInfos.get(i); + faceInfo = DynamicFaceModel.get().findFaceInfoById(faceReceiveInfo.getFaceId()); + if (faceReceiveInfo.getResultIndexes() == null || + faceReceiveInfo.getResultIndexes().size() <= 0 || faceInfo == null) + continue; + String nick = RegexUtil.getPrintableString(faceReceiveInfo.getNick()); + + builder.append(getNewUserDrawable(chatRoomMessage), badgeWidth, badgeHeight) + .append(experUrl, expLevelHeight) + .append(charmUrl, expLevelHeight) + .append(vipIcon, expLevelHeight) + .append(nick, new ForegroundColorSpan(greyColor)) + .append(": " + (faceReceiveInfo.getResultIndexes().size() > 1 ? "\n" : ""), new ForegroundColorSpan(greyColor)); + + //表情 前置处理 + // 幸运数字 + if (faceInfo.getId() == 1 || "Lu".equals(faceInfo.getENName())) { + builder.append(ResourcesKtxKt.getDrawable(R.drawable.ic_lucky_number_icon), bigFace, bigFace); + } +// builder.append(ResourcesKtxKt.getDrawable(R.drawable.ic_lucky_number_icon), bigFace, bigFace); + + List resultIndexes = faceReceiveInfo.getResultIndexes(); + int width = bigFace, height = bigFace; + for (Integer index : resultIndexes) { + // 骰子 + if (faceInfo.getId() == 17 || "shaizi".equals(faceInfo.getENName())) + height = (int) (width / 1.36F); + // 紙牌 + if (faceInfo.getId() == 24 || "pukepai".equals(faceInfo.getENName())) { + width = smallFace;// + height = (int) (width / 0.7F); + } + builder.append(faceInfo.getFacePath(index), width, height); + } + builder.append(faceReceiveInfos.size() - 1 != i ? "\n" : ""); + } + tvContent.setText(builder.build()); + } + + /** + * xxx 全麥送出 {禮物} X數量 + * + * @param tvContent - + * @param giftAttachment - + * @param chatRoomMessage - + */ + private void setMsgMultiGift(TextView tvContent, MultiGiftAttachment giftAttachment, ChatRoomMessage chatRoomMessage) { + GiftInfo giftInfo = giftAttachment.getMultiGiftReceiveInfo().getGift(); + String nick = RegexUtil.getPrintableString(giftAttachment.getMultiGiftReceiveInfo().getNick()); + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(getNewUserDrawable(chatRoomMessage), badgeWidth, badgeHeight) + .append(nick, new ForegroundColorSpan(roomTipNickColor), new OriginalDrawStatusClickSpan() { + + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(chatRoomMessage.getFromAccount()).subscribe(clickConsumer); + } + } + }) + .append(ResUtil.getString(R.string.gift_message_01), new ForegroundColorSpan(getResources().getColor(R.color.white))) + .append(giftInfo == null ? "" : giftInfo.getGiftUrl(), giftLength, giftLength) + .append("X" + giftAttachment.getMultiGiftReceiveInfo().getGiftNum(), new ForegroundColorSpan(getResources().getColor(R.color.white))); + tvContent.setText(text.build()); + tvContent.setOnClickListener(null); + tvContent.setMovementMethod(new LinkMovementMethod()); + } + + /** + * 全麥福袋禮物 + * xxx 全麥送出 {禮物} X數量 + * + * @param tvContent - + * @param giftAttachment - + * @param chatRoomMessage - + */ + private void setMsgAllMicLuckyBagGift(TextView tvContent, MultiLuckyGiftAttachment giftAttachment, ChatRoomMessage chatRoomMessage) { + LuckyBagGifts luckyGiftInfo = giftAttachment.getMultiLuckyGiftReceiveInfo(); + for (int i = 0; i < luckyGiftInfo.getGiftList().size(); i++) { + GiftInfo giftInfo = GiftModel.get().findGiftInfoById(luckyGiftInfo.getGiftList().get(i).getGiftId()); + if (giftInfo != null) { + luckyGiftInfo.getGiftList().get(i).setGiftInfo(giftInfo); + } + } + String nick = RegexUtil.getPrintableString(giftAttachment.getMultiLuckyGiftReceiveInfo().getNick()); + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(getNewUserDrawable(chatRoomMessage), badgeWidth, badgeHeight) + .append(nick, new ForegroundColorSpan(roomTipNickColor), new OriginalDrawStatusClickSpan() { + + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(chatRoomMessage.getFromAccount()).subscribe(clickConsumer); + } + } + }) + .append(ResUtil.getString(R.string.gift_message_01), new ForegroundColorSpan(getResources().getColor(R.color.white))); + + text.append(luckyGiftInfo.getFirstGiftName() + ResUtil.getString(R.string.gift_message_02), new ForegroundColorSpan(getResources().getColor(R.color.white))) + .append(luckyGiftInfo.getUser().getNick(), new ForegroundColorSpan(roomTipNickColor), new OriginalDrawStatusClickSpan() { + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(luckyGiftInfo.getUser().getUid() + "").subscribe(clickConsumer); + } + } + }); + text.append(ResUtil.getString(R.string.gift_message_04)); + for (GiftList luckyGiftList : luckyGiftInfo.getGiftList()) { + if (luckyGiftList.getGiftInfo() == null) continue; + text.append(ResUtil.getString(R.string.gift_message_03) + luckyGiftList.getGiftInfo().getGoldPrice() + ResUtil.getString(R.string.gift_message_05)) + .append(luckyGiftList.getGiftInfo().getGiftUrl(), giftLength, giftLength) + .append("X" + luckyGiftList.getGiftNum(), new ForegroundColorSpan(getResources().getColor(R.color.white))) + .append("、"); + } + Editable msg = text.builder; + msg.delete(msg.length() - 1, msg.length()); + + tvContent.setText(text.build()); + tvContent.setOnClickListener(null); + tvContent.setMovementMethod(new LinkMovementMethod()); + } + + /** + * 發送多人福袋禮物 + * xxx 全麥送出 {禮物} X數量 + * + * @param tvContent - + * @param giftAttachment - + * @param chatRoomMessage - + */ + private void setMsgBatchLuckyBagGift(TextView tvContent, MultiLuckyGiftAttachment giftAttachment, ChatRoomMessage chatRoomMessage) { + LuckyBagGifts luckyGiftInfo = giftAttachment.getMultiLuckyGiftReceiveInfo(); + for (int i = 0; i < luckyGiftInfo.getGiftList().size(); i++) { + GiftInfo giftInfo = GiftModel.get().findGiftInfoById(luckyGiftInfo.getGiftList().get(i).getGiftId()); + if (giftInfo != null) { + luckyGiftInfo.getGiftList().get(i).setGiftInfo(giftInfo); + } + } + String nick = RegexUtil.getPrintableString(giftAttachment.getMultiLuckyGiftReceiveInfo().getNick()); + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(getNewUserDrawable(chatRoomMessage), badgeWidth, badgeHeight) + .append(nick, new ForegroundColorSpan(roomTipNickColor), new OriginalDrawStatusClickSpan() { + + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(chatRoomMessage.getFromAccount()).subscribe(clickConsumer); + } + } + }) + .append(ResUtil.getString(R.string.gift_message_01), new ForegroundColorSpan(getResources().getColor(R.color.white))); + + text.append(luckyGiftInfo.getFirstGiftName() + ResUtil.getString(R.string.gift_message_02), new ForegroundColorSpan(getResources().getColor(R.color.white))) + .append(luckyGiftInfo.getUser().getNick(), new ForegroundColorSpan(roomTipNickColor), new OriginalDrawStatusClickSpan() { + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(luckyGiftInfo.getUser().getUid() + "").subscribe(clickConsumer); + } + } + }); + text.append(ResUtil.getString(R.string.gift_message_04)); + for (GiftList luckyGiftList : luckyGiftInfo.getGiftList()) { + if (luckyGiftList.getGiftInfo() == null) continue; + text.append(ResUtil.getString(R.string.gift_message_03) + luckyGiftList.getGiftInfo().getGoldPrice() + ResUtil.getString(R.string.gift_message_05)) + .append(luckyGiftList.getGiftInfo().getGiftUrl(), giftLength, giftLength) + .append("X" + luckyGiftList.getGiftNum(), new ForegroundColorSpan(getResources().getColor(R.color.white))) + .append("、"); + } + + + Editable msg = text.builder; + msg.delete(msg.length() - 1, msg.length()); + tvContent.setText(text.build()); + tvContent.setOnClickListener(null); + tvContent.setMovementMethod(new LinkMovementMethod()); + } + + /** + * xxx 送給xxx,xxx,xxx... {禮物} X數量 + * + * @param tvContent + * @param attachment + * @param chatRoomMessage + */ + private void setMsgBatchGift(TextView tvContent, GiftBatchAttachment attachment, ChatRoomMessage chatRoomMessage) { + GiftInfo giftInfo = attachment.getGiftMultiReceiverInfo().getGift(); + String nick = RegexUtil.getPrintableString(attachment.getGiftMultiReceiverInfo().getNick()); + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(getNewUserDrawable(chatRoomMessage), badgeWidth, badgeHeight) + .append(nick, new ForegroundColorSpan(roomTipNickColor), new OriginalDrawStatusClickSpan() { + + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(chatRoomMessage.getFromAccount()).subscribe(clickConsumer); + } + } + }) + .append(ResUtil.getString(R.string.gift_message_06), new ForegroundColorSpan(getResources().getColor(R.color.white))); + + for (GiftReceiver targetUser : attachment.getGiftMultiReceiverInfo().getTargetUsers()) { + text.append(targetUser.getNick(), new ForegroundColorSpan(roomTipNickColor), new OriginalDrawStatusClickSpan() { + + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(targetUser.getUid() + "").subscribe(clickConsumer); + } + } + }) + .append(","); + } + Editable msg = text.builder; + msg.delete(msg.length() - 1, msg.length()); + text.append(giftInfo == null ? "" : giftInfo.getGiftUrl(), giftLength, giftLength) + .append(" X" + attachment.getGiftMultiReceiverInfo().getGiftNum(), new ForegroundColorSpan(getResources().getColor(R.color.white))); + tvContent.setText(text.build()); + tvContent.setOnClickListener(null); + tvContent.setMovementMethod(new LinkMovementMethod()); + } + + /** + * {badge}xxx給全麥施魔法{魔法} + * + * @param tvContent - + * @param magicAllMicAttachment - + * @param chatRoomMessage - + */ + private void setAllMicMagicMsg(TextView tvContent, MagicAllMicAttachment magicAllMicAttachment, ChatRoomMessage chatRoomMessage) { + MultiMagicReceivedInfo multiMagicReceivedInfo = magicAllMicAttachment.getMultiMagicReceivedInfo(); + if (multiMagicReceivedInfo == null) return; + MagicInfo magicInfo = MagicModel.get().getMagicInfo(multiMagicReceivedInfo.getMagicId()); + String nick = RegexUtil.getPrintableString(multiMagicReceivedInfo.getNick()); + boolean showEffect = multiMagicReceivedInfo.isNeedShowExplode(); + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(getNewUserDrawable(chatRoomMessage), badgeWidth, badgeHeight) + .append(nick, new ForegroundColorSpan(roomTipNickColor), new OriginalDrawStatusClickSpan() { + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(chatRoomMessage.getFromAccount()).subscribe(clickConsumer); + } + } + }) + .append(ResUtil.getString(R.string.avroom_widget_messageview_0138), new ForegroundColorSpan(getResources().getColor(R.color.white))) + .append(magicInfo == null ? "" : TextUtils.isEmpty(magicInfo.getIcon()) ? "" : magicInfo.getIcon(), giftLength, giftLength) + .append(showEffect ? ResUtil.getString(R.string.avroom_widget_messageview_0139) : "", new ForegroundColorSpan(getResources().getColor(R.color.white))) + .append(showEffect ? ResUtil.getString(R.string.avroom_widget_messageview_0140) : "", new ForegroundColorSpan(roomTipNickColor)); + tvContent.setText(text.build()); + tvContent.setOnClickListener(null); + tvContent.setMovementMethod(new LinkMovementMethod()); + } + + /** + * xxx 送給xxx,xxx,xxx... {魔法} X數量 + * + * @param tvContent - + * @param magicBatchAttachment - + * @param chatRoomMessage - + */ + private void setMsgBatchMagic(TextView tvContent, MagicBatchAttachment magicBatchAttachment, ChatRoomMessage chatRoomMessage) { + MagicMultiReceiverInfo magicMultiReceiverInfo = magicBatchAttachment.getMagicMultiReceiverInfo(); + if (magicMultiReceiverInfo == null) { + return; + } + MagicInfo magicInfo = MagicModel.get().getMagicInfo(magicMultiReceiverInfo.getMagicId()); + String nick = RegexUtil.getPrintableString(magicMultiReceiverInfo.getNick()); + boolean showEffect = magicMultiReceiverInfo.isNeedShowExplode(); + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(getNewUserDrawable(chatRoomMessage), badgeWidth, badgeHeight) + .append(nick, new ForegroundColorSpan(roomTipNickColor), new OriginalDrawStatusClickSpan() { + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(chatRoomMessage.getFromAccount()).subscribe(clickConsumer); + } + } + }) + .append(ResUtil.getString(R.string.avroom_widget_messageview_0141), new ForegroundColorSpan(getResources().getColor(R.color.white))); + + for (MagicReceiver targetUser : magicMultiReceiverInfo.getTargetUsers()) { + text.append(targetUser.getNick(), new ForegroundColorSpan(roomTipNickColor), new OriginalDrawStatusClickSpan() { + + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(targetUser.getUid() + "").subscribe(clickConsumer); + } + } + }) + .append(","); + } + Editable msg = text.builder; + msg.delete(msg.length() - 1, msg.length()); + + text.append(ResUtil.getString(R.string.avroom_widget_messageview_0142), new ForegroundColorSpan(getResources().getColor(R.color.white))) + .append(magicInfo == null ? "" : TextUtils.isEmpty(magicInfo.getIcon()) ? "" : magicInfo.getIcon(), giftLength, giftLength) + .append(" X" + magicMultiReceiverInfo.getNumber(), new ForegroundColorSpan(getResources().getColor(R.color.white))) + .append(showEffect ? ResUtil.getString(R.string.avroom_widget_messageview_0143) : "", new ForegroundColorSpan(getResources().getColor(R.color.white))) + .append(showEffect ? ResUtil.getString(R.string.avroom_widget_messageview_0144) : "", new ForegroundColorSpan(roomTipNickColor)); + tvContent.setText(text.build()); + tvContent.setOnClickListener(null); + tvContent.setMovementMethod(new LinkMovementMethod()); + + } + + /** + * {badge}xxx給{badge}xxx施魔法{魔法} + * + * @param tvContent - + * @param magicAttachment - + * @param chatRoomMessage - + */ + private void setSingleMagicMsg(TextView tvContent, MagicAttachment magicAttachment, ChatRoomMessage chatRoomMessage) { + MagicReceivedInfo magicReceivedInfo = magicAttachment.getMagicReceivedInfo(); + if (magicReceivedInfo == null) return; + MagicInfo magicInfo = MagicModel.get().getMagicInfo(magicReceivedInfo.getMagicId()); + boolean showEffect = magicReceivedInfo.isNeedShowExplodeEffect(); + String nick = RegexUtil.getPrintableString(magicReceivedInfo.getNick()); + String targetNick = RegexUtil.getPrintableString(magicReceivedInfo.getTargetNick()); + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(getNewUserDrawable(chatRoomMessage), badgeWidth, badgeHeight) + .append(nick, new ForegroundColorSpan(roomTipNickColor), new OriginalDrawStatusClickSpan() { + + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(chatRoomMessage.getFromAccount()).subscribe(clickConsumer); + } + } + }) + .append(ResUtil.getString(R.string.avroom_widget_messageview_0145), new ForegroundColorSpan(getResources().getColor(R.color.white))) + .append(targetNick, new ForegroundColorSpan(roomTipNickColor), new OriginalDrawStatusClickSpan() { + + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(magicReceivedInfo.getTargetUid() + "").subscribe(clickConsumer); + } + } + }) + .append(ResUtil.getString(R.string.avroom_widget_messageview_0146), new ForegroundColorSpan(getResources().getColor(R.color.white))) + .append(magicInfo == null ? "" : TextUtils.isEmpty(magicInfo.getIcon()) ? "" : magicInfo.getIcon(), giftLength, giftLength) + .append(showEffect ? ResUtil.getString(R.string.avroom_widget_messageview_0147) : "", new ForegroundColorSpan(getResources().getColor(R.color.white))) + .append(showEffect ? ResUtil.getString(R.string.avroom_widget_messageview_0148) : "", new ForegroundColorSpan(roomTipNickColor)); + tvContent.setText(text.build()); + tvContent.setOnClickListener(null); + tvContent.setMovementMethod(new LinkMovementMethod()); + } + + /** + * {badge}xxx送給{badge}xxx {禮物} X數量 + * + * @param tvContent - + * @param giftAttachment - + * @param chatRoomMessage - + */ + private void setMsgHeaderGift(TextView tvContent, GiftAttachment giftAttachment, ChatRoomMessage chatRoomMessage) { + GiftReceiveInfo giftReceiveInfo = giftAttachment.getGiftReceiveInfo(); + if (giftReceiveInfo == null) return; + String nick = RegexUtil.getPrintableString(giftReceiveInfo.getNick()); + String targetNick = RegexUtil.getPrintableString(giftReceiveInfo.getTargetNick()); + String num = "X" + giftReceiveInfo.getGiftNum(); + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(getNewUserDrawable(chatRoomMessage), badgeWidth, badgeHeight) + .append(nick, new ForegroundColorSpan(roomTipNickColor), new OriginalDrawStatusClickSpan() { + + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(chatRoomMessage.getFromAccount()).subscribe(clickConsumer); + } + } + }) + .append(ResUtil.getString(R.string.gift_message_06), new ForegroundColorSpan(getResources().getColor(R.color.white))) + .append(targetNick, new ForegroundColorSpan(roomTipNickColor), new OriginalDrawStatusClickSpan() { + + @Override + public void onClick(@NonNull View widget) { + if (clickConsumer != null) { + Single.just(giftReceiveInfo.getTargetUid() + "").subscribe(clickConsumer); + } + } + }) + .append(giftReceiveInfo.getGift() == null ? "" : giftReceiveInfo.getGift().getGiftUrl(), giftLength, giftLength) + .append(num, new ForegroundColorSpan(getResources().getColor(R.color.white))); + tvContent.setText(text.build()); + tvContent.setOnClickListener(null); + tvContent.setMovementMethod(new LinkMovementMethod()); + } + + /** + * {boom图片} 恭喜! {用户名} 触发了超级大奖BOOM... + */ + private void setMsgBoom(TextView tvContent, BoomMsgAttachment boomMsgAttachment) { + if (boomMsgAttachment == null || boomMsgAttachment.DialogBean == null) return; + BoomMsgDialogBean data = boomMsgAttachment.DialogBean; + String boomUrl = data.getPic(); + String nick = RegexUtil.getPrintableString(data.getNick()); + String text = ResUtil.getString(R.string.roomBoomMessageView, nick); +// tvContent.setText(text); + + + SpannableString spStr = new SpannableString(text); + int start = text.indexOf(nick); + int end = start + nick.length(); + ForegroundColorSpan colorSpan = new ForegroundColorSpan(Color.parseColor("#FF3b3b")); + spStr.setSpan(colorSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + + TextSpannableBuilder textSpan = new TextSpannableBuilder(tvContent) + .append(boomUrl, boomWidth, boomHeight) + .append(spStr); + +// TextSpannableBuilder textSpan = new TextSpannableBuilder(tvContent) +// .append(boomUrl, boomWidth, boomHeight) +// .append(ResUtil.getString(R.string.avroom_widget_roomeffectview_04), new ForegroundColorSpan(getResources().getColor(R.color.white))) +// .append(" "+nick+" ", new ForegroundColorSpan(Color.parseColor("#FF3b3b"))) +// .append(ResUtil.getString(R.string.roomBoomMessageView), new ForegroundColorSpan(getResources().getColor(R.color.white))); + tvContent.setText(textSpan.build()); + + tvContent.setOnClickListener(null); + tvContent.setMovementMethod(new LinkMovementMethod()); + tvContent.setBackgroundResource(R.drawable.shape_room_message_bg); + + LogUtils.dd(" RoomBoomManager Boom公屏消息 level = "+data.getLevel() + " boomUrl = "+ boomUrl + " nick = "+nick); + + } + + /** + * {badge}xxx來了 + * + * @param chatRoomMessage - + * @param tvContent - + */ + private void setMsgNotification(ChatRoomMessage chatRoomMessage, TextView tvContent, int position) { + int fromType = 0; + String fromNick = ""; + String fromUid = ""; + Map remoteExtension = chatRoomMessage.getRemoteExtension(); + if (remoteExtension != null) { + fromType = (int) remoteExtension.get("fromType"); + fromNick = (String) remoteExtension.get("fromNick"); + fromUid = (String) remoteExtension.get("fromUid"); + } + ChatRoomNotificationAttachment attachment = (ChatRoomNotificationAttachment) chatRoomMessage.getAttachment(); + + String senderNick = ""; + List nicks = attachment.getTargetNicks(); + if (nicks != null && nicks.size() > 0) senderNick = RegexUtil.getPrintableString(attachment.getTargetNicks().get(0)); + ArrayList targets = attachment.getTargets(); + + if (OtherExtKt.isVerify(targets) && OtherExtKt.isVerify(0,targets)) { + String uid = targets.get(0); + ChatRoomMessageExtension chatRoomMessageExtension = chatRoomMessage.getChatRoomMessageExtension(); + if (chatRoomMessageExtension != null) { + Map senderExtension = chatRoomMessageExtension.getSenderExtension(); + if (senderExtension != null) { + Object o = ((Map) chatRoomMessage.getChatRoomMessageExtension().getSenderExtension()).get(uid); + if (o != null) { + String json = JSON.toJSONString(o); +// OtherExtKt.doLog(json); + String nick = MyJsonUtils.getString(json, UserInfo.NICK, ""); + if (OtherExtKt.isVerify(nick)) { + senderNick = nick; + } + } + } + } + } + + + if (attachment.getType() != NotificationType.ChatRoomMemberIn) return; + + OtherExtKt.doLog("进房 fromType = "+fromType); + + // 座駕 + String carName = NobleUtil.getCarName(CarInfo.CAR_NAME, chatRoomMessage); + carName = TextUtils.isEmpty(carName) ? "" : "\"" + carName + "\""; + + TextSpannableBuilder text = new TextSpannableBuilder(tvContent); + addCommonTag(chatRoomMessage, text, tvContent); + text.append(senderNick, new ForegroundColorSpan(roomTipColor), + new OriginalDrawStatusClickSpan() { + @Override + public void onClick(@NonNull View view) { + if (clickConsumer != null) { + Single.just(chatRoomMessage.getFromAccount()) + .doOnSuccess(clickConsumer).subscribe(); + } + } + }); + + text.append(TextUtils.isEmpty(carName) ? "" : ResUtil.getString(R.string.avroom_widget_messageview_0150), new ForegroundColorSpan(greyColor)) + .append(carName, new ForegroundColorSpan(roomTipColor)); + String enterText = ResUtil.getString(R.string.avroom_widget_messageview_0151); + if (fromType == AVRoomActivity.FROM_TYPE_RECOMMEND) { + enterText = ResUtil.getString(R.string.avroom_widget_messageview_0152); + } + if (fromType == AVRoomActivity.FROM_TYPE_USER || fromType == AVRoomActivity.FROM_TYPE_HELLO) { + String finalFromUid = fromUid; + text.append(ResUtil.getString(R.string.avroom_widget_messageview_0153), new ForegroundColorSpan(whiteColor)) + .append(fromNick, new ForegroundColorSpan(roomTipColor), + new OriginalDrawStatusClickSpan() { + @Override + public void onClick(@NonNull View view) { + if (clickConsumer != null) { + Single.just(finalFromUid).doOnSuccess(clickConsumer).subscribe(); + } + } + }); + enterText = ResUtil.getString(R.string.avroom_widget_messageview_0154); + } + + if (fromType == AVRoomActivity.FROM_TYPE_GAME_RECOMMEND) { + String finalFromUid = fromUid; + text.append(ResUtil.getString(R.string.avroom_widget_messageview_0155), new ForegroundColorSpan(whiteColor)) + .append(fromNick, new ForegroundColorSpan(roomTipColor), + new OriginalDrawStatusClickSpan() { + @Override + public void onClick(@NonNull View view) { + if (clickConsumer != null) { + Single.just(finalFromUid).doOnSuccess(clickConsumer).subscribe(); + } + } + }); + enterText = ResUtil.getString(R.string.avroom_widget_messageview_0156); + } + + text.append(enterText, new ForegroundColorSpan(whiteColor)); + + //如果自己在麥上,增加一個歡迎ta的按鈕,並且這條消息不是自己的 + if (AvRoomDataManager.get().isOwnerOnMic() + && !UserModel.get().isMyseft(chatRoomMessage.getFromAccount()) + && !ExtensionUtil.isWelcomeLocal(chatRoomMessage)) { + text.append( + ResourcesCompat.getDrawable(getResources(), + R.drawable.icon_room_welcome, null), + UIUtil.dip2px(mContext, 47), + UIUtil.dip2px(mContext, 17), + new OriginalDrawStatusClickSpan() { + @Override + public void onClick(@NonNull View view) { + ExtensionUtil.setWelcomeLocal(chatRoomMessage, true); + mMessageAdapter.notifyItemChanged(position); + long targetUid = JavaUtil.str2long(chatRoomMessage.getFromAccount()); + Single.zip(AvRoomModel.get().getWelcomeConfig(targetUid), + UserModel.get().getUserInfo(targetUid), (roomWelcomeConfig, info) -> { + WelcomeInfo welcomeInfo = new WelcomeInfo(); + welcomeInfo.setContent(roomWelcomeConfig.getMsg()); + welcomeInfo.setTargetUid(targetUid); + welcomeInfo.setTargetNick(info.getNick()); + welcomeInfo.setFans(roomWelcomeConfig.isFans()); + return welcomeInfo; + }) + .observeOn(AndroidSchedulers.mainThread()) + .flatMap((Function>) welcomeInfo -> { + WelcomeAttachment attachment = new WelcomeAttachment(); + attachment.setWelcomeInfo(welcomeInfo); + return ImHelperUtils.sendChatRoomMessage(attachment); + }) + //添加到自己的公屏 + .doOnSuccess(chatRoomMessage -> + IMNetEaseManager.get().addMessages(chatRoomMessage)) + .doOnError(throwable -> { + LogUtil.e("send welcome msg failed, error: " + throwable.getMessage()); + }) + .subscribe(); + } + }); + } + + tvContent.setText(text.build()); + tvContent.setOnClickListener(null); + tvContent.setMovementMethod(new LinkMovementMethod()); + } + + private TextSpannableBuilder getNotificationBuilder(TextView tvContent, String senderNick, String desc, String tagNick, String carName) { + return new TextSpannableBuilder(tvContent) + .append(senderNick, new ForegroundColorSpan(roomTipColor)) + .append(desc, new ForegroundColorSpan(textColor)) + .append(tagNick, new ForegroundColorSpan(roomTipColor)) + .append((TextUtils.isEmpty(carName) ? "" : ResUtil.getString(R.string.avroom_widget_messageview_0158))) + .append(carName, new ForegroundColorSpan(roomTipColor)) + .append(ResUtil.getString(R.string.avroom_widget_messageview_0159), new ForegroundColorSpan(textColor)); + } + + /** + * 恭喜 xxx 在房間內 續費/開通 "皇帝" + * + * @param chatRoomMessage - + * @param tvContent - + */ + private void setMsgNobleOpenOrRenewText(ChatRoomMessage chatRoomMessage, TextView tvContent) { + NobleAttachment attachment = (NobleAttachment) chatRoomMessage.getAttachment(); + NobleInfo nobleInfo = attachment.nobleInfo; + if (nobleInfo == null) return; + int first = attachment.getFirst(); + if (first != CustomAttachment.CUSTOM_MESS_HEAD_NOBLE) return; + int second = attachment.getSecond(); + if (second != CustomAttachment.CUSTOM_MESS_SUB_OPENNOBLE + && second != CustomAttachment.CUSTOM_MESS_SUB_RENEWNOBLE) + return; + String senderNick = RegexUtil.getPrintableString(attachment.nick); + // 系統通知icon + Drawable icNotification = mContext.getResources().getDrawable(R.drawable.ic_system_notification); + int width = (int) (icNotification.getIntrinsicWidth() / (icNotification.getIntrinsicHeight() + 0.F) * sysIconHeight); + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append(icNotification, width, sysIconHeight) + .append(" 恭喜 ", new ForegroundColorSpan(greyColor)) + .append(senderNick, new ForegroundColorSpan(roomTipColor)) + .append(" 在房間內" + (second == CustomAttachment.CUSTOM_MESS_SUB_RENEWNOBLE ? "續費" : "開通") + "\"", new ForegroundColorSpan(greyColor)) + .append(nobleInfo.getName(), new ForegroundColorSpan(roomTipColor)) + .append("\""); + tvContent.setText(text.build()); + } + + /** + * 瓜分鉆石的消息,二級和三級都有 + * + * @param chatRoomMessage + * @param tvContent + */ + private void setCarveUpGoldMsg(ChatRoomMessage chatRoomMessage, TextView tvContent) { + if (!(chatRoomMessage.getAttachment() instanceof CarveUpGoldAttachment)) { + return; + } + CarveUpGoldAttachment attachment = (CarveUpGoldAttachment) chatRoomMessage.getAttachment(); + // 內容 + TextSpannableBuilder text = new TextSpannableBuilder(tvContent) + .append("【簽到瓜分百萬】哇塞,恭喜 ", new ForegroundColorSpan(greyColor)) + .append(attachment.getNick() + " ", new ForegroundColorSpan(roomTipColor)) + .append("簽到獲得 ", new ForegroundColorSpan(greyColor)) + .append(attachment.getGoldNum() + "金幣", new ForegroundColorSpan(roomTipColor)) + .append("!", new ForegroundColorSpan(greyColor)); + tvContent.setText(text.build()); + } + + /** + * 麥上用戶對你的歡迎語 + */ + private void setMicWelcomeContent(ChatRoomMessage chatRoomMessage, TextView tvContent, int position) { + tvContent.setOnClickListener(null); + tvContent.setMovementMethod(new LinkMovementMethod()); + if (!(chatRoomMessage.getAttachment() instanceof WelcomeAttachment)) { + return; + } + WelcomeAttachment attachment = (WelcomeAttachment) chatRoomMessage.getAttachment(); + WelcomeInfo welcomeInfo = attachment.getWelcomeInfo(); + if (welcomeInfo == null) { + return; + } + ChatRoomMessageExtension extension = chatRoomMessage.getChatRoomMessageExtension(); + // 內容 + String fromAccount = chatRoomMessage.getFromAccount(); + TextSpannableBuilder text = new TextSpannableBuilder(tvContent); + addCommonTag(chatRoomMessage, text, tvContent); + text.append(extension == null ? getContext().getString(R.string.ui_widget_userinfodialog_01) : RegexUtil.getPrintableString(extension.getSenderNick()), + new ForegroundColorSpan(greyColor), + new OriginalDrawStatusClickSpan() { + @Override + public void onClick(@NonNull View widget) { + Single.just(String.valueOf(chatRoomMessage.getFromAccount())) + .doOnSuccess(clickConsumer).subscribe(); + } + }) + .append(":" + welcomeInfo.getLastConent(), new ForegroundColorSpan(whiteColor)) + .append(welcomeInfo.getTargetNick(), new ForegroundColorSpan(roomTipNickColor), + new OriginalDrawStatusClickSpan() { + @Override + public void onClick(@NonNull View widget) { + Single.just(String.valueOf(welcomeInfo.getTargetUid())) + .doOnSuccess(clickConsumer).subscribe(); + } + }) + .append(welcomeInfo.getNextContent(), new ForegroundColorSpan(whiteColor)); + + //自己的消息不顯示關註按鈕 + //被歡迎人必須是自己 + if (!UserModel.get().isMyseft(fromAccount) && UserModel.get().isMyseft(welcomeInfo.getTargetUid())) { + if (!welcomeInfo.isFans()) { + text.append(" ").append( + ResourcesCompat.getDrawable(getResources(), + R.drawable.icon_room_attent, null), + UIUtil.dip2px(mContext, 47), + UIUtil.dip2px(mContext, 17), + new OriginalDrawStatusClickSpan() { + @Override + public void onClick(@NonNull View view) { + if (welcomeInfo.isConnecting()) { + return; + } + + welcomeInfo.setConnecting(true); + //關註 + PraiseModel.get().praise(JavaUtil.str2long(chatRoomMessage.getFromAccount()), true) + .compose(RxHelper.bindContext(mContext)) + .subscribe(new DontWarnObserver() { + @Override + public void accept(String s, String error) { + super.accept(s, error); + welcomeInfo.setConnecting(false); + if (error != null) { + SingleToastUtil.showToast(error); + return; + } + welcomeInfo.setFans(true); + welcomeInfo.setShowAttentedBtn(true); + mMessageAdapter.notifyItemChanged(position); + } + }); + + } + }); + } else if (welcomeInfo.isShowAttentedBtn()) { + text.append(" ").append( + ResourcesCompat.getDrawable(getResources(), + R.drawable.icon_room_attent_gray, null), + UIUtil.dip2px(mContext, 47), + UIUtil.dip2px(mContext, 17)); + } + } + + tvContent.setText(text.build()); + + } + + @Nullable + private Drawable getNewUserDrawable(ChatRoomMessage chatRoomMessage) { + boolean newUser = NobleUtil.getIsNewUser(UserInfo.IS_NEW_USER, chatRoomMessage); //newUser + boolean isHelloUser = NobleUtil.getIsNewUser(UserInfo.IS_FROM_SAY_HELLO_CHANNEL, chatRoomMessage); //fromSayHelloChannel + if (newUser) { + return ResourcesCompat.getDrawable(getResources(), isHelloUser ? R.drawable.ic_new_user_hello : R.drawable.ic_new_user, null); + } + return null; + } + + + @SuppressLint("CheckResult") + @Override + public void onClick(View v) { + String account = ""; + ChatRoomMessage chatRoomMessage = (ChatRoomMessage) v.getTag(); + if (chatRoomMessage.getMsgType() != MsgTypeEnum.tip) { + if (chatRoomMessage.getMsgType() == MsgTypeEnum.text) { + account = chatRoomMessage.getFromAccount(); + } else if (chatRoomMessage.getMsgType() == MsgTypeEnum.notification) { + account = chatRoomMessage.getFromAccount(); + } else if (chatRoomMessage.getMsgType() == MsgTypeEnum.custom) { + CustomAttachment attachment = (CustomAttachment) chatRoomMessage.getAttachment(); + if (attachment.getFirst() == CustomAttachment.CUSTOM_MSG_HEADER_TYPE_ROOM_TIP) { + account = ((RoomTipAttachment) attachment).getUid() + ""; + } else if (attachment.getFirst() == CustomAttachment.CUSTOM_MSG_BOX) { + account = String.valueOf(((RoomBoxPrizeAttachment) attachment).getUid()); + } else if (attachment.getFirst() == CustomAttachment.CUSTOM_MSG_HEADER_TYPE_QUEUE) { + long handleUid = ((RoomQueueMsgAttachment) attachment).handleUid; + if (handleUid > 0) { + account = ((RoomQueueMsgAttachment) attachment).handleUid + ""; + } else { + //ios沒用handleUid,導致iOS發的自定義消息,拿不到uid + account = chatRoomMessage.getFromAccount(); + } + } else if (attachment.getFirst() == CustomAttachment.CUSTOM_MSG_HEADER_TYPE_MONSTER_HUNTING) { + switch (attachment.getSecond()) { + case CustomAttachment.CUSTOM_MSG_SUB_TYPE_MONSTER_HUNTING: + MonsterDataBean dataBean = ((MonsterStatusAttachment) attachment).getDataBean(); + RoomInfo mCurrentRoomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (!Objects.equals(mCurrentRoomInfo.getUid(), dataBean.getAppearRoomUid())) { + AVRoomActivity.start(getContext(), dataBean.getAppearRoomUid()); + } else { + SingleToastUtil.showToast("你已經在怪獸房間內"); + } + break; + + case CustomAttachment.CUSTOM_NOTI_SUB_GAME_RESULT: + MonsterHuntingResult result = ((MonsterHuntingResultAttachment) attachment).getResult(); + UIHelper.showMonsterResult(getContext(), String.valueOf(result.getMonster().getMonsterId())); + break; + } + } else if (attachment.getFirst() == CustomAttachment.CUSTOM_MESS_HEAD_ROOM_PK) { + if (attachment.getSecond() == CustomAttachment.CUSTOM_MESS_SUB_ROOM_PK_RESULT) { + RoomTeamPKResultDialog pkResultDialog = new RoomTeamPKResultDialog(getContext(), ((RoomPkAttachment) attachment).getRoomPkData()); + pkResultDialog.show(); + } + } else if (attachment instanceof RoomFollowOwnerAttachment2 && !AvRoomDataManager.get().isRoomFans) { + CollectionRoomModel.get().followRoom("1", ((RoomFollowOwnerAttachment2) attachment).getOwnerUid()) + .subscribe(s -> { + AvRoomDataManager.get().isRoomFans = true; + SingleToastUtil.showToast("收藏成功!"); + EventBus.getDefault().post(new FollowRoomEvent()); + PraiseModel.get().setFollowRoomSuccessRoomTip(JavaUtil.str2long(chatRoomMessage.getFromAccount())); + }); + } else if (attachment.getFirst() == CustomAttachment.CUSTOM_MESS_TAROT) { + if (attachment instanceof TarotAttachment) { + account = ((TarotAttachment) attachment).getTarotMsgBean().getUid() + ""; + } + } + } + if (TextUtils.isEmpty(account)) return; + if (clickConsumer != null) { + Single.just(account).subscribe(clickConsumer); + } + } else { + String content = chatRoomMessage.getContent(); + if (!TextUtils.isEmpty(content) && content.equals(ResUtil.getString(R.string.yizhuan_xchat_android_constants_xchatconstants_08))) + if (onClick != null) { + onClick.onShowRoomIntroduction(); + } + } + } + + class MessageViewHolder extends RecyclerView.ViewHolder { + TextView tvContent; + + public MessageViewHolder(View itemView) { + super(itemView); + tvContent = itemView.findViewById(R.id.tv_content); + } + } + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/widget/MicroView.java b/app/src/main/java/com/chwl/app/avroom/widget/MicroView.java new file mode 100644 index 0000000..6ecb0c1 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/widget/MicroView.java @@ -0,0 +1,368 @@ +package com.chwl.app.avroom.widget; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Point; +import android.graphics.drawable.AnimationDrawable; +import android.graphics.drawable.Drawable; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.util.SparseArray; +import android.view.View; +import android.widget.ImageView; +import android.widget.LinearLayout; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.RecyclerView; + +import com.chwl.app.R; +import com.chwl.app.avroom.adapter.BaseMicroViewAdapter; +import com.chwl.app.avroom.adapter.DatingMicroViewAdapter; +import com.chwl.app.avroom.adapter.OnMicroItemClickListener; +import com.chwl.app.ui.anim.AnimFactory; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.ui.widget.recyclerview.decoration.DatingItemDecoration; +import com.chwl.app.utils.ResourceManager; +import com.chwl.core.bean.RoomQueueInfo; +import com.chwl.core.gift.bean.RoomMicDress; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.manager.IMNetEaseManager; +import com.chwl.core.manager.RoomEvent; +import com.chwl.core.noble.NobleResourceType; +import com.chwl.core.noble.NobleUtil; +import com.chwl.core.room.event.ReceiveFaceEvent; +import com.chwl.core.room.face.FaceReceiveInfo; +import com.chwl.core.utils.LogUtils; +import com.chwl.library.common.util.OtherExtKt; +import com.chwl.library.widget.SVGAView; +import com.example.lib_utils.UiUtils; +import com.opensource.svgaplayer.SVGADrawable; +import com.opensource.svgaplayer.SVGAImageView; +import com.opensource.svgaplayer.SVGAParser; +import com.opensource.svgaplayer.SVGAVideoEntity; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.List; + +import io.reactivex.disposables.Disposable; + +/** + * 上麦布局界面 + * + * @author xiaoyu + * @date 2017/12/20 + */ +public class MicroView extends LinearLayout implements View.OnLayoutChangeListener { + private static final String TAG = "MicroView"; + public RecyclerView recyclerView; + private Context mContext; + private int giftWidth; + private int giftHeight; + + private Disposable subscribe; + + private boolean isNeedResetMicCenterPoint = true; + + private DatingItemDecoration datingItemDecoration; + private OnMicroItemClickListener onMicroItemClickListener = null; + + public MicroView(Context context) { + this(context, null); + } + + public MicroView(Context context, AttributeSet attr) { + this(context, attr, 0); + } + + public MicroView(Context context, AttributeSet attr, int i) { + super(context, attr, i); + init(context); + } + + public void setOnMicroItemClickListener(OnMicroItemClickListener onMicroItemClickListener) { + this.onMicroItemClickListener = onMicroItemClickListener; + if (recyclerView != null && recyclerView.getAdapter() instanceof BaseMicroViewAdapter) { + ((BaseMicroViewAdapter) recyclerView.getAdapter()).setOnMicroItemClickListener(onMicroItemClickListener); + } + } + + private void init(final Context context) { + this.mContext = context; + inflate(mContext, R.layout.layout_micro_view, this); + recyclerView = findViewById(R.id.recycler_view); + recyclerView.addOnLayoutChangeListener(this); + giftWidth = UIUtil.dip2px(mContext, 80); + giftHeight = UIUtil.dip2px(mContext, 80); + } + + public void bindAdapter(@NonNull BaseMicroViewAdapter adapter) { + if (adapter instanceof DatingMicroViewAdapter) { + if (datingItemDecoration == null) datingItemDecoration = new DatingItemDecoration(UiUtils.INSTANCE.isRtl(getContext())); + recyclerView.addItemDecoration(datingItemDecoration); + } else if (datingItemDecoration != null) { + recyclerView.removeItemDecoration(datingItemDecoration); + } + adapter.bindToRecyclerView(recyclerView); + adapter.setOnMicroItemClickListener(onMicroItemClickListener); + } + + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + EventBus.getDefault().register(this); + subMsg(); + } + + private void subMsg() { + if (isInEditMode()) { + return; + } + subscribe = IMNetEaseManager.get() + .getChatRoomEventObservable().subscribe( + roomEvent -> onReceiveRoomEvent(roomEvent), + throwable -> subMsg()); + } + + @Override + protected void onDetachedFromWindow() { + EventBus.getDefault().unregister(this); + if (subscribe != null) { + subscribe.dispose(); + subscribe = null; + } + + if (recyclerView != null) { + RecyclerView.Adapter adapter = recyclerView.getAdapter(); + if (adapter != null) { + if (adapter instanceof BaseMicroViewAdapter) { + ((BaseMicroViewAdapter) adapter).setOnMicroItemClickListener(null); + } + } + } + + super.onDetachedFromWindow(); + } + + private void onReceiveRoomEvent(RoomEvent roomEvent) { + if (roomEvent == null || roomEvent.getEvent() == RoomEvent.NONE) return; + if (roomEvent.getEvent() == RoomEvent.SPEAK_STATE_CHANGE) { + onSpeakQueueUpdate(roomEvent.getMicPositionList()); + } + } + + @Override + public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { + //高度和位置都没发生变化,就没必要要reset了 + LogUtils.d("top == oldTop=" + (top == oldTop) + " bottom == oldBottom=" + (bottom == oldBottom)); + LogUtils.d("left= " + left + " right= " + right); + if (top == oldTop && bottom == oldBottom && left == oldLeft && right == oldRight) return; + if (isNeedResetMicCenterPoint) {//这里有时候会重复调用,简单处理下(都是在500毫秒内重复调用的) + isNeedResetMicCenterPoint = false; + recyclerView.post(() -> { + isNeedResetMicCenterPoint = true; + setMicCenterPoint(); + }); + } + } + + private void setMicCenterPoint() { + SparseArray centerPoints = new SparseArray<>(); + // 算出每一个麦位的位置 + int childCount = recyclerView.getChildCount(); + View child; + for (int i = 0; i < childCount; i++) { + child = recyclerView.getChildAt(i); + addFaceView(centerPoints, child, i - 1); + if (i == 0) { + RecyclerView rvVip = child.findViewById(R.id.rv_vip); + if (rvVip != null && rvVip.getChildCount() > 0) { + addFaceView(centerPoints, rvVip.getChildAt(0), AvRoomDataManager.POSITION_VIP_MIC); + } + } + } + AvRoomDataManager.get().mMicPointMap = centerPoints; + } + + private void addFaceView(SparseArray centerPoints, View child, int micPosition) { + int[] location = new int[2]; + // 找到头像 + View view = child.findViewById(R.id.micro_layout); + if (view != null) child = view; + child.getLocationInWindow(location); + int x; + int y; + if (UiUtils.INSTANCE.isRtl(getContext())) { + location[0] = getWidth() - location[0]; + x = (location[0] - child.getWidth() / 2) - giftWidth / 2; + }else{ + x = (location[0] + child.getWidth() / 2) - giftWidth / 2; + } + y = (location[1] + child.getHeight() / 2) - giftHeight / 2; + Point point = new Point(x, y); + LogUtils.d("x= " + x + " y= " + y); + centerPoints.put(micPosition, point); + } + + public BaseMicroViewAdapter getAdapter() { + return (BaseMicroViewAdapter) recyclerView.getAdapter(); + } + + @SuppressLint("CheckResult") + public void onSpeakQueueUpdate(List positions) { + if (recyclerView == null || getAdapter() == null) return; + int count = getAdapter().getItemCount(); + for (int i = 0; i < positions.size(); i++) { + int pos = positions.get(i) + 1; + if (pos >= count && pos != AvRoomDataManager.POSITION_VIP_MIC + 1) continue; + + final SVGAImageView speakState = findItemView(pos, R.id.iv_halo); + + if (speakState != null) { + RoomQueueInfo roomQueueInfo = AvRoomDataManager.get().getRoomQueueMemberInfoByMicPosition(positions.get(i)); + if (roomQueueInfo == null || roomQueueInfo.mChatRoomMember == null) continue; + String halo = (String) NobleUtil.getResource(NobleResourceType.KEY_HALO, roomQueueInfo.mChatRoomMember); + String micCircle = roomQueueInfo.mChatRoomMember.getMicCircle(); + boolean isSingleAnchor = AvRoomDataManager.get().isSingleRoom() && pos == 0; + RoomMicDress roomMicEffects = ResourceManager.INSTANCE.getRoomMicEffects(); + if (TextUtils.isEmpty(micCircle)) { + if (roomMicEffects != null) { + micCircle = roomMicEffects.normalMicUrl; + } + } + + // 如果 micCircle 没有值,表示 没有后台没有返回麦位光圈 且 他不是个播房 的 主播位 pos=0 , 那么 走默认光圈逻辑 + if (TextUtils.isEmpty(micCircle) && !isSingleAnchor) { + //光圈的起始位置应该是头像边界,终止位置是头饰边界,头像:头饰=3:4 + boolean isNeedSetBackground = false; + if (speakState.getBackground() != null) { + if (speakState.getBackground() instanceof AnimationDrawable) { + AnimationDrawable oldAnimationDrawable = (AnimationDrawable) speakState.getBackground(); + //因为设置了setOneShot属性,这里判断动画是否完成。 + if (oldAnimationDrawable.getCurrent() == oldAnimationDrawable.getFrame(oldAnimationDrawable.getNumberOfFrames() - 1)) { + isNeedSetBackground = true; + } + } else { + isNeedSetBackground = true; + } + } else { + isNeedSetBackground = true; + } + + if (isNeedSetBackground) { + AnimFactory.getSpeakingAnimation(mContext, speakState.getWidth(), speakState.getHeight(), NobleUtil.getColor(halo), speakState.getWidth() * 3 / 4) + .subscribe((animationDrawable, throwable) -> { + speakState.setBackground(animationDrawable); + animationDrawable.start(); + }); + + } + + } else { + if (speakState.isAnimating()) continue; + try { + speakState.setFillMode(SVGAImageView.FillMode.Clear); + SVGAParser.ParseCompletion parseCompletion = new SVGAParser.ParseCompletion() { + @Override + public void onComplete(@NonNull SVGAVideoEntity svgaVideoEntity) { + SVGADrawable drawable = new SVGADrawable(svgaVideoEntity); + speakState.setImageDrawable(drawable); + speakState.startAnimation(); + } + + @Override + public void onError() { + + } + }; + if (isSingleAnchor) { + speakState.setLoops(-1); + SVGAParser.Companion.shareParser().decodeFromAssets("svga/single_headware.svga", parseCompletion, null); + } else { + speakState.setLoops(1); + SVGAParser.Companion.shareParser().decodeFromURL(new URL(micCircle), parseCompletion, null); + } + } catch (MalformedURLException e) { + e.printStackTrace(); + } + } + } + } + } + + @Nullable + private T findItemView(int pos, int viewId) { + if (pos == AvRoomDataManager.POSITION_VIP_MIC + 1) { + return ((RecyclerView) recyclerView.getChildAt(0).findViewById(R.id.rv_vip)) + .getChildAt(0).findViewById(viewId); + } else { + RecyclerView.ViewHolder viewHolder = recyclerView.findViewHolderForLayoutPosition(pos); + if (viewHolder == null) return null; + return viewHolder.itemView.findViewById(viewId); + } + + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onReceiveFace(ReceiveFaceEvent event) { + List faceReceiveInfos = event.getFaceReceiveInfos(); + if (faceReceiveInfos == null || faceReceiveInfos.size() <= 0) return; + faceAnima(faceReceiveInfos, false, true, true, true); + } + + public void release() { + // 移除麦上的所有成员还有说话的光晕 + for (int i = 0; i < recyclerView.getChildCount(); i++) { + View child = recyclerView.getChildAt(i); + RecyclerView.ViewHolder holder = recyclerView.getChildViewHolder(child); + if (holder instanceof BaseMicroViewAdapter.NormalMicroViewHolder) { + ((BaseMicroViewAdapter.NormalMicroViewHolder) holder).clear(); + } + } + } + + //开始表情动画和龙珠动画 //xxx 麦位动画播放 + @SuppressLint("CheckResult") + private void faceAnima(List faceReceiveInfos, boolean isDragon, boolean needAnim, boolean needResult, boolean needGone) { + for (FaceReceiveInfo faceReceiveInfo : faceReceiveInfos) { + int position = AvRoomDataManager.get().getMicPosition(faceReceiveInfo.getUid()); + if (position < -1) continue; + ImageView imageView; + if (isDragon) { + return; + } else { + imageView = findItemView(position + 1, R.id.iv_face); + } + if (imageView == null) continue; + if (OtherExtKt.isVerify(faceReceiveInfo.getSvgaURL())) { + if (imageView instanceof SVGAView) { + ((SVGAView)imageView).setClearsAfterStop(true); + ((SVGAView)imageView).setLoops(1); + ((SVGAView)imageView).loadUrl(faceReceiveInfo.getSvgaURL(),true); + } + }else { + AnimFactory.getFaceAnimation(faceReceiveInfo, mContext, imageView.getWidth(), imageView.getHeight(), needAnim, needResult, needGone) + .subscribe((animationDrawable, throwable) -> { + if (animationDrawable != null) { + Drawable drawable = imageView.getDrawable(); + if (drawable != null && drawable instanceof AnimationDrawable) { + ((AnimationDrawable) drawable).stop(); + imageView.clearAnimation(); + } + imageView.setImageDrawable(animationDrawable); + imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE); + animationDrawable.setOneShot(true); + animationDrawable.start(); + } + }); + } + + } + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/widget/OnMsgLongClickListener.java b/app/src/main/java/com/chwl/app/avroom/widget/OnMsgLongClickListener.java new file mode 100644 index 0000000..8ac3ed7 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/widget/OnMsgLongClickListener.java @@ -0,0 +1,7 @@ +package com.chwl.app.avroom.widget; + +import android.view.View; + +public interface OnMsgLongClickListener { + void onLongClick(View v,String account,String name); +} diff --git a/app/src/main/java/com/chwl/app/avroom/widget/PKProgressBar.kt b/app/src/main/java/com/chwl/app/avroom/widget/PKProgressBar.kt new file mode 100644 index 0000000..31db97b --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/widget/PKProgressBar.kt @@ -0,0 +1,37 @@ +package com.chwl.app.avroom.widget + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Canvas +import android.util.AttributeSet +import android.widget.ProgressBar +import com.chwl.app.R + +class PKProgressBar(context: Context, attrs: AttributeSet?) : ProgressBar(context, attrs) { + + private var thumbBitmap: Bitmap = BitmapFactory.decodeResource(context.resources, R.drawable.ic_pb_indicator) + private var thumbWidth: Float = thumbBitmap.width.toFloat() + private var thumbHeight: Float = thumbBitmap.height.toFloat() + private var mWidth = 0 + private var mHeight = 0 + + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + mWidth = w + mHeight = h + } + + @Synchronized + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + val radio = progress * 1.0f / max + canvas.drawBitmap( + thumbBitmap, + mWidth * radio - thumbWidth / 2f, + (mHeight - thumbHeight) / 2f, + null + ) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/widget/RankNavigatorAdapter.java b/app/src/main/java/com/chwl/app/avroom/widget/RankNavigatorAdapter.java new file mode 100644 index 0000000..f325e77 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/widget/RankNavigatorAdapter.java @@ -0,0 +1,85 @@ +package com.chwl.app.avroom.widget; + +import android.content.Context; +import android.graphics.Color; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import androidx.core.content.ContextCompat; + +import com.chwl.app.R; +import com.chwl.app.decoration.view.widgets.BadgeScaleTransitionPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.CommonNavigatorAdapter; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.indicators.LinePagerIndicator; +import com.chwl.library.utils.ResUtil; + +import java.util.ArrayList; +import java.util.List; + +/** + * 排行榜指示器定制 + * Created by lvzebiao on 2018/10/30. + */ + +public class RankNavigatorAdapter extends CommonNavigatorAdapter { + + private List mTitleList = new ArrayList<>(); + + public RankNavigatorAdapter(boolean showMonth) { + mTitleList.add(ResUtil.getString(R.string.avroom_widget_ranknavigatoradapter_01)); + mTitleList.add(ResUtil.getString(R.string.avroom_widget_ranknavigatoradapter_02)); + if (showMonth) { + mTitleList.add(ResUtil.getString(R.string.avroom_widget_ranknavigatoradapter_03)); + } + } + + @Override + public int getCount() { + return mTitleList.size(); + } + + @Override + public IPagerTitleView getTitleView(Context context, int index) { + BadgeScaleTransitionPagerTitleView scaleTransitionPagerTitleView = new BadgeScaleTransitionPagerTitleView(context); + scaleTransitionPagerTitleView.setNormalColor(ContextCompat.getColor(context, R.color.white_transparent_50)); + scaleTransitionPagerTitleView.setSelectedColor(ContextCompat.getColor(context, R.color.white)); + scaleTransitionPagerTitleView.setMinScale(1f); + scaleTransitionPagerTitleView.setTextSize(14); + scaleTransitionPagerTitleView.setText(mTitleList.get(index)); + + scaleTransitionPagerTitleView.setOnClickListener(view -> { + if (mOnItemSelectListener != null) { + mOnItemSelectListener.onItemSelect(index); + } + }); + return scaleTransitionPagerTitleView; + } + + @Override + public IPagerIndicator getIndicator(Context context) { + LinePagerIndicator indicator = new LinePagerIndicator(context); + indicator.setMode(LinePagerIndicator.MODE_EXACTLY); + indicator.setLineHeight(UIUtil.dip2px(context, 3)); + indicator.setRoundRadius(UIUtil.dip2px(context, 1.5)); + indicator.setLineWidth(UIUtil.dip2px(context, 9)); + indicator.setColors(Color.parseColor("#FFFFFF")); + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + //lp.bottomMargin = 0; + indicator.setLayoutParams(lp); + return indicator; + } + + + private OnItemSelectListener mOnItemSelectListener; + + public void setOnItemSelectListener(OnItemSelectListener mOnItemSelectListener) { + this.mOnItemSelectListener = mOnItemSelectListener; + } + + public interface OnItemSelectListener { + void onItemSelect(int position); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/widget/RoomEffectBoxView.kt b/app/src/main/java/com/chwl/app/avroom/widget/RoomEffectBoxView.kt new file mode 100644 index 0000000..95262b2 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/widget/RoomEffectBoxView.kt @@ -0,0 +1,1273 @@ +package com.chwl.app.avroom.widget + +import android.animation.Animator +import android.animation.AnimatorListenerAdapter +import android.animation.ObjectAnimator +import android.annotation.SuppressLint +import android.app.Activity +import android.content.Context +import android.graphics.Color +import android.text.Layout +import android.text.StaticLayout +import android.text.TextPaint +import android.text.TextUtils +import android.text.style.ForegroundColorSpan +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View +import android.view.ViewConfiguration +import android.view.ViewGroup +import android.view.animation.AccelerateDecelerateInterpolator +import android.view.animation.Animation +import android.view.animation.AnimationUtils +import android.widget.FrameLayout +import android.widget.ImageView +import android.widget.TextView +import com.chwl.app.R +import com.chwl.app.avroom.activity.AVRoomActivity +import com.chwl.app.avroom.helper.AnimHelper +import com.chwl.app.common.svga.SimpleSvgaCallback +import com.chwl.app.databinding.LayoutRoomEffectBinding +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.app.ui.utils.isDestroyed +import com.chwl.app.ui.utils.load +import com.chwl.app.ui.utils.loadAnim +import com.chwl.app.ui.widget.SimpleAnimListener +import com.chwl.app.ui.widget.TextSpannableBuilder +import com.chwl.app.ui.widget.drawgift.DrawGiftPlayHelper +import com.chwl.app.utils.SpannableBuilder +import com.chwl.core.XConstants +import com.chwl.core.auth.AuthModel +import com.chwl.core.decoration.car.bean.CarInfo +import com.chwl.core.im.custom.bean.* +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.manager.IMNetEaseManager +import com.chwl.core.manager.RoomEvent +import com.chwl.core.room.bean.DatingNotifyInfo +import com.chwl.core.super_admin.util.SuperAdminUtil +import com.chwl.core.user.UserModel +import com.chwl.core.user.bean.UserInfo +import com.chwl.core.utils.extension.subAndReplaceDot +import com.chwl.library.common.util.isRtl +import com.chwl.library.common.util.setVis +import com.chwl.library.utils.ListUtils +import com.chwl.library.utils.ResUtil +import com.coorchice.library.SuperTextView +import com.example.lib_utils.ktx.dp +import com.netease.nim.uikit.common.util.sys.ScreenUtil +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage +import com.opensource.svgaplayer.* +import com.opensource.svgaplayer.SVGAParser.Companion.shareParser +import io.reactivex.Observable +import io.reactivex.ObservableEmitter +import io.reactivex.ObservableOnSubscribe +import io.reactivex.Single +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import java.net.MalformedURLException +import java.net.URL +import java.util.concurrent.TimeUnit + +/** + * 房間特效View(座駕,心動場景,飄屏等) + */ +class RoomEffectBoxView @JvmOverloads constructor( + private val mContext: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : FrameLayout(mContext, attrs, defStyleAttr) { + private val mCarEffectList: MutableList by lazy { ArrayList() } + + //頂部飄屏總展示時間 + private val SHOW_TIME = 4500 + private val CLOSE_TIME = 5000 + + //頂部飄屏周期 + private val PERIOD = 1000 + private val binding: LayoutRoomEffectBinding = + LayoutRoomEffectBinding.inflate(LayoutInflater.from(mContext), this, true) + + private val imDisposable: Disposable? + + private var animationBox: Animation? = null + private var boxDisposable: Disposable? = null + private val messagesBox: MutableList by lazy { ArrayList() } + + private var animationLuckyGift: Animation? = null + private var disposableLuckyGift: Disposable? = null + private val messagesLuckyGift: MutableList by lazy { ArrayList() } + + private var disposableMemberIn: Disposable? = null + private val messagesMemberIn: MutableList by lazy { ArrayList() } + + private var disposableLevelUp: Disposable? = null + private val messagesLevelUp: MutableList by lazy { ArrayList() } + + private var animationDatingAll: Animation? = null + private var disposableDatingAll: Disposable? = null + private val messagesDatingAll: MutableList by lazy { ArrayList() } + private var datingDisposable: Disposable? = null + + + private var disposableRoomPK: Disposable? = null + private val messagesRoomPK: MutableList by lazy { ArrayList() } + + private var disposableSingleRoomPK: Disposable? = null + private val messagesSingleRoomPK: MutableList by lazy { ArrayList() } + + private var disposableGiftCompound: Disposable? = null + private val messagesGiftCompound: MutableList by lazy { ArrayList() } + + private var animationRadish: Animation? = null + private val messagesRadish: MutableList by lazy { java.util.ArrayList() } + private var radishDisposable: Disposable? = null + + private val messagesRadishSVGA: MutableList by lazy { java.util.ArrayList() } + private var radishSVGADisposable: Disposable? = null + + private var isSvgaPlaying = false + + private var isHideCarEffect = false + + private val drawGiftPlayHelper: DrawGiftPlayHelper by lazy { DrawGiftPlayHelper(context as Activity) } + + private fun loopCarAnim() { + if (context.isDestroyed()) return + isSvgaPlaying = false + + if (isHideCarEffect && mCarEffectList.isNotEmpty()) { + mCarEffectList.clear() + } + if (ListUtils.isListEmpty(mCarEffectList)) { + binding.roomCarSvga.visibility = GONE + binding.vapAnimView.visibility = GONE + return + } + mCarEffectList.removeAt(0) + if (!ListUtils.isListEmpty(mCarEffectList)) { + playCarAnim(mCarEffectList[0]) + } + } + + init { + imDisposable = IMNetEaseManager.get().chatRoomEventObservable + .subscribe { roomEvent: RoomEvent? -> + if (roomEvent == null || AvRoomDataManager.get().isSelfGamePlaying) return@subscribe + when (roomEvent.event) { +// RoomEvent.BOX_NOTIFY -> addBoxNotify(roomEvent.chatRoomMessage) +// RoomEvent.BOX_NOTIFY_SVGA -> addBoxNotify(roomEvent.chatRoomMessage) + RoomEvent.DATING_ALL_NOTIFY -> addDatingAllNotify(roomEvent.chatRoomMessage) + RoomEvent.RADISH_NOTIFY, + RoomEvent.RADISH_NOTIFY_SVGA -> addRadishNotify(roomEvent.chatRoomMessage) + + RoomEvent.ROOM_GIFT_COMPOUND -> addGiftCompoundNotify(roomEvent.chatRoomMessage) + RoomEvent.DATING_PUBLISH_RESULT -> showHandAnim((roomEvent.chatRoomMessage.attachment as DatingAttachment).datingNotifyInfo) + RoomEvent.RECEIVE_MEMBER_IN_NOTICE -> //進入房間 + addMemberInNotify(roomEvent.chatRoomMessage) + + RoomEvent.RECEIVE_EXPER_LEVEL_UP_NOTICE -> addLevelUpNotify(roomEvent.chatRoomMessage) + RoomEvent.ENTER_ROOM -> { + if (!SuperAdminUtil.isSuperAdmin()) { + playCarSvga(AuthModel.get().currentUid.toString(), null, true) + } + } + + RoomEvent.CAR_MEMBER_IN -> { + if (roomEvent.mRoomCarMsgAttachment != null) { + playCarSvga( + null, + CarInfo( + roomEvent.mRoomCarMsgAttachment.effect, + roomEvent.mRoomCarMsgAttachment.viewUrl, + roomEvent.mRoomCarMsgAttachment.otherViewType + ), + false + ) + } + } + + RoomEvent.ROOM_PK_NOTIFY -> addRoomPKNotify(roomEvent.chatRoomMessage) + RoomEvent.SINGLE_ROOM_PK_NOTIFY -> addSingleRoomPKNotify(roomEvent.chatRoomMessage) + RoomEvent.SINGLE_ROOM_RANK_TOP_NOTIFY -> showRoomRankNotify(roomEvent.chatRoomMessage) + RoomEvent.ROOM_RANK_TOP_NOTIFY -> showRoomRankNotify(roomEvent.chatRoomMessage) + RoomEvent.ROOM_CAR_EFFECT_HIDE -> { + isHideCarEffect = true + loopCarAnim() + } + + RoomEvent.ROOM_CAR_EFFECT_SHOW -> { + isHideCarEffect = false + } + + RoomEvent.DRAW_GIFT_EFFECT -> { + val drawGiftAttachment = + (roomEvent.chatRoomMessage?.attachment as? DrawGiftAttachment) + ?: return@subscribe + drawGiftPlayHelper.prepareShowDrawGift( + drawGiftAttachment.giftId, + drawGiftAttachment.drawFixedArray, + false + ) + } + + else -> {} + } + } + binding.roomCarSvga.callback = object : SimpleSvgaCallback() { + override fun onFinished() { + loopCarAnim() + } + } + binding.vapAnimView.setAnimListener(object : SimpleAnimListener() { + override fun onVideoComplete() { + loopCarAnim() + } + }) + } + + /** + * 幸運池飄屏 + * + * @param chatRoomMessage + */ + private fun addDatingAllNotify(chatRoomMessage: ChatRoomMessage) { + if (binding.clNotify.visibility == GONE) { + binding.clNotify.visibility = VISIBLE + } + messagesDatingAll.add(chatRoomMessage) + if (disposableDatingAll == null || messagesDatingAll.size == 1) { + disposableDatingAll = Observable.interval(0, 3, TimeUnit.SECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .takeWhile { messagesDatingAll.size > 0 && !mContext.isDestroyed() } + .subscribe { + if (binding.flDatingAllNotify.childCount == 0) { + showDatingAllNotify( + messagesDatingAll.removeAt(0) + ) + } + } + } + } + + private fun showDatingAllNotify(chatRoomMessage: ChatRoomMessage) { + val attachment = chatRoomMessage.attachment as DatingAllNotifyAttachment + val (_, _, oneUserNick, anotherUserNick, roomUid, roomTitle, backgroundUrl, joinHandLevel, _, sweetWords) = attachment.datingAllNotifyInfo + ?: return + //自己房間不需要飄 + if (AvRoomDataManager.get().roomUid == roomUid) return + val textView = LayoutInflater.from(mContext) + .inflate(R.layout.layout_room_dating_all_notify, null) as TextView + textView.setOnClickListener { AVRoomActivity.start(mContext, roomUid) } + var defaultBg = R.drawable.bg_dating_hand_1 + when (joinHandLevel) { + 1 -> defaultBg = R.drawable.bg_dating_hand_1 + 2 -> defaultBg = R.drawable.bg_dating_hand_2 + 3 -> defaultBg = R.drawable.bg_dating_hand_3 + } + textView.setBackgroundResource(defaultBg) + ImageLoadUtils.loadBackground(mContext, backgroundUrl, defaultBg, textView) + val text = SpannableBuilder() + .append( + ResUtil.getString(R.string.avroom_widget_roomeffectview_01), + ForegroundColorSpan(Color.WHITE) + ) + .append( + getShortString(oneUserNick, 8), + ForegroundColorSpan(resources.getColor(R.color.notice_nick)) + ) + .append( + ResUtil.getString(R.string.avroom_widget_roomeffectview_02), + ForegroundColorSpan(Color.WHITE) + ) + .append( + getShortString(anotherUserNick, 8), + ForegroundColorSpan(resources.getColor(R.color.notice_nick)) + ) + .append( + ResUtil.getString(R.string.avroom_widget_roomeffectview_03) + getShortString( + roomTitle, + 10 + ) + ")" + sweetWords, + ForegroundColorSpan(Color.WHITE) + ) + textView.text = text.build() + animationDatingAll = AnimationUtils.loadAnimation(mContext, R.anim.anim_box_notify) + binding.flDatingAllNotify.addView(textView) + textView.startAnimation(animationDatingAll) + binding.flDatingAllNotify.postDelayed( + { binding.flDatingAllNotify.removeView(textView) }, + 4500 + ) + } + + private fun getShortString(text: String, max: Int): String { + return if (TextUtils.isEmpty(text) || text.length <= max) text else text.substring( + 0, + max + ) + "…" + } + + /** + * 幸運池飄屏 + * + * @param chatRoomMessage + */ +// private fun addBoxNotify(chatRoomMessage: ChatRoomMessage) { +// if (binding.clNotify.visibility == GONE) { +// binding.clNotify.visibility = VISIBLE +// } +// messagesBox.add(chatRoomMessage) +// if (boxDisposable == null || messagesBox.size == 1) { +// boxDisposable = Observable.interval(0, PERIOD.toLong(), TimeUnit.MILLISECONDS) +// .observeOn(AndroidSchedulers.mainThread()) +// .takeWhile { messagesBox.size > 0 && !mContext.isDestroyed() } +// .subscribe { +// if (binding.flBoxNotify.childCount == 0) { +// val msg = messagesBox.removeAt(0) +// val attachment = msg.attachment +// if (attachment is CustomAttachment) { +// if (attachment.second == CUSTOM_MSG_SUB_BOX_ALL_ROOM_NOTIFY) { +// showBoxNotify(msg) +// } else if(attachment.second == CUSTOM_MSG_SUB_BOX_ALL_ROOM_NOTIFY_BY_SVGA) { +// showBoxNotifyBySVGA(msg) +// } +// +// } +// } +// } +// } +// } + +// private fun showBoxNotify(chatRoomMessage: ChatRoomMessage) { +// val attachment = chatRoomMessage.attachment as RoomBoxPrizeAttachment +// val textView = +// LayoutInflater.from(mContext).inflate(R.layout.layout_room_box_notify, null) as TextView +// val text = SpannableBuilder() +// .append( +// ResUtil.getString(R.string.avroom_widget_roomeffectview_08), +// ForegroundColorSpan(Color.WHITE) +// ) +// .append( +// attachment.nick.subAndReplaceDot(8), +// ForegroundColorSpan(resources.getColor(R.color.notice_nick)) +// ) +// .append( +// ResUtil.getString(R.string.treasure_in_find_love) + ResUtil.getString( +// R.string.avroom_widget_roomeffectview_010 +// ), ForegroundColorSpan(Color.WHITE) +// ) +// .append( +// attachment.prizeName, +// ForegroundColorSpan(resources.getColor(R.color.notice_nick)) +// ) +// if (attachment.prizeNum > 1) { +// text.append("x" + attachment.prizeNum, ForegroundColorSpan(Color.WHITE)) +// } +// textView.text = text.build() +// animationBox = AnimationUtils.loadAnimation(mContext, R.anim.anim_box_notify) +// binding.flBoxNotify.addView(textView) +// textView.startAnimation(animationBox) +// binding.flBoxNotify.postDelayed( +// { +// animationBox = AnimationUtils.loadAnimation(mContext, R.anim.anim_box_notify_close) +// textView.startAnimation(animationBox) +// }, +// SHOW_TIME.toLong() +// ) +// binding.flBoxNotify.postDelayed({ +// binding.flBoxNotify.removeView(textView) +// }, CLOSE_TIME.toLong()) +// } + +// private fun showBoxNotifyBySVGA(chatRoomMessage: ChatRoomMessage) { +// val attachment = chatRoomMessage.attachment as RoomBoxPrizeAttachment +// val text = SpannableBuilder() +// .append( +// ResUtil.getString(R.string.avroom_widget_roomeffectview_011), +// ForegroundColorSpan(Color.WHITE) +// ) +// .append( +// StringUtils.abbreviate(attachment.nick, 8) + " ", +// ForegroundColorSpan(resources.getColor(R.color.notice_nick)) +// ) +// .append( +// ResUtil.getString(R.string.treasure_in_find_love) + ResUtil.getString( +// R.string.avroom_widget_roomeffectview_013 +// ), ForegroundColorSpan(Color.WHITE) +// ) +// .append( +// attachment.prizeName, +// ForegroundColorSpan(resources.getColor(R.color.notice_nick)) +// ) +// if (attachment.prizeNum > 1) { +// text.append("x" + attachment.prizeNum, ForegroundColorSpan(Color.WHITE)) +// } +// val svgaImageView = SVGAImageView(mContext) +// svgaImageView.loops = 1 +// svgaImageView.clearsAfterDetached = true +// val params = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT) +// svgaImageView.layoutParams = params +// svgaImageView.callback = object : SimpleSvgaCallback() { +// override fun onFinished() { +// animationBox = AnimationUtils.loadAnimation(mContext, R.anim.anim_box_notify_close) +// animationBox!!.setAnimationListener(object : SimpleAnimationListener() { +// override fun onAnimationEnd(animation: Animation?) { +// binding.flBoxNotify.removeView(svgaImageView) +// } +// }) +// binding.flBoxNotify.startAnimation(animationBox) +// } +// } +// animationBox = AnimationUtils.loadAnimation(mContext, R.anim.anim_box_notify) +// binding.flBoxNotify.addView(svgaImageView) +// binding.flBoxNotify.startAnimation(animationBox) +// +// shareParser().decodeFromAssets("svga/box_notify.svga", object : SVGAParser.ParseCompletion { +// override fun onComplete(videoItem: SVGAVideoEntity) { +// val dynamicEntity = SVGADynamicEntity() +// val textPaint = TextPaint() +// textPaint.color = Color.WHITE //字體顏色 +// textPaint.textSize = 24f //字體大小 +// dynamicEntity.setDynamicText( +// StaticLayout( +// text.build(), +// 0, +// text.build().length, +// textPaint, +// 0, +// Layout.Alignment.ALIGN_CENTER, +// 1.0f, +// 0.0f, +// false +// ), "bg" +// ) +// val drawable = SVGADrawable(videoItem, dynamicEntity) +// svgaImageView.setImageDrawable(drawable) +// svgaImageView.stepToFrame(0, true) +// } +// +// override fun onError() {} +// }, null) +// } + + /** + * 幸運池飄屏 + * + * @param chatRoomMessage + */ + private fun addRadishNotify(chatRoomMessage: ChatRoomMessage) { + if (binding.clNotify.visibility == GONE) { + binding.clNotify.visibility = VISIBLE + } + messagesRadish.add(chatRoomMessage) + if (radishDisposable == null || messagesRadish.size == 1) { + radishDisposable = Observable.interval(0, PERIOD.toLong(), TimeUnit.MILLISECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .takeWhile { messagesRadish.size > 0 && !mContext.isDestroyed() } + .subscribe { + if (binding.flRadishNotify.childCount == 0) { + showRadishNotify(messagesRadish.removeAt(0)) + } + } + } + } + + private fun showRadishNotify(chatRoomMessage: ChatRoomMessage?) { + val attachment = chatRoomMessage?.attachment as? RoomBoxPrizeAttachment ?: return + val textView = + LayoutInflater.from(mContext) + .inflate(R.layout.layout_room_radish_notify, null) as TextView + textView.setBackgroundResource(R.drawable.bg_radish_notice) + val text = SpannableBuilder() + .append( + ResUtil.getString(R.string.avroom_widget_roomeffectview_014), + ForegroundColorSpan(Color.WHITE) + ) + .append( + attachment.nick.subAndReplaceDot(6) + " ", + ForegroundColorSpan(resources.getColor(R.color.notice_nick)) + ) + .append( + attachment.boxTypeStr + ResUtil.getString(R.string.avroom_widget_roomeffectview_015), + ForegroundColorSpan(Color.WHITE) + ) + .append( + attachment.prizeName, + ForegroundColorSpan(resources.getColor(R.color.notice_gift)) + ) + if (attachment.prizeNum > 1) { + text.append("x" + attachment.prizeNum, ForegroundColorSpan(Color.WHITE)) + } + textView.text = text.build() + setupRoomTitleMarquee(textView) + animationRadish = AnimationUtils.loadAnimation(mContext, R.anim.anim_box_notify) + binding.flRadishNotify.addView(textView) + textView.startAnimation(animationRadish) + binding.flRadishNotify.postDelayed( + { binding.flRadishNotify.removeView(textView) }, + SHOW_TIME.toLong() + ) + } + + /** + * 添加跑馬燈 + * 以及反射一些參數影響跑馬燈 + */ + private fun setupRoomTitleMarquee(textView: TextView) { + try { + val configuration = ViewConfiguration.get(context) + val claz: Class<*> = configuration.javaClass + val field = claz.getDeclaredField("mFadingMarqueeEnabled") + field.isAccessible = true + field[configuration] = true + } catch (e: NoSuchFieldException) { + e.printStackTrace() + } catch (e: IllegalArgumentException) { + e.printStackTrace() + } catch (e: IllegalAccessException) { + e.printStackTrace() + } + textView.isSelected = true + } + + /** + * 幸運池飄屏 五級 SVGA背景的 + * + * @param chatRoomMessage + */ + private fun addRadishNotifyBySVGA(chatRoomMessage: ChatRoomMessage) { + if (binding.clNotify.visibility == GONE) { + binding.clNotify.visibility = VISIBLE + } + messagesRadishSVGA.add(chatRoomMessage) + if (radishSVGADisposable == null || messagesRadishSVGA.size == 1) { + radishSVGADisposable = Observable.interval(0, PERIOD.toLong(), TimeUnit.MILLISECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .takeWhile { messagesRadishSVGA.size > 0 && !mContext.isDestroyed() } + .subscribe { + if (binding.flSvgaRadishNotify.childCount == 0) { + showRadishNotifyBySVGA(messagesRadishSVGA.removeAt(0)) + } + } + } + } + + private fun showRadishNotifyBySVGA(chatRoomMessage: ChatRoomMessage?) { + val attachment = chatRoomMessage?.attachment as? RoomBoxPrizeAttachment ?: return + val text = SpannableBuilder() + .append( + ResUtil.getString(R.string.avroom_widget_roomeffectview_016), + ForegroundColorSpan(Color.WHITE) + ) + .append( + attachment.nick + " ", + ForegroundColorSpan(resources.getColor(R.color.notice_nick)) + ) + .append( + attachment.boxTypeStr + ResUtil.getString(R.string.avroom_widget_roomeffectview_017), + ForegroundColorSpan(Color.WHITE) + ) + .append( + attachment.prizeName, + ForegroundColorSpan(resources.getColor(R.color.notice_gift)) + ) + if (attachment.prizeNum > 1) { + text.append("x" + attachment.prizeNum, ForegroundColorSpan(Color.WHITE)) + } + val svgaImageView = SVGAImageView(mContext) + svgaImageView.loops = 1 + svgaImageView.clearsAfterStop = true + val params = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT) + svgaImageView.layoutParams = params + svgaImageView.callback = object : SimpleSvgaCallback() { + override fun onFinished() { + binding.flSvgaRadishNotify.post { + binding.flSvgaRadishNotify.removeView(svgaImageView) + } + } + } + binding.flSvgaRadishNotify.addView(svgaImageView) + shareParser().decodeFromAssets( + "svga/radish_notify.svga", + object : SVGAParser.ParseCompletion { + override fun onComplete(videoItem: SVGAVideoEntity) { + val dynamicEntity = SVGADynamicEntity() + val textPaint = TextPaint() + textPaint.color = Color.WHITE //字體顏色 + textPaint.textSize = 24f //字體大小 + dynamicEntity.setDynamicText( + StaticLayout( + text.build(), + 0, + text.build().length, + textPaint, + 0, + Layout.Alignment.ALIGN_CENTER, + 1.0f, + 0.0f, + false + ), "blb_copywriting" + ) + val drawable = SVGADrawable(videoItem, dynamicEntity) + svgaImageView.setImageDrawable(drawable) + svgaImageView.stepToFrame(0, true) + } + + override fun onError() {} + }) + } + + + /** + * 禮物合成,帶SVGA背景的消息 + * + * @param chatRoomMessage + */ + private fun addGiftCompoundNotify(chatRoomMessage: ChatRoomMessage) { + if (binding.clNotify.visibility == GONE) { + binding.clNotify.visibility = VISIBLE + } + messagesGiftCompound.add(chatRoomMessage) + if (disposableGiftCompound == null || messagesGiftCompound.size == 1) { + disposableGiftCompound = Observable.interval(0, PERIOD.toLong(), TimeUnit.MILLISECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .takeWhile { messagesGiftCompound.size > 0 && !mContext.isDestroyed() } + .subscribe { + if (binding.flGiftCompoundNotify.childCount == 0) { + showGiftCompoundNotify(messagesGiftCompound.removeAt(0)) + } + } + } + } + + private fun showGiftCompoundNotify(chatRoomMessage: ChatRoomMessage) { + val msgBean = (chatRoomMessage.attachment as GiftCompoundAttachment).msgBean + val text = SpannableBuilder() + .append( + msgBean.nick.subAndReplaceDot(7) + " ", + ForegroundColorSpan(resources.getColor(R.color.notice_nick)) + ) + .append(msgBean.msg + " ", ForegroundColorSpan(Color.WHITE)) + .append( + msgBean.giftName, + ForegroundColorSpan(resources.getColor(R.color.notice_nick)) + ) + val svgaImageView = SVGAImageView(mContext) + svgaImageView.loops = 1 + svgaImageView.clearsAfterStop = true + val params = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT) + svgaImageView.layoutParams = params + svgaImageView.callback = object : SimpleSvgaCallback() { + override fun onFinished() { + binding.flGiftCompoundNotify.post { + binding.flGiftCompoundNotify.removeView(svgaImageView) + } + } + } + binding.flGiftCompoundNotify.addView(svgaImageView) + shareParser().decodeFromAssets( + "svga/gift_compound_notify.svga", + object : SVGAParser.ParseCompletion { + override fun onComplete(videoItem: SVGAVideoEntity) { + val dynamicEntity = SVGADynamicEntity() + val textPaint = TextPaint() + textPaint.color = Color.WHITE //字體顏色 + textPaint.textSize = 24f //字體大小 + dynamicEntity.setDynamicText( + StaticLayout( + text.build(), + 0, + text.build().length, + textPaint, + 0, + Layout.Alignment.ALIGN_CENTER, + 1.0f, + 0.0f, + false + ), "noble_text_tx" + ) + val drawable = SVGADrawable(videoItem, dynamicEntity) + svgaImageView.setImageDrawable(drawable) + svgaImageView.startAnimation() + } + + override fun onError() {} + }, + null + ) + } + + /** + * 成員進入飄屏 + * + * @param chatRoomMessage + */ + private fun addMemberInNotify(chatRoomMessage: ChatRoomMessage) { + messagesMemberIn.add(chatRoomMessage) + if (disposableMemberIn == null || messagesMemberIn.size == 1) { + disposableMemberIn = Observable.interval(0, 6, TimeUnit.SECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .takeWhile { messagesMemberIn.size > 0 && !mContext.isDestroyed() } + .subscribe { + showMemberInNotify(messagesMemberIn.removeAt(0)) + } + } + } + + private fun showMemberInNotify(chatRoomMessage: ChatRoomMessage) { + val attachment = chatRoomMessage.attachment + if (attachment is RoomUserEnterRoomMsgAttachment){ + val data = attachment.userEnterRoomBean + if (data != null) { + val targetNicks = data.nick + val fromType = data.fromType + val fromNick = data.fromNick + + val textView = LayoutInflater.from(mContext).inflate(R.layout.layout_member_in_notify, null) as SuperTextView + // 內容 + val text = TextSpannableBuilder(textView).append(targetNicks, ForegroundColorSpan(Color.WHITE)) + var enterText = ResUtil.getString(R.string.avroom_widget_roomeffectview_018) + if (fromType == AVRoomActivity.FROM_TYPE_RECOMMEND) { + enterText = ResUtil.getString(R.string.avroom_widget_roomeffectview_019) + } + if (fromType == AVRoomActivity.FROM_TYPE_USER) { + enterText = ResUtil.getString(R.string.avroom_widget_roomeffectview_020) + fromNick.subAndReplaceDot(7) + ResUtil.getString(R.string.avroom_widget_roomeffectview_021) + } + if (fromType == AVRoomActivity.FROM_TYPE_GAME_RECOMMEND) { + enterText = ResUtil.getString(R.string.avroom_widget_roomeffectview_022) + fromNick.subAndReplaceDot(7) + ResUtil.getString(R.string.avroom_widget_roomeffectview_023) + } + text.append(enterText, ForegroundColorSpan(Color.WHITE)) + + textView.text = text.build() + val wrapNick = "【" + targetNicks.subAndReplaceDot(7) + "】" + enterText + + if (data.isCpInRoom) { + //cp有特殊背景 + playMemberInAnimByPath(wrapNick, "svga/experience_entre_effect_cp.svga") + } else { + if (!TextUtils.isEmpty(data.enterRoomEffects)) { + playMemberInAnimByUrl(wrapNick, data.enterRoomEffects) // userInfo.getUserVipInfoVO().getEnterRoomEffects() + } else { + playMemberInAnimByPath(wrapNick, memberInSvgaPath(data.experLevelSeq)) // userInfo.getUserLevelVo().getExperLevelSeq() + } + } + } + } + } + + //xxx 进场特效背景 + private fun memberInSvgaPath(level: Int): String { + var path = "" + if (level in 30..39) { + path = "svga/experience_entre_effect_30.svga" + } else if (level in 40..49) { + path = "svga/experience_entre_effect_40.svga" + } else if (level in 50..59) { + path = "svga/experience_entre_effect_50.svga" + } else if (level in 60..69) { + path = "svga/experience_entre_effect_60.svga" + } else if (level in 70..79) { + path = "svga/experience_entre_effect_70.svga" + } else if (level in 80..89) { + path = "svga/experience_entre_effect_80.svga" + } else if (level >= 90) { + path = "svga/experience_entre_effect_90.svga" + } + return path + } + + private fun playMemberInAnimByPath(text: String, path: String) { + shareParser().decodeFromAssets(path, object : SVGAParser.ParseCompletion { + override fun onComplete(videoItem: SVGAVideoEntity) { + playMemberInAnim(text, videoItem) + } + + override fun onError() {} + }, null) + } + + private fun playMemberInAnimByUrl(text: String, url: String?) { + try { + shareParser().decodeFromURL(URL(url), object : SVGAParser.ParseCompletion { + override fun onComplete(videoItem: SVGAVideoEntity) { + playMemberInAnim(text, videoItem) + } + + override fun onError() {} + }, null) + } catch (e: MalformedURLException) { + e.printStackTrace() + } + } + + private fun playMemberInAnim(text: String, svgaVideoEntity: SVGAVideoEntity) { + binding.roomMenberInSvga.setVis(false) + binding.roomMenberInSvga.loops = 1 + binding.roomMenberInSvga.clearsAfterStop = true + val dynamicEntity = SVGADynamicEntity() + val textPaint = TextPaint() + textPaint.color = Color.WHITE //字體顏色 + textPaint.textSize = 22f //字體大小 + dynamicEntity.setDynamicText( + StaticLayout( + text, + 0, + text.length, + textPaint, + 0, + Layout.Alignment.ALIGN_NORMAL, + 1.0f, + 0.0f, + false + ), "room_text" + ) + val drawable = SVGADrawable(svgaVideoEntity, dynamicEntity) + binding.roomMenberInSvga.setImageDrawable(drawable) + binding.roomMenberInSvga.stepToFrame(0, true) + + + val start = if (context.isRtl()) -317.dp.toFloat() else 317.dp.toFloat() + val objectAnimator1 = ObjectAnimator.ofFloat(binding.roomMenberInSvga, "translationX", start, 0f).setDuration(150) + objectAnimator1.interpolator = AccelerateDecelerateInterpolator() + objectAnimator1.startDelay = 150 + objectAnimator1.addListener(object : AnimatorListenerAdapter() { + override fun onAnimationStart(animation: Animator) { + super.onAnimationStart(animation) + binding.roomMenberInSvga.setVis(true) + } + }) + objectAnimator1.start() + } + + /** + * 升級飄屏 + * + * @param chatRoomMessage + */ + private fun addLevelUpNotify(chatRoomMessage: ChatRoomMessage) { + messagesLevelUp.add(chatRoomMessage) + if (disposableLevelUp == null || messagesLevelUp.size == 1) { + disposableLevelUp = Observable.interval(0, 6, TimeUnit.SECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .takeWhile { messagesLevelUp.size > 0 && !mContext.isDestroyed() } + .subscribe { + showLevelUpNotify(messagesLevelUp.removeAt(0)) + } + } + } + + private fun showLevelUpNotify(chatRoomMessage: ChatRoomMessage) { + val attachment = chatRoomMessage.attachment as LevelUpNoticeAttachment + val message = attachment.getMessage() + val picUrl = attachment.getPicUrl() + val roomUid = attachment.getRoomUid() + if (picUrl == null || message == null) { + return + } + playLevelUpAnim(message, picUrl, roomUid) + } + + private fun playLevelUpAnim(message: String, picUrl: String, roomUid: Long) { + try { + shareParser().decodeFromURL(URL(picUrl), object : SVGAParser.ParseCompletion { + override fun onComplete(videoItem: SVGAVideoEntity) { + binding.roomLevelUpSvga.visibility = VISIBLE + binding.roomLevelUpSvga.loops = 1 + binding.roomLevelUpSvga.clearsAfterStop = true + val dynamicEntity = SVGADynamicEntity() + val textPaint = TextPaint() + textPaint.color = Color.WHITE //字體顏色 + textPaint.textSize = 22f //字體大小 Util.dip2px(mContext,11) + // textPaint.setShadowLayer(3, 2, 2, 0xff000000);//字體陰影,不需要可以不用設置 + dynamicEntity.setDynamicText(message, textPaint, "y_yhname") + val drawable = SVGADrawable(videoItem, dynamicEntity) + binding.roomLevelUpSvga.setImageDrawable(drawable) + binding.roomLevelUpSvga.stepToFrame(0, true) + binding.roomLevelUpSvga.callback = object : SimpleSvgaCallback() { + override fun onFinished() { + binding.roomLevelUpSvga.visibility = GONE + } + } + } + + override fun onError() {} + }, null) + binding.roomLevelUpSvga.setOnClickListener { v: View? -> + AVRoomActivity.start( + mContext, + roomUid + ) + } + } catch (e: MalformedURLException) { + e.printStackTrace() + } + } + + @SuppressLint("SetTextI18n") + private fun showHandAnim(datingNotifyInfo: DatingNotifyInfo) { + datingDisposable?.dispose() + binding.flSvgaDating.setOnClickListener { } + binding.ivDatingSvgaClose.setOnClickListener { + binding.flSvgaDating.visibility = GONE + datingDisposable?.dispose() + } + binding.flSvgaDating.post { binding.flSvgaDating.visibility = GONE } + datingDisposable = Single.just(datingNotifyInfo) + .observeOn(AndroidSchedulers.mainThread()) + .flatMap { info: DatingNotifyInfo -> + if (datingNotifyInfo.hasSelectUser && !datingNotifyInfo.hasHeart) { + showHeartAnim(datingNotifyInfo.position, datingNotifyInfo.targetPosition) + return@flatMap Single.timer( + XConstants.SELECT_ANIM_DURATION.toLong(), + TimeUnit.MILLISECONDS + ).map { info } + } + Single.just(info) + } + .observeOn(AndroidSchedulers.mainThread()) + .filter { datingNotifyInfo.hasHeart } + .toObservable() + .flatMap { info: DatingNotifyInfo -> + Observable.create( + ObservableOnSubscribe { emitter: ObservableEmitter -> + shareParser().decodeFromURL( + URL(datingNotifyInfo.svgaUrl), object : SVGAParser.ParseCompletion { + override fun onComplete(videoItem: SVGAVideoEntity) { + binding.flSvgaDating.visibility = VISIBLE + binding.llDatingSvgaTime.visibility = GONE + val dynamicEntity = SVGADynamicEntity() + val textPaint = TextPaint() + textPaint.color = Color.WHITE + textPaint.textSize = ScreenUtil.sp2px(10f).toFloat() + AnimHelper.addDynamicImage( + binding.svgaDating, + dynamicEntity, + datingNotifyInfo.avatar, + "z_tx" + ) + AnimHelper.addDynamicImage( + binding.svgaDating, + dynamicEntity, + datingNotifyInfo.targetAvatar, + "y_tx" + ) + val nickName = datingNotifyInfo.nickname.subAndReplaceDot(5) + dynamicEntity.setDynamicText( + StaticLayout( + nickName, + 0, + nickName.length, + textPaint, + 0, + Layout.Alignment.ALIGN_CENTER, + 1.0f, + 0.0f, + false + ), "z_yhname" + ) + val targetNickName = + datingNotifyInfo.targetNickname.subAndReplaceDot(5) + dynamicEntity.setDynamicText( + StaticLayout( + targetNickName, + 0, + targetNickName.length, + textPaint, + 0, + Layout.Alignment.ALIGN_CENTER, + 1.0f, + 0.0f, + false + ), "y_yhname" + ) + val drawable = SVGADrawable(videoItem, dynamicEntity) + binding.svgaDating.setImageDrawable(drawable) + binding.svgaDating.startAnimation() + emitter.onNext(info) + emitter.onComplete() + } + + override fun onError() { + emitter.onError(Throwable(ResUtil.getString(R.string.avroom_widget_roomeffectview_024))) + } + }, null + ) + } as ObservableOnSubscribe) + } + .flatMap { + Observable.intervalRange( + 1, + datingNotifyInfo.svgaSecond.toLong(), + 1, + 1, + TimeUnit.SECONDS + ) + } + .observeOn(AndroidSchedulers.mainThread()) + .doAfterTerminate { binding.flSvgaDating.visibility = GONE } + .subscribe { aLong: Long -> + val residueTime = datingNotifyInfo.svgaSecond - aLong + binding.tvDatingSecond.text = residueTime.toString() + "S" + if (residueTime == 5L) { //剩余5秒開始顯示倒計時 + binding.llDatingSvgaTime.visibility = VISIBLE + } + } + } + + private fun showHeartAnim(position: Int, targetPosition: Int) { + val micViewPoint = AvRoomDataManager.get().mMicPointMap + AnimHelper.showDatingSelectUserAnim( + context, + binding.root as ViewGroup, + micViewPoint[position], + micViewPoint[targetPosition] + ) + } + + @SuppressLint("CheckResult") + private fun playCarSvga(account: String?, carInfo: CarInfo?, isSendMsg: Boolean) { + if (isSendMsg) { + UserModel.get().getUserInfoFromServer(account?.toLong() ?: 0) + .subscribe { userInfo: UserInfo? -> + //播放座駕動效 + if (userInfo != null && userInfo.carInfo != null && userInfo.carInfo.isUsing + && userInfo.carInfo.getStatus() == CarInfo.STATUS_USER_CAN_USE + ) { + + // 貴族人員,要先判斷是否隱身 + if (userInfo.userVipInfoVO == null || !userInfo.userVipInfoVO.enterHide && !userInfo.isSuperAdmin) { + if (AvRoomDataManager.get().mIsNeedGiftEffect && + !AvRoomDataManager.get().isSelfGamePlaying && + !isHideCarEffect + ) { + mCarEffectList.add(userInfo.carInfo) + if (!binding.roomCarSvga.isAnimating && !isSvgaPlaying) { + // 播放座駕動畫 + playCarAnim(userInfo.carInfo) + } + } + + // 公屏進入房間的提示語 + IMNetEaseManager.get() + .sendCarPlayRoomMsgBySdk( + userInfo.carInfo, + userInfo.uid, + userInfo.nick + ) + .subscribe() + } + } + } + } else { + if (carInfo == null) return + if (AvRoomDataManager.get().mIsNeedGiftEffect && + !AvRoomDataManager.get().isSelfGamePlaying && + !isHideCarEffect + ) { + mCarEffectList.add(carInfo) + if (!binding.roomCarSvga.isAnimating && !isSvgaPlaying) { + playCarAnim(carInfo) + } + } + + } + } + + private fun playCarAnim(carInfo: CarInfo?) { + if (carInfo?.otherViewType == 1 && !TextUtils.isEmpty(carInfo.viewUrl)) { + playCarVAPEnterRoom(carInfo.viewUrl) + } else { + playCarSvagEnterRoom(carInfo?.effect) + } + } + + /** + * 真實播放svga + * + * @param effect + */ + private fun playCarSvagEnterRoom(effect: String?) { + if (TextUtils.isEmpty(effect)) return + if (!AvRoomDataManager.get().mIsNeedGiftEffect || + AvRoomDataManager.get().isSelfGamePlaying + ) { + return + } + isSvgaPlaying = true + try { + shareParser().decodeFromURL( + URL(effect), + object : SVGAParser.ParseCompletion { + override fun onComplete(videoItem: SVGAVideoEntity) { + binding.roomCarSvga.visibility = VISIBLE + binding.roomCarSvga.loops = 1 + binding.roomCarSvga.clearsAfterStop = true + binding.roomCarSvga.setImageDrawable(SVGADrawable(videoItem)) + binding.roomCarSvga.startAnimation() + } + + override fun onError() { + isSvgaPlaying = false + binding.roomCarSvga.visibility = GONE + } + }, null + ) + } catch (e: MalformedURLException) { + e.printStackTrace() + isSvgaPlaying = false + } + } + + /** + * 真實播放vap + * + * @param viewUrl + */ + private fun playCarVAPEnterRoom(viewUrl: String) { + if (TextUtils.isEmpty(viewUrl)) return + if (!AvRoomDataManager.get().mIsNeedGiftEffect || + AvRoomDataManager.get().isSelfGamePlaying + ) { + return + } + isSvgaPlaying = true + binding.vapAnimView.visibility = VISIBLE + binding.vapAnimView.loadAnim(viewUrl) + } + + /** + * 跨房PK飄屏 + * + * @param chatRoomMessage + */ + private fun addRoomPKNotify(chatRoomMessage: ChatRoomMessage) { + messagesRoomPK.add(chatRoomMessage) + if (binding.clNotify.visibility == GONE) { + binding.clNotify.visibility = VISIBLE + } + if (disposableRoomPK == null || messagesRoomPK.size == 1) { + disposableRoomPK = Observable.interval(0, 4, TimeUnit.SECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .takeWhile { messagesRoomPK.size > 0 && !mContext.isDestroyed() } + .subscribe { + if (binding.flRoomPkNotify.childCount == 0) { + showRoomPKNotify(messagesRoomPK.removeAt(0)) + } + } + } + } + + private fun showRoomPKNotify(chatRoomMessage: ChatRoomMessage) { + val roomPkBean = (chatRoomMessage.attachment as RoomPKAttachment).roomPkBean + val rootView = LayoutInflater.from(mContext).inflate(R.layout.layout_room_pk_notify, null) + (rootView.findViewById(R.id.tv_title_left) as TextView).text = + roomPkBean.winTitle.subAndReplaceDot(7) + (rootView.findViewById(R.id.tv_title_right) as TextView).text = + roomPkBean.failTitle.subAndReplaceDot(7) + (rootView.findViewById(R.id.tv_win_text) as TextView).text = roomPkBean.msg + rootView.findViewById(R.id.iv_avatar_left).load(roomPkBean.winAvatar) + rootView.findViewById(R.id.iv_avatar_right).load(roomPkBean.failAvatar) + rootView.findViewById(R.id.tv_go_room).setOnClickListener { + AVRoomActivity.start( + context, roomPkBean.winUid + ) + } + binding.flRoomPkNotify.addView(rootView) + animationLuckyGift = AnimationUtils.loadAnimation(mContext, R.anim.anim_box_notify) + rootView.startAnimation(animationLuckyGift) + binding.flRoomPkNotify.postDelayed( + { binding.flRoomPkNotify.removeView(rootView) }, + SHOW_TIME.toLong() + ) + } + + /** + * 個播跨房PK飄屏 + * + * @param chatRoomMessage + */ + private fun addSingleRoomPKNotify(chatRoomMessage: ChatRoomMessage) { + messagesSingleRoomPK.add(chatRoomMessage) + if (binding.clNotify.visibility == GONE) { + binding.clNotify.visibility = VISIBLE + } + if (disposableSingleRoomPK == null || messagesSingleRoomPK.size == 1) { + disposableSingleRoomPK = Observable.interval(0, 4, TimeUnit.SECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .takeWhile { messagesSingleRoomPK.size > 0 && !mContext.isDestroyed() } + .subscribe { + if (binding.flSingleRoomPkNotify.childCount == 0) { + showSingleRoomPKNotify(messagesSingleRoomPK.removeAt(0)) + } + } + } + } + + private fun showSingleRoomPKNotify(chatRoomMessage: ChatRoomMessage) { + val roomPkBean = (chatRoomMessage.attachment as RoomPKAttachment).roomPkBean + val rootView = + LayoutInflater.from(mContext).inflate(R.layout.layout_single_room_pk_notify, null) + (rootView.findViewById(R.id.tv_title_left) as TextView).text = + roomPkBean.winNick.subAndReplaceDot(7) + (rootView.findViewById(R.id.tv_title_right) as TextView).text = + roomPkBean.failNick.subAndReplaceDot(7) + (rootView.findViewById(R.id.tv_win_text) as TextView).text = roomPkBean.msg + rootView.findViewById(R.id.iv_avatar_left).load(roomPkBean.winAvatar) + rootView.findViewById(R.id.iv_avatar_right).load(roomPkBean.failAvatar) + rootView.findViewById(R.id.tv_go_room).setOnClickListener { v: View? -> + AVRoomActivity.start( + context, roomPkBean.winUid + ) + } + binding.flSingleRoomPkNotify.addView(rootView) + animationLuckyGift = AnimationUtils.loadAnimation(mContext, R.anim.anim_box_notify) + rootView.startAnimation(animationLuckyGift) + binding.flSingleRoomPkNotify.postDelayed( + { binding.flSingleRoomPkNotify.removeView(rootView) }, + SHOW_TIME.toLong() + ) + } + + + private fun showRoomRankNotify(chatRoomMessage: ChatRoomMessage) { + if (binding.clNotify.visibility == GONE) { + binding.clNotify.visibility = VISIBLE + } + val msgBean = (chatRoomMessage.attachment as RoomRankAttachment).msgBean + val rootView = LayoutInflater.from(mContext).inflate(R.layout.layout_room_rank_notify, null) + val textView = rootView.findViewById(R.id.tv_content) + val text = TextSpannableBuilder(textView) + .append( + ResUtil.getString(R.string.avroom_widget_roomeffectview_025), + ForegroundColorSpan(Color.WHITE) + ) + .append("「${msgBean.title}」房間", ForegroundColorSpan(Color.parseColor("#FFFC4C"))) + .append(msgBean.desc, ForegroundColorSpan(Color.WHITE)) + .append("TOP1", ForegroundColorSpan(Color.parseColor("#FFFC4C"))) + textView.text = text.build() + rootView.setOnClickListener { AVRoomActivity.start(context, msgBean.uid) } + binding.flSingleRoomRankNotify.addView(rootView) + animationLuckyGift = AnimationUtils.loadAnimation(mContext, R.anim.anim_box_notify) + rootView.startAnimation(animationLuckyGift) + binding.flSingleRoomRankNotify.postDelayed({ + binding.flSingleRoomRankNotify.removeView( + rootView + ) + }, SHOW_TIME.toLong()) + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + boxDisposable?.dispose() + disposableLuckyGift?.dispose() + disposableMemberIn?.dispose() + disposableLevelUp?.dispose() + datingDisposable?.dispose() + imDisposable?.dispose() + disposableDatingAll?.dispose() + disposableRoomPK?.dispose() + disposableSingleRoomPK?.dispose() + disposableGiftCompound?.dispose() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/widget/RoomEffectView.kt b/app/src/main/java/com/chwl/app/avroom/widget/RoomEffectView.kt new file mode 100644 index 0000000..2c174ed --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/widget/RoomEffectView.kt @@ -0,0 +1,2027 @@ +package com.chwl.app.avroom.widget + +import android.animation.Animator +import android.animation.AnimatorListenerAdapter +import android.animation.ObjectAnimator +import android.annotation.SuppressLint +import android.app.Activity +import android.content.Context +import android.graphics.Color +import android.text.Layout +import android.text.StaticLayout +import android.text.TextPaint +import android.text.TextUtils +import android.text.style.ForegroundColorSpan +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View +import android.view.ViewConfiguration +import android.view.ViewGroup +import android.view.animation.AccelerateDecelerateInterpolator +import android.view.animation.Animation +import android.view.animation.AnimationUtils +import android.widget.FrameLayout +import android.widget.ImageView +import android.widget.TextView +import androidx.core.content.ContextCompat +import androidx.core.text.HtmlCompat +import com.chwl.app.R +import com.chwl.app.avroom.activity.AVRoomActivity +import com.chwl.app.avroom.bean.RoomPlayBean +import com.chwl.app.avroom.helper.AnimHelper +import com.chwl.app.common.svga.SimpleSvgaCallback +import com.chwl.app.databinding.LayoutRoomEffectBinding +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.app.ui.utils.isDestroyed +import com.chwl.app.ui.utils.load +import com.chwl.app.ui.utils.loadAnim +import com.chwl.app.ui.webview.CommonWebViewActivity +import com.chwl.app.ui.widget.SimpleAnimListener +import com.chwl.app.ui.widget.TextSpannableBuilder +import com.chwl.app.ui.widget.drawgift.DrawGiftPlayHelper +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil +import com.chwl.app.utils.MsgBuilder +import com.chwl.app.utils.RegexUtil +import com.chwl.app.utils.SpannableBuilder +import com.chwl.core.XConstants +import com.chwl.core.auth.AuthModel +import com.chwl.core.decoration.car.bean.CarInfo +import com.chwl.core.im.custom.bean.DatingAllNotifyAttachment +import com.chwl.core.im.custom.bean.DatingAttachment +import com.chwl.core.im.custom.bean.DrawGiftAttachment +import com.chwl.core.im.custom.bean.FairyMsgAttachment +import com.chwl.core.im.custom.bean.GiftCompoundAttachment +import com.chwl.core.im.custom.bean.LevelUpNoticeAttachment +import com.chwl.core.im.custom.bean.NotifyH5Attachment +import com.chwl.core.im.custom.bean.NotifyH5Info +import com.chwl.core.im.custom.bean.RoomBoxPrizeAttachment +import com.chwl.core.im.custom.bean.RoomLuckySeaAttachment +import com.chwl.core.im.custom.bean.RoomPKAttachment +import com.chwl.core.im.custom.bean.RoomRankAttachment +import com.chwl.core.im.custom.bean.RoomReceivedLuckyGiftAttachment +import com.chwl.core.im.custom.bean.RoomUserEnterRoomMsgAttachment +import com.chwl.core.im.custom.bean.SingleRoomRankAttachment +import com.chwl.core.im.custom.bean.TarotAttachment +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.manager.IMNetEaseManager +import com.chwl.core.manager.RoomEvent +import com.chwl.core.room.bean.DatingNotifyInfo +import com.chwl.core.super_admin.util.SuperAdminUtil +import com.chwl.core.user.UserModel +import com.chwl.core.user.bean.UserInfo +import com.chwl.core.utils.extension.subAndReplaceDot +import com.chwl.library.common.util.doLog +import com.chwl.library.common.util.isRtl +import com.chwl.library.common.util.setVis +import com.chwl.library.utils.ListUtils +import com.chwl.library.utils.ResUtil +import com.chwl.library.utils.StringUtils +import com.coorchice.library.SuperTextView +import com.example.lib_utils.ktx.dp +import com.netease.nim.uikit.common.util.sys.ScreenUtil +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage +import com.opensource.svgaplayer.SVGADrawable +import com.opensource.svgaplayer.SVGADynamicEntity +import com.opensource.svgaplayer.SVGAImageView +import com.opensource.svgaplayer.SVGAParser +import com.opensource.svgaplayer.SVGAParser.Companion.shareParser +import com.opensource.svgaplayer.SVGAVideoEntity +import io.reactivex.Observable +import io.reactivex.ObservableEmitter +import io.reactivex.ObservableOnSubscribe +import io.reactivex.Single +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import java.net.MalformedURLException +import java.net.URL +import java.util.concurrent.TimeUnit + +/** + * 房間特效View(座駕,心動場景,飄屏等) + */ +class RoomEffectView @JvmOverloads constructor( + private val mContext: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : FrameLayout(mContext, attrs, defStyleAttr) { + private val mCarEffectList: MutableList by lazy { ArrayList() } + + //頂部飄屏總展示時間 + private val SHOW_TIME = 4500 + private val CLOSE_TIME = 5000 + + //頂部飄屏周期 + private val PERIOD = 1000 + private val binding: LayoutRoomEffectBinding = + LayoutRoomEffectBinding.inflate(LayoutInflater.from(mContext), this, true) + + private val imDisposable: Disposable? + + private var animationPlay: Animation? = null + private var playDisposable: Disposable? = null + private val messagesPlay: MutableList by lazy { ArrayList() } + + private var boxDisposable: Disposable? = null + + private var animationLuckyGift: Animation? = null + private var disposableLuckyGift: Disposable? = null + + private var disposableMemberIn: Disposable? = null + private val messagesMemberIn: MutableList by lazy { ArrayList() } + + private var disposableLevelUp: Disposable? = null + private val messagesLevelUp: MutableList by lazy { ArrayList() } + + private var animationDatingAll: Animation? = null + private var disposableDatingAll: Disposable? = null + private val messagesDatingAll: MutableList by lazy { ArrayList() } + private var datingDisposable: Disposable? = null + + + private var disposableRoomPK: Disposable? = null + private val messagesRoomPK: MutableList by lazy { ArrayList() } + + private var disposableSingleRoomPK: Disposable? = null + private val messagesSingleRoomPK: MutableList by lazy { ArrayList() } + + private var disposableGiftCompound: Disposable? = null + private val messagesGiftCompound: MutableList by lazy { ArrayList() } + + private var animationRadish: Animation? = null + private val messagesRadish: MutableList by lazy { java.util.ArrayList() } + private var radishDisposable: Disposable? = null + + private val messagesRadishSVGA: MutableList by lazy { java.util.ArrayList() } + private var radishSVGADisposable: Disposable? = null + + private var isSvgaPlaying = false + + private var isHideCarEffect = false + + private val drawGiftPlayHelper: DrawGiftPlayHelper by lazy { DrawGiftPlayHelper(context as Activity) } + + private var isPlayAnim = false + + private var onPlayAnimCallback: (() -> Boolean)? = null + + fun setOnPlayAnimCallback(onPlayAnimCallback: (() -> Boolean)) { + this.onPlayAnimCallback = onPlayAnimCallback + } + + private fun loopCarAnim() { + if (context.isDestroyed()) return + isSvgaPlaying = false + + if (isHideCarEffect && mCarEffectList.isNotEmpty()) { + mCarEffectList.clear() + } + if (ListUtils.isListEmpty(mCarEffectList)) { + binding.roomCarSvga.visibility = GONE + binding.vapAnimView.visibility = GONE + return + } + mCarEffectList.removeAt(0) + if (!ListUtils.isListEmpty(mCarEffectList)) { + playCarAnim(mCarEffectList[0]) + } + } + + init { + imDisposable = IMNetEaseManager.get().chatRoomEventObservable + .subscribe { roomEvent: RoomEvent? -> + if (roomEvent == null || AvRoomDataManager.get().isSelfGamePlaying) return@subscribe + when (roomEvent.event) { +// RoomEvent.BOX_NOTIFY -> {//寻爱 +// addPlayNotify(RoomEvent.BOX_NOTIFY, roomEvent.chatRoomMessage) +// } +// +// RoomEvent.BOX_NOTIFY_SVGA -> {//寻爱svga +// addPlayNotify(RoomEvent.BOX_NOTIFY_SVGA, roomEvent.chatRoomMessage) +// } + + RoomEvent.TAROT_NOTIFY, + RoomEvent.TAROT_NOTIFY_SVGA -> { + addPlayNotify(roomEvent.event, roomEvent.chatRoomMessage) + } + + RoomEvent.NOTIFY_H5 -> { + addPlayNotify(roomEvent.event, roomEvent.chatRoomMessage) + } + +// RoomEvent.RECEIVE_ROOM_LUCKY_BAG_NOTICE, RoomEvent.RECEIVE_SERVICE_LUCKY_BAG_NOTICE ->//全服福袋 +// //廳內福袋 +// addPlayNotify(roomEvent.event, roomEvent.chatRoomMessage) + + RoomEvent.LUCKY_SEA_GIFT_ROOM_NOTIFY -> {// 星级厨房房间飘屏通知 + addPlayNotify(roomEvent.event, roomEvent.chatRoomMessage) + } + + RoomEvent.LUCKY_SEA_GIFT_SERVER_NOTIFY -> {// 星级厨房全服飘屏通知 + addPlayNotify(roomEvent.event, roomEvent.chatRoomMessage) + } + + RoomEvent.FAIRY_DRAW_GIFT_L4, + RoomEvent.FAIRY_DRAW_GIFT_L5, + RoomEvent.FAIRY_CONVERT_L1, + RoomEvent.FAIRY_CONVERT_L2, + RoomEvent.FAIRY_CONVERT_L3 -> { + addPlayNotify(roomEvent.event, roomEvent.chatRoomMessage) + } + + RoomEvent.DATING_ALL_NOTIFY -> addDatingAllNotify(roomEvent.chatRoomMessage) + RoomEvent.RADISH_NOTIFY, + RoomEvent.RADISH_NOTIFY_SVGA -> addRadishNotify(roomEvent.chatRoomMessage) + + RoomEvent.ROOM_GIFT_COMPOUND -> addGiftCompoundNotify(roomEvent.chatRoomMessage) + RoomEvent.DATING_PUBLISH_RESULT -> showHandAnim((roomEvent.chatRoomMessage.attachment as DatingAttachment).datingNotifyInfo) + RoomEvent.RECEIVE_MEMBER_IN_NOTICE -> //進入房間 + addMemberInNotify(roomEvent.chatRoomMessage) + + RoomEvent.RECEIVE_EXPER_LEVEL_UP_NOTICE -> addLevelUpNotify(roomEvent.chatRoomMessage) + RoomEvent.ENTER_ROOM -> { //自己看到的座驾 + if (!SuperAdminUtil.isSuperAdmin()) { + playCarSvga(AuthModel.get().currentUid.toString(), null, true) + } + } + + RoomEvent.CAR_MEMBER_IN -> { //接收别人的座驾 + if (roomEvent.mRoomCarMsgAttachment != null) { + playCarSvga( + null, + CarInfo( + roomEvent.mRoomCarMsgAttachment.effect, + roomEvent.mRoomCarMsgAttachment.viewUrl, + roomEvent.mRoomCarMsgAttachment.otherViewType + ), + false + ) + } + } + + RoomEvent.ROOM_PK_NOTIFY -> addRoomPKNotify(roomEvent.chatRoomMessage) + RoomEvent.SINGLE_ROOM_PK_NOTIFY -> addSingleRoomPKNotify(roomEvent.chatRoomMessage) + RoomEvent.SINGLE_ROOM_RANK_TOP_NOTIFY -> showSingleRoomRankNotify(roomEvent.chatRoomMessage) + RoomEvent.ROOM_RANK_TOP_NOTIFY -> showRoomRankNotify(roomEvent.chatRoomMessage) + RoomEvent.ROOM_CAR_EFFECT_HIDE -> { + isHideCarEffect = true + loopCarAnim() + } + + RoomEvent.ROOM_CAR_EFFECT_SHOW -> { + isHideCarEffect = false + } + + RoomEvent.DRAW_GIFT_EFFECT -> { + val drawGiftAttachment = + (roomEvent.chatRoomMessage?.attachment as? DrawGiftAttachment) + ?: return@subscribe + drawGiftPlayHelper.prepareShowDrawGift( + drawGiftAttachment.giftId, + drawGiftAttachment.drawFixedArray, + false + ) + } + + else -> {} + } + } + binding.roomCarSvga.callback = object : SimpleSvgaCallback() { + override fun onFinished() { + loopCarAnim() + } + } + binding.vapAnimView.setAnimListener(object : SimpleAnimListener() { + override fun onVideoComplete() { + loopCarAnim() + } + }) + } + + /** + * 玩法飄屏 + * + * @param chatRoomMessage + */ + private fun addPlayNotify(event: Int, chatRoomMessage: ChatRoomMessage) { + if (binding.clNotify.visibility == GONE) { + binding.clNotify.visibility = VISIBLE + } + messagesPlay.add(RoomPlayBean(event, chatRoomMessage)) + if (playDisposable == null || messagesPlay.size == 1) { + playDisposable = Observable.interval(0, PERIOD.toLong(), TimeUnit.MILLISECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .takeWhile { messagesPlay.size > 0 && !mContext.isDestroyed() } + .subscribe { + if (binding.flPlayNotify.childCount != 0) { + return@subscribe + } + + when (messagesPlay[0].event) { +// RoomEvent.BOX_NOTIFY -> {//寻爱 +// if ((mContext as AVRoomActivity).isTopActivity) { +// isPlayAnim = true +// val isPlay = onPlayAnimCallback?.invoke() ?: false +// if (isPlay) { +// margin( +// binding.clNotify, +// 0, +// UIUtil.dip2px(context, 180.0), +// 0, +// 0 +// ) +// } else { +// margin( +// binding.clNotify, +// 0, +// UIUtil.dip2px(context, 60.0), +// 0, +// 0 +// ) +// } +// showBoxNotify( +// messagesPlay.removeAt(0) +// ) +// } +// } +// +// RoomEvent.BOX_NOTIFY_SVGA -> {//寻爱 +// if ((mContext as AVRoomActivity).isTopActivity) { +// isPlayAnim = true +// val isPlay = onPlayAnimCallback?.invoke() ?: false +// if (isPlay) { +// margin( +// binding.clNotify, +// 0, +// UIUtil.dip2px(context, 180.0), +// 0, +// 0 +// ) +// } else { +// margin( +// binding.clNotify, +// 0, +// UIUtil.dip2px(context, 60.0), +// 0, +// 0 +// ) +// } +// showBoxNotifyBySVGA(messagesPlay.removeAt(0)) +// } +// } + + RoomEvent.TAROT_NOTIFY -> { + if ((mContext as AVRoomActivity).isTopActivity) { + isPlayAnim = true + val isPlay = onPlayAnimCallback?.invoke() ?: false + if (isPlay) { + margin( + binding.clNotify, + 0, + UIUtil.dip2px(context, 180.0), + 0, + 0 + ) + } else { + margin( + binding.clNotify, + 0, + UIUtil.dip2px(context, 60.0), + 0, + 0 + ) + } + showTarotNotify( + messagesPlay.removeAt(0) + ) + } + } + + RoomEvent.TAROT_NOTIFY_SVGA -> { + if ((mContext as AVRoomActivity).isTopActivity) { + isPlayAnim = true + val isPlay = onPlayAnimCallback?.invoke() ?: false + if (isPlay) { + margin( + binding.clNotify, + 0, + UIUtil.dip2px(context, 180.0), + 0, + 0 + ) + } else { + margin( + binding.clNotify, + 0, + UIUtil.dip2px(context, 60.0), + 0, + 0 + ) + } + showTarotNotifyBySVGA(messagesPlay.removeAt(0)) + } + } + + RoomEvent.NOTIFY_H5 -> { + if (!(mContext as AVRoomActivity).isTopActivity) { + return@subscribe + } + + isPlayAnim = true + val isPlay = onPlayAnimCallback?.invoke() ?: false + margin( + binding.clNotify, + 0, + UIUtil.dip2px(context, if (isPlay) 180.0 else 60.0), + 0, + 0 + ) + + val msg = messagesPlay.removeAt(0) + val attachment = msg.chatRoomMessage.attachment as NotifyH5Attachment + val bean = attachment.bean ?: return@subscribe + if (bean.floatingType == 0) { + showNotifyH5(bean) + } else { + showNotifyH5WithAnim(bean) + } + + } + + RoomEvent.RECEIVE_ROOM_LUCKY_BAG_NOTICE, RoomEvent.RECEIVE_SERVICE_LUCKY_BAG_NOTICE -> {//福袋 + isPlayAnim = true + val isPlay = onPlayAnimCallback?.invoke() ?: false + if (isPlay) { + margin(binding.clNotify, 0, UIUtil.dip2px(context, 180.0), 0, 0) + } else { + margin(binding.clNotify, 0, UIUtil.dip2px(context, 60.0), 0, 0) + } + showLuckyBagNotify( + messagesPlay.removeAt(0) + ) + } + + RoomEvent.LUCKY_SEA_GIFT_ROOM_NOTIFY -> {//星级厨房 + isPlayAnim = true + val isPlay = onPlayAnimCallback?.invoke() ?: false + if (isPlay) { + margin(binding.clNotify, 0, UIUtil.dip2px(context, 180.0), 0, 0) + } else { + margin(binding.clNotify, 0, UIUtil.dip2px(context, 60.0), 0, 0) + } + showLuckySeaNotify( + messagesPlay.removeAt(0) + ) + } + + RoomEvent.LUCKY_SEA_GIFT_SERVER_NOTIFY -> {//星级厨房 + isPlayAnim = true + val isPlay = onPlayAnimCallback?.invoke() ?: false + if (isPlay) { + margin(binding.clNotify, 0, UIUtil.dip2px(context, 180.0), 0, 0) + } else { + margin(binding.clNotify, 0, UIUtil.dip2px(context, 60.0), 0, 0) + } + showLuckySeaNotifyBySVGA( + messagesPlay.removeAt(0) + ) + } + + RoomEvent.FAIRY_DRAW_GIFT_L4, + RoomEvent.FAIRY_DRAW_GIFT_L5, + RoomEvent.FAIRY_CONVERT_L1, + RoomEvent.FAIRY_CONVERT_L2, + RoomEvent.FAIRY_CONVERT_L3 -> {//夺宝 + isPlayAnim = true + val isPlay = onPlayAnimCallback?.invoke() ?: false + if (isPlay) { + margin(binding.clNotify, 0, UIUtil.dip2px(context, 180.0), 0, 0) + } else { + margin(binding.clNotify, 0, UIUtil.dip2px(context, 60.0), 0, 0) + } + showFairyNotify( + messagesPlay.removeAt(0) + ) + } + } + } + } + } + + private fun showFairyNotify(roomPlayBean: RoomPlayBean) { + val chatRoomMessage = roomPlayBean.chatRoomMessage + val attachment = chatRoomMessage.attachment as FairyMsgAttachment + when (roomPlayBean.event) { + RoomEvent.FAIRY_DRAW_GIFT_L4, + RoomEvent.FAIRY_CONVERT_L1, + RoomEvent.FAIRY_CONVERT_L2 -> { + val textView = + LayoutInflater.from(mContext) + .inflate(R.layout.layout_room_fairy_notify, null) as TextView + val text = MsgBuilder.buildFairyMsg(roomPlayBean.event, attachment) + textView.text = text.build() + animationPlay = AnimationUtils.loadAnimation(mContext, R.anim.anim_box_notify) + binding.flPlayNotify.addView(textView) + textView.startAnimation(animationPlay) + binding.flPlayNotify.postDelayed( + { + binding.flPlayNotify.removeView(textView) + isPlayAnim = false + }, + SHOW_TIME.toLong() + ) + } + + RoomEvent.FAIRY_DRAW_GIFT_L5, + RoomEvent.FAIRY_CONVERT_L3 -> { + showFairyNotifyBySVGA(roomPlayBean) + } + } + + } + + private fun showFairyNotifyBySVGA(roomPlayBean: RoomPlayBean) { + val chatRoomMessage = roomPlayBean.chatRoomMessage + val attachment = chatRoomMessage.attachment as FairyMsgAttachment + val text = MsgBuilder.buildFairyMsg(roomPlayBean.event, attachment) + val svgaImageView = SVGAImageView(mContext) + svgaImageView.loops = 1 + svgaImageView.clearsAfterStop = true + val params = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT) + svgaImageView.layoutParams = params + svgaImageView.callback = object : SimpleSvgaCallback() { + override fun onFinished() { + binding.flPlayNotify.post { + binding.flPlayNotify.removeView(svgaImageView) + isPlayAnim = false + } + } + } + binding.flPlayNotify.addView(svgaImageView) + shareParser().decodeFromAssets( + "svga/all_fairy.svga", + object : SVGAParser.ParseCompletion { + override fun onComplete(videoItem: SVGAVideoEntity) { + val dynamicEntity = SVGADynamicEntity() + val textPaint = TextPaint() + textPaint.color = Color.WHITE //字体颜色 + textPaint.textSize = 20f //字体大小 + dynamicEntity.setDynamicText( + StaticLayout( + text.build(), + 0, + text.build().length, + textPaint, + 0, + Layout.Alignment.ALIGN_CENTER, + 1.0f, + 0.0f, + false + ), "touming_text_name" + ) + val drawable = SVGADrawable(videoItem, dynamicEntity) + svgaImageView.setImageDrawable(drawable) + svgaImageView.startAnimation() + } + + override fun onError() {} + }, + null + ) + } + + /** + * 幸運池飄屏 + * + * @param chatRoomMessage + */ + private fun addDatingAllNotify(chatRoomMessage: ChatRoomMessage) { + if (binding.clNotify.visibility == GONE) { + binding.clNotify.visibility = VISIBLE + } + messagesDatingAll.add(chatRoomMessage) + if (disposableDatingAll == null || messagesDatingAll.size == 1) { + disposableDatingAll = Observable.interval(0, 3, TimeUnit.SECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .takeWhile { messagesDatingAll.size > 0 && !mContext.isDestroyed() } + .subscribe { + if (binding.flDatingAllNotify.childCount == 0) { + showDatingAllNotify( + messagesDatingAll.removeAt(0) + ) + } + } + } + } + + private fun showDatingAllNotify(chatRoomMessage: ChatRoomMessage) { + val attachment = chatRoomMessage.attachment as DatingAllNotifyAttachment + val (_, _, oneUserNick, anotherUserNick, roomUid, roomTitle, backgroundUrl, joinHandLevel, _, sweetWords) = attachment.datingAllNotifyInfo + ?: return + //自己房間不需要飄 + if (AvRoomDataManager.get().roomUid == roomUid) return + val textView = LayoutInflater.from(mContext) + .inflate(R.layout.layout_room_dating_all_notify, null) as TextView + textView.setOnClickListener { AVRoomActivity.start(mContext, roomUid) } + var defaultBg = R.drawable.bg_dating_hand_1 + when (joinHandLevel) { + 1 -> defaultBg = R.drawable.bg_dating_hand_1 + 2 -> defaultBg = R.drawable.bg_dating_hand_2 + 3 -> defaultBg = R.drawable.bg_dating_hand_3 + } + textView.setBackgroundResource(defaultBg) + ImageLoadUtils.loadBackground(mContext, backgroundUrl, defaultBg, textView) + val text = SpannableBuilder() + .append( + ResUtil.getString(R.string.avroom_widget_roomeffectview_01), + ForegroundColorSpan(Color.WHITE) + ) + .append( + getShortString(oneUserNick, 8), + ForegroundColorSpan(resources.getColor(R.color.notice_nick)) + ) + .append( + ResUtil.getString(R.string.avroom_widget_roomeffectview_02), + ForegroundColorSpan(Color.WHITE) + ) + .append( + getShortString(anotherUserNick, 8), + ForegroundColorSpan(resources.getColor(R.color.notice_nick)) + ) + .append( + ResUtil.getString(R.string.avroom_widget_roomeffectview_03) + getShortString( + roomTitle, + 10 + ) + ")" + sweetWords, + ForegroundColorSpan(Color.WHITE) + ) + textView.text = text.build() + animationDatingAll = AnimationUtils.loadAnimation(mContext, R.anim.anim_box_notify) + binding.flDatingAllNotify.addView(textView) + textView.startAnimation(animationDatingAll) + binding.flDatingAllNotify.postDelayed( + { binding.flDatingAllNotify.removeView(textView) }, + 4500 + ) + } + + private fun getShortString(text: String, max: Int): String { + return if (TextUtils.isEmpty(text) || text.length <= max) text else text.substring( + 0, + max + ) + "…" + } + + private fun margin(v: View, l: Int, t: Int, r: Int, b: Int) { + if (v.layoutParams is MarginLayoutParams) { + val params = v.layoutParams as MarginLayoutParams + params.setMargins(l, t, r, b) + v.requestLayout() + } + } + + private fun showLuckyBagNotify(roomPlayBean: RoomPlayBean) { + val message = roomPlayBean.chatRoomMessage + val attachment = message.attachment as? RoomReceivedLuckyGiftAttachment ?: return + val noticeInfo = attachment.luckyBagNoticeInfo ?: return + val text = SpannableBuilder() + .append( + ResUtil.getString(R.string.avroom_widget_roomeffectview_04), + ForegroundColorSpan(Color.WHITE) + ) + .append( + noticeInfo.nick.subAndReplaceDot(6) + " ", + ForegroundColorSpan(resources.getColor(R.color.notice_nick)) + ) + .append( + ResUtil.getString(R.string.avroom_widget_roomeffectview_05), + ForegroundColorSpan(Color.WHITE) + ) + .append( + noticeInfo.luckyBagName + " ", + ForegroundColorSpan(resources.getColor(R.color.notice_nick)) + ) + .append( + ResUtil.getString(R.string.avroom_widget_roomeffectview_06), + ForegroundColorSpan(Color.WHITE) + ) + .append( + noticeInfo.goldPrice + " ", + ForegroundColorSpan(resources.getColor(R.color.notice_nick)) + ) + .append( + ResUtil.getString(R.string.avroom_widget_roomeffectview_07), + ForegroundColorSpan(Color.WHITE) + ) + .append( + noticeInfo.giftName, + ForegroundColorSpan(resources.getColor(R.color.notice_nick)) + ) + + val svgaImageView = SVGAImageView(mContext) + svgaImageView.loops = 1 + svgaImageView.clearsAfterStop = true + shareParser().decodeFromAssets( + "svga/lucky_gift_notify.svga", + object : SVGAParser.ParseCompletion { + override fun onComplete(videoItem: SVGAVideoEntity) { + binding.flPlayNotify.addView(svgaImageView) + val dynamicEntity = SVGADynamicEntity() + val textPaint = TextPaint() + textPaint.color = Color.WHITE //字體顏色 + textPaint.textSize = 24f //字體大小 + dynamicEntity.setDynamicText( + StaticLayout( + text.build(), + 0, + text.build().length, + textPaint, + 0, + Layout.Alignment.ALIGN_CENTER, + 1.0f, + 0.0f, + false + ), "fdpp_copywriting" + ) + if (AvRoomDataManager.get().roomUid == noticeInfo.roomUid) { + dynamicEntity.setHidden(true, "img_206") + } else { + svgaImageView.setOnClickListener { + //跳轉房間要移除監聽,不然可能NPE + svgaImageView.callback = null + AVRoomActivity.start(mContext, noticeInfo.roomUid) + } + } + val drawable = SVGADrawable(videoItem, dynamicEntity) + svgaImageView.setImageDrawable(drawable) + svgaImageView.stepToFrame(0, true) + } + + override fun onError() {} + }) + svgaImageView.callback = object : SimpleSvgaCallback() { + override fun onFinished() { + binding.flPlayNotify.post { + binding.flPlayNotify.removeView(svgaImageView) + isPlayAnim = false + } + } + } + } + + private fun showLuckySeaNotify(roomPlayBean: RoomPlayBean) { + val chatRoomMessage = roomPlayBean.chatRoomMessage + val attachment = chatRoomMessage.attachment as RoomLuckySeaAttachment + val bean = attachment.roomLuckySeaMsgInfo + val textView = + LayoutInflater.from(mContext) + .inflate(R.layout.layout_room_lucky_sea_notify, null) as TextView + val text = SpannableBuilder() + .append( + ResUtil.getString(R.string.congratulation), + ForegroundColorSpan(Color.WHITE) + ) + .append( + bean.nick, + ForegroundColorSpan(ContextCompat.getColor(context, R.color.notice_nick)) + ) + .append( + ResUtil.getString(R.string.in_the_star_kitchen_draw), + ForegroundColorSpan(Color.WHITE) + ) + .append( + bean.itemMultiple.toString(), + ForegroundColorSpan(ContextCompat.getColor(context, R.color.color_00EAFF)) + ) + .append( + ResUtil.getString(R.string.times_reward_get), + ForegroundColorSpan(Color.WHITE) + ) + .append( + bean.diamonds.toString(), + ForegroundColorSpan(ContextCompat.getColor(context, R.color.color_00EAFF)) + ) + .append( + ResUtil.getString(R.string.diamond_point), + ForegroundColorSpan(Color.WHITE) + ) + textView.text = text.build() + animationPlay = AnimationUtils.loadAnimation(mContext, R.anim.anim_box_notify) + binding.flPlayNotify.addView(textView) + textView.startAnimation(animationPlay) + binding.flPlayNotify.postDelayed( + { + binding.flPlayNotify.removeView(textView) + isPlayAnim = false + }, + SHOW_TIME.toLong() + ) + } + + private fun showLuckySeaNotifyBySVGA(roomPlayBean: RoomPlayBean) { + val chatRoomMessage = roomPlayBean.chatRoomMessage + val attachment = chatRoomMessage.attachment as RoomLuckySeaAttachment + val bean = attachment.roomLuckySeaMsgInfo + val text = SpannableBuilder() + .append( + ResUtil.getString(R.string.congratulation), + ForegroundColorSpan(Color.WHITE) + ) + .append( + bean.nick + " ", + ForegroundColorSpan(ContextCompat.getColor(context, R.color.notice_nick)) + ) + .append( + ResUtil.getString(R.string.in_the_star_kitchen_draw), + ForegroundColorSpan(Color.WHITE) + ) + .append( + bean.itemMultiple.toString(), + ForegroundColorSpan(ContextCompat.getColor(context, R.color.color_00EAFF)) + ) + .append( + ResUtil.getString(R.string.times_reward_get), + ForegroundColorSpan(Color.WHITE) + ) + .append( + bean.diamonds.toString(), + ForegroundColorSpan(ContextCompat.getColor(context, R.color.color_00EAFF)) + ) + .append( + ResUtil.getString(R.string.diamond_point), + ForegroundColorSpan(Color.WHITE) + ) + val svgaImageView = SVGAImageView(mContext) + svgaImageView.loops = 1 + svgaImageView.clearsAfterDetached = true + val params = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT) + svgaImageView.layoutParams = params + svgaImageView.callback = object : SimpleSvgaCallback() { + override fun onFinished() { + binding.flPlayNotify.post { + binding.flPlayNotify.removeView(svgaImageView) + isPlayAnim = false + } + } + } + binding.flPlayNotify.addView(svgaImageView) + shareParser().decodeFromAssets( + "svga/lucky_sea_notify.svga", + object : SVGAParser.ParseCompletion { + override fun onComplete(videoItem: SVGAVideoEntity) { + val dynamicEntity = SVGADynamicEntity() + val textPaint = TextPaint() + textPaint.color = Color.WHITE //字體顏色 + textPaint.textSize = 24f //字體大小 + dynamicEntity.setDynamicText( + StaticLayout( + text.build(), + 0, + text.build().length, + textPaint, + 0, + Layout.Alignment.ALIGN_CENTER, + 1.0f, + 0.0f, + false + ), "noble_text_tx" + ) + svgaImageView.setOnClickListener { + if (!TextUtils.isEmpty(bean.skipUrl)) { + CommonWebViewActivity.start(mContext, bean.skipUrl) + } + } + val drawable = SVGADrawable(videoItem, dynamicEntity) + svgaImageView.setImageDrawable(drawable) + svgaImageView.stepToFrame(0, true) + } + + override fun onError() {} + }, + null + ) + } + + private fun showNotifyH5(data: NotifyH5Info) { + val textView = LayoutInflater.from(mContext) + .inflate(R.layout.layout_notify_h5, null) as TextView + textView.text = data.content + animationPlay = AnimationUtils.loadAnimation(mContext, R.anim.anim_box_notify) + binding.flPlayNotify.addView(textView) + textView.startAnimation(animationPlay) + binding.flPlayNotify.postDelayed( + { + animationPlay = AnimationUtils.loadAnimation(mContext, R.anim.anim_box_notify_close) + textView.startAnimation(animationPlay) + }, + SHOW_TIME.toLong() + ) + binding.flPlayNotify.postDelayed({ + binding.flPlayNotify.removeView(textView) + isPlayAnim = false + }, CLOSE_TIME.toLong()) + } + + private fun showNotifyH5WithAnim(data: NotifyH5Info) { + + val svgaImageView = SVGAImageView(mContext) + svgaImageView.loops = 1 + svgaImageView.clearsAfterStop = true + val params = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT) + svgaImageView.layoutParams = params + svgaImageView.callback = object : SimpleSvgaCallback() { + override fun onFinished() { + binding.flPlayNotify.post { + binding.flPlayNotify.removeView(svgaImageView) + isPlayAnim = false + } + } + } + binding.flPlayNotify.addView(svgaImageView) + shareParser().decodeFromAssets( + "svga/svga_notify_h5.svga", + object : SVGAParser.ParseCompletion { + override fun onComplete(videoItem: SVGAVideoEntity) { + val dynamicEntity = SVGADynamicEntity() + val textPaint = TextPaint() + textPaint.color = Color.WHITE //字體顏色 + textPaint.textSize = 24f + dynamicEntity.setDynamicText( + StaticLayout( + data.content, + 0, + data.content!!.length, + textPaint, + 0, + Layout.Alignment.ALIGN_CENTER, + 1.0f, + 0.0f, + false + ), "bg" + ) + val drawable = SVGADrawable(videoItem, dynamicEntity) + svgaImageView.setImageDrawable(drawable) + svgaImageView.stepToFrame(0, true) + } + + override fun onError() {} + }, + null + ) + } + + private fun showTarotNotify(roomPlayBean: RoomPlayBean) { + val chatRoomMessage = roomPlayBean.chatRoomMessage + val attachment = chatRoomMessage.attachment as TarotAttachment + val textView = + LayoutInflater.from(mContext) + .inflate(R.layout.layout_notify_tarot_intermediate, null) as TextView + val string = mContext.getString( + R.string.avroom_widget_roomeffectview_026, + StringUtils.abbreviate(RegexUtil.getPrintableString(attachment.tarotMsgBean.nick), 8), + attachment.tarotMsgBean.drawGoldNum + ) + textView.text = HtmlCompat.fromHtml(string, HtmlCompat.FROM_HTML_MODE_COMPACT) + animationPlay = AnimationUtils.loadAnimation(mContext, R.anim.anim_box_notify) + binding.flPlayNotify.addView(textView) + textView.startAnimation(animationPlay) + binding.flPlayNotify.postDelayed( + { + animationPlay = AnimationUtils.loadAnimation(mContext, R.anim.anim_box_notify_close) + textView.startAnimation(animationPlay) + }, + SHOW_TIME.toLong() + ) + binding.flPlayNotify.postDelayed({ + binding.flPlayNotify.removeView(textView) + isPlayAnim = false + }, CLOSE_TIME.toLong()) + } +// +// private fun showBoxNotify(roomPlayBean: RoomPlayBean) { +// val chatRoomMessage = roomPlayBean.chatRoomMessage +// val attachment = chatRoomMessage.attachment as RoomBoxPrizeAttachment +// val textView = +// LayoutInflater.from(mContext).inflate(R.layout.layout_room_box_notify, null) as TextView +// val text = SpannableBuilder() +// .append( +// ResUtil.getString(R.string.avroom_widget_roomeffectview_08), +// ForegroundColorSpan(Color.WHITE) +// ) +// .append( +// attachment.nick.subAndReplaceDot(8), +// ForegroundColorSpan(resources.getColor(R.color.notice_nick)) +// ) +// .append( +// ResUtil.getString(R.string.treasure_in_find_love) + ResUtil.getString( +// R.string.avroom_widget_roomeffectview_010 +// ), ForegroundColorSpan(Color.WHITE) +// ) +// .append( +// attachment.prizeName, +// ForegroundColorSpan(resources.getColor(R.color.notice_nick)) +// ) +// if (attachment.prizeNum > 1) { +// text.append("x" + attachment.prizeNum, ForegroundColorSpan(Color.WHITE)) +// } +// textView.text = text.build() +// animationPlay = AnimationUtils.loadAnimation(mContext, R.anim.anim_box_notify) +// binding.flPlayNotify.addView(textView) +// textView.startAnimation(animationPlay) +// binding.flPlayNotify.postDelayed( +// { +// animationPlay = AnimationUtils.loadAnimation(mContext, R.anim.anim_box_notify_close) +// textView.startAnimation(animationPlay) +// }, +// SHOW_TIME.toLong() +// ) +// binding.flPlayNotify.postDelayed({ +// binding.flPlayNotify.removeView(textView) +// isPlayAnim = false +// }, CLOSE_TIME.toLong()) +// } + + private fun showTarotNotifyBySVGA(roomPlayBean: RoomPlayBean) { + val chatRoomMessage = roomPlayBean.chatRoomMessage + val attachment = chatRoomMessage.attachment as TarotAttachment + val string = mContext.getString( + R.string.avroom_widget_roomeffectview_026, + StringUtils.abbreviate(RegexUtil.getPrintableString(attachment.tarotMsgBean.nick), 8), + attachment.tarotMsgBean.drawGoldNum + ) + val text = HtmlCompat.fromHtml(string, HtmlCompat.FROM_HTML_MODE_COMPACT) + + val svgaImageView = SVGAImageView(mContext) + svgaImageView.loops = 1 + svgaImageView.clearsAfterStop = true + val params = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT) + svgaImageView.layoutParams = params + svgaImageView.callback = object : SimpleSvgaCallback() { + override fun onFinished() { + binding.flPlayNotify.post { + binding.flPlayNotify.removeView(svgaImageView) + isPlayAnim = false + } + } + } + binding.flPlayNotify.addView(svgaImageView) + shareParser().decodeFromAssets( + "svga/svga_tarot_senior.svga", + object : SVGAParser.ParseCompletion { + override fun onComplete(videoItem: SVGAVideoEntity) { + val dynamicEntity = SVGADynamicEntity() + val textPaint = TextPaint() + textPaint.color = Color.WHITE //字體顏色 + textPaint.textSize = 22f + dynamicEntity.setDynamicText( + StaticLayout( + text, + 0, + text.length, + textPaint, + 0, + Layout.Alignment.ALIGN_CENTER, + 1.0f, + 0.0f, + false + ), "taxt" + ) + val drawable = SVGADrawable(videoItem, dynamicEntity) + svgaImageView.setImageDrawable(drawable) + svgaImageView.stepToFrame(0, true) + } + + override fun onError() {} + }, + null + ) + } + +// private fun showBoxNotifyBySVGA(roomPlayBean: RoomPlayBean) { +// val chatRoomMessage = roomPlayBean.chatRoomMessage +// val attachment = chatRoomMessage.attachment as RoomBoxPrizeAttachment +// val text = SpannableBuilder() +// .append( +// ResUtil.getString(R.string.avroom_widget_roomeffectview_011), +// ForegroundColorSpan(Color.WHITE) +// ) +// .append( +// StringUtils.abbreviate(attachment.nick, 8) + " ", +// ForegroundColorSpan(resources.getColor(R.color.notice_nick)) +// ) +// .append( +// ResUtil.getString(R.string.treasure_in_find_love) + ResUtil.getString( +// R.string.avroom_widget_roomeffectview_013 +// ), ForegroundColorSpan(Color.WHITE) +// ) +// .append( +// attachment.prizeName, +// ForegroundColorSpan(resources.getColor(R.color.notice_nick)) +// ) +// if (attachment.prizeNum > 1) { +// text.append("x" + attachment.prizeNum, ForegroundColorSpan(Color.WHITE)) +// } +// val svgaImageView = SVGAImageView(mContext) +// svgaImageView.loops = 1 +// svgaImageView.clearsAfterDetached = true +// val params = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT) +// svgaImageView.layoutParams = params +// svgaImageView.callback = object : SimpleSvgaCallback() { +// override fun onFinished() { +// animationPlay = AnimationUtils.loadAnimation(mContext, R.anim.anim_box_notify_close) +// animationPlay!!.setAnimationListener(object : SimpleAnimationListener() { +// override fun onAnimationEnd(animation: Animation?) { +// binding.flPlayNotify.removeView(svgaImageView) +// isPlayAnim = false +// } +// }) +// binding.flPlayNotify.startAnimation(animationPlay) +// } +// } +// animationPlay = AnimationUtils.loadAnimation(mContext, R.anim.anim_box_notify) +// binding.flPlayNotify.addView(svgaImageView) +// binding.flPlayNotify.startAnimation(animationPlay) +// +// shareParser().decodeFromAssets("svga/box_notify.svga", object : SVGAParser.ParseCompletion { +// override fun onComplete(videoItem: SVGAVideoEntity) { +// val dynamicEntity = SVGADynamicEntity() +// val textPaint = TextPaint() +// textPaint.color = Color.WHITE //字體顏色 +// textPaint.textSize = 24f //字體大小 +// dynamicEntity.setDynamicText( +// StaticLayout( +// text.build(), +// 0, +// text.build().length, +// textPaint, +// 0, +// Layout.Alignment.ALIGN_CENTER, +// 1.0f, +// 0.0f, +// false +// ), "bg" +// ) +// val drawable = SVGADrawable(videoItem, dynamicEntity) +// svgaImageView.setImageDrawable(drawable) +// svgaImageView.stepToFrame(0, true) +// } +// +// override fun onError() {} +// }, null) +// } + + /** + * 幸運池飄屏 + * + * @param chatRoomMessage + */ + private fun addRadishNotify(chatRoomMessage: ChatRoomMessage) { + if (binding.clNotify.visibility == GONE) { + binding.clNotify.visibility = VISIBLE + } + messagesRadish.add(chatRoomMessage) + if (radishDisposable == null || messagesRadish.size == 1) { + radishDisposable = Observable.interval(0, PERIOD.toLong(), TimeUnit.MILLISECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .takeWhile { messagesRadish.size > 0 && !mContext.isDestroyed() } + .subscribe { + if (binding.flRadishNotify.childCount == 0) { + showRadishNotify(messagesRadish.removeAt(0)) + } + } + } + } + + private fun showRadishNotify(chatRoomMessage: ChatRoomMessage?) { + val attachment = chatRoomMessage?.attachment as? RoomBoxPrizeAttachment ?: return + val textView = + LayoutInflater.from(mContext) + .inflate(R.layout.layout_room_radish_notify, null) as TextView + textView.setBackgroundResource(R.drawable.bg_radish_notice) + val text = SpannableBuilder() + .append( + ResUtil.getString(R.string.avroom_widget_roomeffectview_014), + ForegroundColorSpan(Color.WHITE) + ) + .append( + attachment.nick.subAndReplaceDot(6) + " ", + ForegroundColorSpan(resources.getColor(R.color.notice_nick)) + ) + .append( + attachment.boxTypeStr + ResUtil.getString(R.string.avroom_widget_roomeffectview_015), + ForegroundColorSpan(Color.WHITE) + ) + .append( + attachment.prizeName, + ForegroundColorSpan(resources.getColor(R.color.notice_gift)) + ) + if (attachment.prizeNum > 1) { + text.append("x" + attachment.prizeNum, ForegroundColorSpan(Color.WHITE)) + } + textView.text = text.build() + setupRoomTitleMarquee(textView) + animationRadish = AnimationUtils.loadAnimation(mContext, R.anim.anim_box_notify) + binding.flRadishNotify.addView(textView) + textView.startAnimation(animationRadish) + binding.flRadishNotify.postDelayed( + { binding.flRadishNotify.removeView(textView) }, + SHOW_TIME.toLong() + ) + } + + /** + * 添加跑馬燈 + * 以及反射一些參數影響跑馬燈 + */ + private fun setupRoomTitleMarquee(textView: TextView) { + try { + val configuration = ViewConfiguration.get(context) + val claz: Class<*> = configuration.javaClass + val field = claz.getDeclaredField("mFadingMarqueeEnabled") + field.isAccessible = true + field[configuration] = true + } catch (e: NoSuchFieldException) { + e.printStackTrace() + } catch (e: IllegalArgumentException) { + e.printStackTrace() + } catch (e: IllegalAccessException) { + e.printStackTrace() + } + textView.isSelected = true + } + + /** + * 幸運池飄屏 五級 SVGA背景的 + * + * @param chatRoomMessage + */ + private fun addRadishNotifyBySVGA(chatRoomMessage: ChatRoomMessage) { + if (binding.clNotify.visibility == GONE) { + binding.clNotify.visibility = VISIBLE + } + messagesRadishSVGA.add(chatRoomMessage) + if (radishSVGADisposable == null || messagesRadishSVGA.size == 1) { + radishSVGADisposable = Observable.interval(0, PERIOD.toLong(), TimeUnit.MILLISECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .takeWhile { messagesRadishSVGA.size > 0 && !mContext.isDestroyed() } + .subscribe { + if (binding.flSvgaRadishNotify.childCount == 0) { + showRadishNotifyBySVGA(messagesRadishSVGA.removeAt(0)) + } + } + } + } + + private fun showRadishNotifyBySVGA(chatRoomMessage: ChatRoomMessage?) { + val attachment = chatRoomMessage?.attachment as? RoomBoxPrizeAttachment ?: return + val text = SpannableBuilder() + .append( + ResUtil.getString(R.string.avroom_widget_roomeffectview_016), + ForegroundColorSpan(Color.WHITE) + ) + .append( + attachment.nick + " ", + ForegroundColorSpan(resources.getColor(R.color.notice_nick)) + ) + .append( + attachment.boxTypeStr + ResUtil.getString(R.string.avroom_widget_roomeffectview_017), + ForegroundColorSpan(Color.WHITE) + ) + .append( + attachment.prizeName, + ForegroundColorSpan(resources.getColor(R.color.notice_gift)) + ) + if (attachment.prizeNum > 1) { + text.append("x" + attachment.prizeNum, ForegroundColorSpan(Color.WHITE)) + } + val svgaImageView = SVGAImageView(mContext) + svgaImageView.loops = 1 + svgaImageView.clearsAfterStop = true + val params = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT) + svgaImageView.layoutParams = params + svgaImageView.callback = object : SimpleSvgaCallback() { + override fun onFinished() { + binding.flSvgaRadishNotify.post { + binding.flSvgaRadishNotify.removeView(svgaImageView) + } + } + } + binding.flSvgaRadishNotify.addView(svgaImageView) + shareParser().decodeFromAssets( + "svga/radish_notify.svga", + object : SVGAParser.ParseCompletion { + override fun onComplete(videoItem: SVGAVideoEntity) { + val dynamicEntity = SVGADynamicEntity() + val textPaint = TextPaint() + textPaint.color = Color.WHITE //字體顏色 + textPaint.textSize = 24f //字體大小 + dynamicEntity.setDynamicText( + StaticLayout( + text.build(), + 0, + text.build().length, + textPaint, + 0, + Layout.Alignment.ALIGN_CENTER, + 1.0f, + 0.0f, + false + ), "blb_copywriting" + ) + val drawable = SVGADrawable(videoItem, dynamicEntity) + svgaImageView.setImageDrawable(drawable) + svgaImageView.stepToFrame(0, true) + } + + override fun onError() {} + }) + } + + + /** + * 禮物合成,帶SVGA背景的消息 + * + * @param chatRoomMessage + */ + private fun addGiftCompoundNotify(chatRoomMessage: ChatRoomMessage) { + if (binding.clNotify.visibility == GONE) { + binding.clNotify.visibility = VISIBLE + } + messagesGiftCompound.add(chatRoomMessage) + if (disposableGiftCompound == null || messagesGiftCompound.size == 1) { + disposableGiftCompound = Observable.interval(0, PERIOD.toLong(), TimeUnit.MILLISECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .takeWhile { messagesGiftCompound.size > 0 && !mContext.isDestroyed() } + .subscribe { + if (binding.flGiftCompoundNotify.childCount == 0) { + showGiftCompoundNotify(messagesGiftCompound.removeAt(0)) + } + } + } + } + + private fun showGiftCompoundNotify(chatRoomMessage: ChatRoomMessage) { + val msgBean = (chatRoomMessage.attachment as GiftCompoundAttachment).msgBean + val text = SpannableBuilder() + .append( + msgBean.nick.subAndReplaceDot(7) + " ", + ForegroundColorSpan(resources.getColor(R.color.notice_nick)) + ) + .append(msgBean.msg + " ", ForegroundColorSpan(Color.WHITE)) + .append( + msgBean.giftName, + ForegroundColorSpan(resources.getColor(R.color.notice_nick)) + ) + val svgaImageView = SVGAImageView(mContext) + svgaImageView.loops = 1 + svgaImageView.clearsAfterStop = true + val params = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT) + svgaImageView.layoutParams = params + svgaImageView.callback = object : SimpleSvgaCallback() { + override fun onFinished() { + binding.flGiftCompoundNotify.post { + binding.flGiftCompoundNotify.removeView(svgaImageView) + } + } + } + binding.flGiftCompoundNotify.addView(svgaImageView) + shareParser().decodeFromAssets( + "svga/gift_compound_notify.svga", + object : SVGAParser.ParseCompletion { + override fun onComplete(videoItem: SVGAVideoEntity) { + val dynamicEntity = SVGADynamicEntity() + val textPaint = TextPaint() + textPaint.color = Color.WHITE //字體顏色 + textPaint.textSize = 24f //字體大小 + dynamicEntity.setDynamicText( + StaticLayout( + text.build(), + 0, + text.build().length, + textPaint, + 0, + Layout.Alignment.ALIGN_CENTER, + 1.0f, + 0.0f, + false + ), "noble_text_tx" + ) + val drawable = SVGADrawable(videoItem, dynamicEntity) + svgaImageView.setImageDrawable(drawable) + svgaImageView.startAnimation() + } + + override fun onError() {} + }, + null + ) + } + + /** + * 成員進入飄屏 + * + * @param chatRoomMessage + */ + private fun addMemberInNotify(chatRoomMessage: ChatRoomMessage) { + messagesMemberIn.add(chatRoomMessage) + if (disposableMemberIn == null || messagesMemberIn.size == 1) { + disposableMemberIn = Observable.interval(0, 6, TimeUnit.SECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .takeWhile { messagesMemberIn.size > 0 && !mContext.isDestroyed() } + .subscribe { + showMemberInNotify(messagesMemberIn.removeAt(0)) + } + } + } + + private fun showMemberInNotify(chatRoomMessage: ChatRoomMessage) { + "成员进入 ".doLog() + val attachment = chatRoomMessage.attachment + if (attachment is RoomUserEnterRoomMsgAttachment){ + val data = attachment.userEnterRoomBean + if (data != null) { + val targetNicks = data.nick + val fromType = data.fromType + val fromNick = data.fromNick + + val textView = LayoutInflater.from(mContext).inflate(R.layout.layout_member_in_notify, null) as SuperTextView + // 內容 + val text = TextSpannableBuilder(textView).append(targetNicks, ForegroundColorSpan(Color.WHITE)) + var enterText = ResUtil.getString(R.string.avroom_widget_roomeffectview_018) + if (fromType == AVRoomActivity.FROM_TYPE_RECOMMEND) { + enterText = ResUtil.getString(R.string.avroom_widget_roomeffectview_019) + } + if (fromType == AVRoomActivity.FROM_TYPE_USER) { + enterText = ResUtil.getString(R.string.avroom_widget_roomeffectview_020) + fromNick.subAndReplaceDot(7) + ResUtil.getString(R.string.avroom_widget_roomeffectview_021) + } + if (fromType == AVRoomActivity.FROM_TYPE_GAME_RECOMMEND) { + enterText = ResUtil.getString(R.string.avroom_widget_roomeffectview_022) + fromNick.subAndReplaceDot(7) + ResUtil.getString(R.string.avroom_widget_roomeffectview_023) + } + text.append(enterText, ForegroundColorSpan(Color.WHITE)) + + textView.text = text.build() + val wrapNick = "【" + targetNicks.subAndReplaceDot(7) + "】" + enterText + + if (data.isCpInRoom) { + //cp有特殊背景 + playMemberInAnimByPath(wrapNick, "svga/experience_entre_effect_cp.svga") + } else { + if (!TextUtils.isEmpty(data.enterRoomEffects)) { + playMemberInAnimByUrl(wrapNick, data.enterRoomEffects) // userInfo.getUserVipInfoVO().getEnterRoomEffects() + } else { + playMemberInAnimByPath(wrapNick, memberInSvgaPath(data.experLevelSeq)) // userInfo.getUserLevelVo().getExperLevelSeq() + } + } + } + } + } + + //xxx 进场特效背景 + private fun memberInSvgaPath(level: Int): String { + var path = "" + if (level in 30..39) { + path = "svga/experience_entre_effect_30.svga" + } else if (level in 40..49) { + path = "svga/experience_entre_effect_40.svga" + } else if (level in 50..59) { + path = "svga/experience_entre_effect_50.svga" + } else if (level in 60..69) { + path = "svga/experience_entre_effect_60.svga" + } else if (level in 70..79) { + path = "svga/experience_entre_effect_70.svga" + } else if (level in 80..89) { + path = "svga/experience_entre_effect_80.svga" + } else if (level >= 90) { + path = "svga/experience_entre_effect_90.svga" + } + return path + } + + private fun playMemberInAnimByPath(text: String, path: String) { + shareParser().decodeFromAssets(path, object : SVGAParser.ParseCompletion { + override fun onComplete(videoItem: SVGAVideoEntity) { + playMemberInAnim(text, videoItem) + } + + override fun onError() {} + }, null) + } + + private fun playMemberInAnimByUrl(text: String, url: String?) { + try { + shareParser().decodeFromURL(URL(url), object : SVGAParser.ParseCompletion { + override fun onComplete(videoItem: SVGAVideoEntity) { + playMemberInAnim(text, videoItem) + } + + override fun onError() {} + }, null) + } catch (e: MalformedURLException) { + e.printStackTrace() + } + } + + private fun playMemberInAnim(text: String, svgaVideoEntity: SVGAVideoEntity) { + binding.roomMenberInSvga.setVis(false) + if (svgaVideoEntity.frames == 1) { + binding.roomMenberInSvga.loops = 50 + } else { + binding.roomMenberInSvga.loops = 1 + } + binding.roomMenberInSvga.clearsAfterStop = true + val dynamicEntity = SVGADynamicEntity() + val textPaint = TextPaint() + textPaint.color = Color.WHITE //字體顏色 + textPaint.textSize = 22f //字體大小 + dynamicEntity.setDynamicText( + StaticLayout( + text, + 0, + text.length, + textPaint, + 0, + Layout.Alignment.ALIGN_NORMAL, + 1.0f, + 0.0f, + false + ), "room_text" + ) + val drawable = SVGADrawable(svgaVideoEntity, dynamicEntity) + binding.roomMenberInSvga.setImageDrawable(drawable) + binding.roomMenberInSvga.stepToFrame(0, true) + + val start = if (context.isRtl()) -317.dp.toFloat() else 317.dp.toFloat() + val objectAnimator1 = ObjectAnimator.ofFloat(binding.roomMenberInSvga, "translationX", start, 0f).setDuration(150) + objectAnimator1.interpolator = AccelerateDecelerateInterpolator() + objectAnimator1.startDelay = 150 + objectAnimator1.addListener(object : AnimatorListenerAdapter() { + override fun onAnimationStart(animation: Animator) { + super.onAnimationStart(animation) + binding.roomMenberInSvga.setVis(true) + } + + override fun onAnimationEnd(animation: Animator) { + super.onAnimationEnd(animation) + } + }) + objectAnimator1.start() + } + + /** + * 升級飄屏 + * + * @param chatRoomMessage + */ + private fun addLevelUpNotify(chatRoomMessage: ChatRoomMessage) { + messagesLevelUp.add(chatRoomMessage) + if (disposableLevelUp == null || messagesLevelUp.size == 1) { + disposableLevelUp = Observable.interval(0, 6, TimeUnit.SECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .takeWhile { messagesLevelUp.size > 0 && !mContext.isDestroyed() } + .subscribe { + showLevelUpNotify(messagesLevelUp.removeAt(0)) + } + } + } + + private fun showLevelUpNotify(chatRoomMessage: ChatRoomMessage) { + val attachment = chatRoomMessage.attachment as LevelUpNoticeAttachment + val message = attachment.getMessage() + val picUrl = attachment.getPicUrl() + val roomUid = attachment.getRoomUid() + if (picUrl == null || message == null) { + return + } + playLevelUpAnim(message, picUrl, roomUid) + } + + private fun playLevelUpAnim(message: String, picUrl: String, roomUid: Long) { + try { + shareParser().decodeFromURL(URL(picUrl), object : SVGAParser.ParseCompletion { + override fun onComplete(videoItem: SVGAVideoEntity) { + binding.roomLevelUpSvga.visibility = VISIBLE + binding.roomLevelUpSvga.loops = 1 + binding.roomLevelUpSvga.clearsAfterStop = true + val dynamicEntity = SVGADynamicEntity() + val textPaint = TextPaint() + textPaint.color = Color.WHITE //字體顏色 + textPaint.textSize = 22f //字體大小 Util.dip2px(mContext,11) + // textPaint.setShadowLayer(3, 2, 2, 0xff000000);//字體陰影,不需要可以不用設置 + dynamicEntity.setDynamicText(message, textPaint, "y_yhname") + val drawable = SVGADrawable(videoItem, dynamicEntity) + binding.roomLevelUpSvga.setImageDrawable(drawable) + binding.roomLevelUpSvga.stepToFrame(0, true) + binding.roomLevelUpSvga.callback = object : SimpleSvgaCallback() { + override fun onFinished() { + binding.roomLevelUpSvga.visibility = GONE + } + } + } + + override fun onError() {} + }, null) + binding.roomLevelUpSvga.setOnClickListener { v: View? -> + AVRoomActivity.start( + mContext, + roomUid + ) + } + } catch (e: MalformedURLException) { + e.printStackTrace() + } + } + + @SuppressLint("SetTextI18n") + private fun showHandAnim(datingNotifyInfo: DatingNotifyInfo) { + datingDisposable?.dispose() + binding.flSvgaDating.setOnClickListener { } + binding.ivDatingSvgaClose.setOnClickListener { + binding.flSvgaDating.visibility = GONE + datingDisposable?.dispose() + } + binding.flSvgaDating.post { binding.flSvgaDating.visibility = GONE } + datingDisposable = Single.just(datingNotifyInfo) + .observeOn(AndroidSchedulers.mainThread()) + .flatMap { info: DatingNotifyInfo -> + if (datingNotifyInfo.hasSelectUser && !datingNotifyInfo.hasHeart) { + showHeartAnim(datingNotifyInfo.position, datingNotifyInfo.targetPosition) + return@flatMap Single.timer( + XConstants.SELECT_ANIM_DURATION.toLong(), + TimeUnit.MILLISECONDS + ).map { info } + } + Single.just(info) + } + .observeOn(AndroidSchedulers.mainThread()) + .filter { datingNotifyInfo.hasHeart } + .toObservable() + .flatMap { info: DatingNotifyInfo -> + Observable.create( + ObservableOnSubscribe { emitter: ObservableEmitter -> + shareParser().decodeFromURL( + URL(datingNotifyInfo.svgaUrl), object : SVGAParser.ParseCompletion { + override fun onComplete(videoItem: SVGAVideoEntity) { + binding.flSvgaDating.visibility = VISIBLE + binding.llDatingSvgaTime.visibility = GONE + val dynamicEntity = SVGADynamicEntity() + val textPaint = TextPaint() + textPaint.color = Color.WHITE + textPaint.textSize = ScreenUtil.sp2px(10f).toFloat() + AnimHelper.addDynamicImage( + binding.svgaDating, + dynamicEntity, + datingNotifyInfo.avatar, + "z_tx" + ) + AnimHelper.addDynamicImage( + binding.svgaDating, + dynamicEntity, + datingNotifyInfo.targetAvatar, + "y_tx" + ) + val nickName = datingNotifyInfo.nickname.subAndReplaceDot(5) + dynamicEntity.setDynamicText( + StaticLayout( + nickName, + 0, + nickName.length, + textPaint, + 0, + Layout.Alignment.ALIGN_CENTER, + 1.0f, + 0.0f, + false + ), "z_yhname" + ) + val targetNickName = + datingNotifyInfo.targetNickname.subAndReplaceDot(5) + dynamicEntity.setDynamicText( + StaticLayout( + targetNickName, + 0, + targetNickName.length, + textPaint, + 0, + Layout.Alignment.ALIGN_CENTER, + 1.0f, + 0.0f, + false + ), "y_yhname" + ) + val drawable = SVGADrawable(videoItem, dynamicEntity) + binding.svgaDating.setImageDrawable(drawable) + binding.svgaDating.startAnimation() + emitter.onNext(info) + emitter.onComplete() + } + + override fun onError() { + emitter.onError(Throwable(ResUtil.getString(R.string.avroom_widget_roomeffectview_024))) + } + }, null + ) + } as ObservableOnSubscribe) + } + .flatMap { + Observable.intervalRange( + 1, + datingNotifyInfo.svgaSecond.toLong(), + 1, + 1, + TimeUnit.SECONDS + ) + } + .observeOn(AndroidSchedulers.mainThread()) + .doAfterTerminate { binding.flSvgaDating.visibility = GONE } + .subscribe { aLong: Long -> + val residueTime = datingNotifyInfo.svgaSecond - aLong + binding.tvDatingSecond.text = residueTime.toString() + "S" + if (residueTime == 5L) { //剩余5秒開始顯示倒計時 + binding.llDatingSvgaTime.visibility = VISIBLE + } + } + } + + private fun showHeartAnim(position: Int, targetPosition: Int) { + val micViewPoint = AvRoomDataManager.get().mMicPointMap + AnimHelper.showDatingSelectUserAnim( + context, + binding.root as ViewGroup, + micViewPoint[position], + micViewPoint[targetPosition] + ) + } + + @SuppressLint("CheckResult") + private fun playCarSvga(account: String?, carInfo: CarInfo?, isSendMsg: Boolean) { + if (isSendMsg) { + UserModel.get().getUserInfoFromServer(account?.toLong() ?: 0) + .subscribe { userInfo: UserInfo? -> + //播放座駕動效 + if (userInfo != null && userInfo.carInfo != null && userInfo.carInfo.isUsing + && userInfo.carInfo.getStatus() == CarInfo.STATUS_USER_CAN_USE + ) { + + // 貴族人員,要先判斷是否隱身 + if (userInfo.userVipInfoVO == null || !userInfo.userVipInfoVO.enterHide && !userInfo.isSuperAdmin) { + if (AvRoomDataManager.get().mIsNeedGiftEffect && + !AvRoomDataManager.get().isSelfGamePlaying && + !isHideCarEffect + ) { + mCarEffectList.add(userInfo.carInfo) + if (!binding.roomCarSvga.isAnimating && !isSvgaPlaying) { + // 播放座駕動畫 + playCarAnim(userInfo.carInfo) + } + } + + // 公屏進入房間的提示語 + IMNetEaseManager.get() + .sendCarPlayRoomMsgBySdk( + userInfo.carInfo, + userInfo.uid, + userInfo.nick + ) + .subscribe() + } + } + } + } else { + if (carInfo == null) return + if (AvRoomDataManager.get().mIsNeedGiftEffect && + !AvRoomDataManager.get().isSelfGamePlaying && + !isHideCarEffect + ) { + mCarEffectList.add(carInfo) + if (!binding.roomCarSvga.isAnimating && !isSvgaPlaying) { + playCarAnim(carInfo) + } + } + + } + } + + private fun playCarAnim(carInfo: CarInfo?) { + if (carInfo?.otherViewType == 1 && !TextUtils.isEmpty(carInfo.viewUrl)) { + playCarVAPEnterRoom(carInfo.viewUrl) + } else { + playCarSvagEnterRoom(carInfo?.effect) + } + } + + /** + * 真實播放svga + * + * @param effect + */ + private fun playCarSvagEnterRoom(effect: String?) { + if (TextUtils.isEmpty(effect)) return + if (!AvRoomDataManager.get().mIsNeedGiftEffect || + AvRoomDataManager.get().isSelfGamePlaying + ) { + return + } + isSvgaPlaying = true + try { + shareParser().decodeFromURL( + URL(effect), + object : SVGAParser.ParseCompletion { + override fun onComplete(videoItem: SVGAVideoEntity) { + binding.roomCarSvga.visibility = VISIBLE + binding.roomCarSvga.loops = 1 + binding.roomCarSvga.clearsAfterStop = true + binding.roomCarSvga.setImageDrawable(SVGADrawable(videoItem)) + binding.roomCarSvga.startAnimation() + } + + override fun onError() { + isSvgaPlaying = false + binding.roomCarSvga.visibility = GONE + } + }, null + ) + } catch (e: MalformedURLException) { + e.printStackTrace() + isSvgaPlaying = false + } + } + + /** + * 真實播放vap + * + * @param viewUrl + */ + private fun playCarVAPEnterRoom(viewUrl: String) { + if (TextUtils.isEmpty(viewUrl)) return + if (!AvRoomDataManager.get().mIsNeedGiftEffect || + AvRoomDataManager.get().isSelfGamePlaying + ) { + return + } + isSvgaPlaying = true + binding.vapAnimView.visibility = VISIBLE + binding.vapAnimView.loadAnim(viewUrl) + } + + /** + * 跨房PK飄屏 + * + * @param chatRoomMessage + */ + private fun addRoomPKNotify(chatRoomMessage: ChatRoomMessage) { + messagesRoomPK.add(chatRoomMessage) + if (binding.clNotify.visibility == GONE) { + binding.clNotify.visibility = VISIBLE + } + if (disposableRoomPK == null || messagesRoomPK.size == 1) { + disposableRoomPK = Observable.interval(0, 4, TimeUnit.SECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .takeWhile { messagesRoomPK.size > 0 && !mContext.isDestroyed() } + .subscribe { + if (binding.flRoomPkNotify.childCount == 0) { + showRoomPKNotify(messagesRoomPK.removeAt(0)) + } + } + } + } + + private fun showRoomPKNotify(chatRoomMessage: ChatRoomMessage) { + val roomPkBean = (chatRoomMessage.attachment as RoomPKAttachment).roomPkBean + val rootView = LayoutInflater.from(mContext).inflate(R.layout.layout_room_pk_notify, null) + (rootView.findViewById(R.id.tv_title_left) as TextView).text = + roomPkBean.winTitle.subAndReplaceDot(7) + (rootView.findViewById(R.id.tv_title_right) as TextView).text = + roomPkBean.failTitle.subAndReplaceDot(7) + (rootView.findViewById(R.id.tv_win_text) as TextView).text = roomPkBean.msg + rootView.findViewById(R.id.iv_avatar_left).load(roomPkBean.winAvatar) + rootView.findViewById(R.id.iv_avatar_right).load(roomPkBean.failAvatar) + rootView.findViewById(R.id.tv_go_room).setOnClickListener { + AVRoomActivity.start( + context, roomPkBean.winUid + ) + } + binding.flRoomPkNotify.addView(rootView) + animationLuckyGift = AnimationUtils.loadAnimation(mContext, R.anim.anim_box_notify) + rootView.startAnimation(animationLuckyGift) + binding.flRoomPkNotify.postDelayed( + { binding.flRoomPkNotify.removeView(rootView) }, + SHOW_TIME.toLong() + ) + } + + /** + * 個播跨房PK飄屏 + * + * @param chatRoomMessage + */ + private fun addSingleRoomPKNotify(chatRoomMessage: ChatRoomMessage) { + messagesSingleRoomPK.add(chatRoomMessage) + if (binding.clNotify.visibility == GONE) { + binding.clNotify.visibility = VISIBLE + } + if (disposableSingleRoomPK == null || messagesSingleRoomPK.size == 1) { + disposableSingleRoomPK = Observable.interval(0, 4, TimeUnit.SECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .takeWhile { messagesSingleRoomPK.size > 0 && !mContext.isDestroyed() } + .subscribe { + if (binding.flSingleRoomPkNotify.childCount == 0) { + showSingleRoomPKNotify(messagesSingleRoomPK.removeAt(0)) + } + } + } + } + + private fun showSingleRoomPKNotify(chatRoomMessage: ChatRoomMessage) { + val roomPkBean = (chatRoomMessage.attachment as RoomPKAttachment).roomPkBean + val rootView = + LayoutInflater.from(mContext).inflate(R.layout.layout_single_room_pk_notify, null) + (rootView.findViewById(R.id.tv_title_left) as TextView).text = + roomPkBean.winNick.subAndReplaceDot(7) + (rootView.findViewById(R.id.tv_title_right) as TextView).text = + roomPkBean.failNick.subAndReplaceDot(7) + (rootView.findViewById(R.id.tv_win_text) as TextView).text = roomPkBean.msg + rootView.findViewById(R.id.iv_avatar_left).load(roomPkBean.winAvatar) + rootView.findViewById(R.id.iv_avatar_right).load(roomPkBean.failAvatar) + rootView.findViewById(R.id.tv_go_room).setOnClickListener { v: View? -> + AVRoomActivity.start( + context, roomPkBean.winUid + ) + } + binding.flSingleRoomPkNotify.addView(rootView) + animationLuckyGift = AnimationUtils.loadAnimation(mContext, R.anim.anim_box_notify) + rootView.startAnimation(animationLuckyGift) + binding.flSingleRoomPkNotify.postDelayed( + { binding.flSingleRoomPkNotify.removeView(rootView) }, + SHOW_TIME.toLong() + ) + } + + private fun showSingleRoomRankNotify(chatRoomMessage: ChatRoomMessage) { + if (binding.clNotify.visibility == GONE) { + binding.clNotify.visibility = VISIBLE + } + val roomPkBean = (chatRoomMessage.attachment as SingleRoomRankAttachment).msgBean + val rootView = + LayoutInflater.from(mContext).inflate(R.layout.layout_single_room_rank_notify, null) + (rootView.findViewById(R.id.tv_nick) as TextView).text = + roomPkBean.nick.subAndReplaceDot(6) + (rootView.findViewById(R.id.tv_desc) as TextView).text = roomPkBean.desc + rootView.findViewById(R.id.iv_avatar).load(roomPkBean.avatar) + rootView.setOnClickListener { AVRoomActivity.start(context, roomPkBean.uid) } + binding.flSingleRoomRankNotify.addView(rootView) + animationLuckyGift = AnimationUtils.loadAnimation(mContext, R.anim.anim_box_notify) + rootView.startAnimation(animationLuckyGift) + binding.flSingleRoomRankNotify.postDelayed({ + binding.flSingleRoomRankNotify.removeView( + rootView + ) + }, SHOW_TIME.toLong()) + } + + private fun showRoomRankNotify(chatRoomMessage: ChatRoomMessage) { + if (binding.clNotify.visibility == GONE) { + binding.clNotify.visibility = VISIBLE + } + val msgBean = (chatRoomMessage.attachment as RoomRankAttachment).msgBean + val rootView = LayoutInflater.from(mContext).inflate(R.layout.layout_room_rank_notify, null) + val textView = rootView.findViewById(R.id.tv_content) + val text = TextSpannableBuilder(textView) + .append( + ResUtil.getString(R.string.avroom_widget_roomeffectview_025), + ForegroundColorSpan(Color.WHITE) + ) + .append("「${msgBean.title}」房間", ForegroundColorSpan(Color.parseColor("#FFFC4C"))) + .append(msgBean.desc, ForegroundColorSpan(Color.WHITE)) + .append("TOP1", ForegroundColorSpan(Color.parseColor("#FFFC4C"))) + textView.text = text.build() + rootView.setOnClickListener { AVRoomActivity.start(context, msgBean.uid) } + binding.flSingleRoomRankNotify.addView(rootView) + animationLuckyGift = AnimationUtils.loadAnimation(mContext, R.anim.anim_box_notify) + rootView.startAnimation(animationLuckyGift) + binding.flSingleRoomRankNotify.postDelayed({ + binding.flSingleRoomRankNotify.removeView( + rootView + ) + }, SHOW_TIME.toLong()) + } + + fun getIsPlayAnim(): Boolean { + return isPlayAnim + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + playDisposable?.dispose() + boxDisposable?.dispose() + disposableLuckyGift?.dispose() + disposableMemberIn?.dispose() + disposableLevelUp?.dispose() + datingDisposable?.dispose() + imDisposable?.dispose() + disposableDatingAll?.dispose() + disposableRoomPK?.dispose() + disposableSingleRoomPK?.dispose() + disposableGiftCompound?.dispose() + isPlayAnim = false + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/widget/RoomRankNavigatorAdapter.java b/app/src/main/java/com/chwl/app/avroom/widget/RoomRankNavigatorAdapter.java new file mode 100644 index 0000000..84ff839 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/widget/RoomRankNavigatorAdapter.java @@ -0,0 +1,83 @@ +package com.chwl.app.avroom.widget; + +import android.content.Context; +import android.graphics.Color; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import androidx.core.content.ContextCompat; + +import com.chwl.app.R; +import com.chwl.app.decoration.view.widgets.BadgeScaleTransitionPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.CommonNavigatorAdapter; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.indicators.LinePagerIndicator; +import com.chwl.library.utils.ResUtil; + +import java.util.ArrayList; +import java.util.List; + +/** + * 排行榜指示器定制 + * Created by lvzebiao on 2018/10/30. + */ + +public class RoomRankNavigatorAdapter extends CommonNavigatorAdapter { + + private List mTitleList = new ArrayList<>(); + + public RoomRankNavigatorAdapter() { + mTitleList.add(ResUtil.getString(R.string.avroom_widget_roomranknavigatoradapter_01)); + mTitleList.add(ResUtil.getString(R.string.avroom_widget_roomranknavigatoradapter_02)); + } + + @Override + public int getCount() { + return mTitleList.size(); + } + + @Override + public IPagerTitleView getTitleView(Context context, final int index) { + BadgeScaleTransitionPagerTitleView scaleTransitionPagerTitleView = new BadgeScaleTransitionPagerTitleView(context); + scaleTransitionPagerTitleView.setNormalColor(ContextCompat.getColor(context, R.color.white_transparent_50)); + scaleTransitionPagerTitleView.setSelectedColor(ContextCompat.getColor(context, R.color.color_759EF0)); + scaleTransitionPagerTitleView.setMinScale(1f); + scaleTransitionPagerTitleView.setTextSize(14); + scaleTransitionPagerTitleView.setText(mTitleList.get(index)); + + scaleTransitionPagerTitleView.setOnClickListener(v -> { + if (mOnItemSelectListener != null) { + mOnItemSelectListener.onItemSelect(index); + } + }); + return scaleTransitionPagerTitleView; + } + + @Override + public IPagerIndicator getIndicator(Context context) { + LinePagerIndicator indicator = new LinePagerIndicator(context); + indicator.setMode(LinePagerIndicator.MODE_WRAP_CONTENT); + indicator.setLineHeight(UIUtil.dip2px(context, 30)); + indicator.setRoundRadius(UIUtil.dip2px(context, 15)); + indicator.setLineWidth(UIUtil.dip2px(context, 171)); + indicator.setYOffset(UIUtil.dip2px(context, 2)); + indicator.setXOffset(UIUtil.dip2px(context, 2)); + indicator.setColors(Color.parseColor("#FFFFFF")); + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + indicator.setLayoutParams(lp); + return indicator; + } + + + private OnItemSelectListener mOnItemSelectListener; + + public void setOnItemSelectListener(OnItemSelectListener mOnItemSelectListener) { + this.mOnItemSelectListener = mOnItemSelectListener; + } + + public interface OnItemSelectListener { + void onItemSelect(int position); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/widget/RoomRankWrapViewPager.java b/app/src/main/java/com/chwl/app/avroom/widget/RoomRankWrapViewPager.java new file mode 100644 index 0000000..366f777 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/widget/RoomRankWrapViewPager.java @@ -0,0 +1,70 @@ +package com.chwl.app.avroom.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.view.MotionEvent; +import android.view.View; +import android.view.WindowManager; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.viewpager.widget.ViewPager; + +public class RoomRankWrapViewPager extends ViewPager { + private Context context; + private int minHeight; + + public RoomRankWrapViewPager(@NonNull Context context) { + super(context); + this.context = context; + minHeight = getMinHeight(); + } + + public RoomRankWrapViewPager(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + this.context = context; + minHeight = getMinHeight(); + } + + private int getMinHeight() { + WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + if (windowManager != null) { + DisplayMetrics displayMetrics = new DisplayMetrics(); + windowManager.getDefaultDisplay().getMetrics(displayMetrics); + return displayMetrics.heightPixels / 3 * 2; + } else { + return 800; + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int height = 0; + // 遍历所有child的高度 + for (int i = 0; i < getChildCount(); i++) { + View child = getChildAt(i); +// child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); + child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(minHeight, MeasureSpec.AT_MOST)); + int h = child.getMeasuredHeight(); + if (h < minHeight) { + h = minHeight; + } + if (h > height) { + height = h; // 采用最大的view的高度。 + } + } + heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + return false; + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + return false; + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/widget/ScaleTransformer.java b/app/src/main/java/com/chwl/app/avroom/widget/ScaleTransformer.java new file mode 100644 index 0000000..22621ed --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/widget/ScaleTransformer.java @@ -0,0 +1,23 @@ +package com.chwl.app.avroom.widget; + +import android.view.View; + +/** + * Created by chensuilun on 2016/12/16. + */ +public class ScaleTransformer implements GalleryLayoutManager.ItemTransformer { + + private static final String TAG = "CurveTransformer"; + + + @Override + public void transformItem(GalleryLayoutManager layoutManager, View item, float fraction) { + item.setPivotX(item.getWidth() / 2.f); + item.setPivotY(item.getHeight() / 2.0f); + float scale = 1 - 0.32f * Math.abs(fraction); + float alpah = 1 - 0.5f * Math.abs(fraction); + item.setScaleX(scale); + item.setScaleY(scale); + item.setAlpha(alpah); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/widget/ScrollSpeedLinearLayoutManger.java b/app/src/main/java/com/chwl/app/avroom/widget/ScrollSpeedLinearLayoutManger.java new file mode 100644 index 0000000..fd3f316 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/widget/ScrollSpeedLinearLayoutManger.java @@ -0,0 +1,53 @@ +package com.chwl.app.avroom.widget; + +import android.content.Context; +import android.graphics.PointF; +import android.util.DisplayMetrics; +import android.util.Log; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.LinearSmoothScroller; +import androidx.recyclerview.widget.RecyclerView; + +/** + * @author chenran + * @date 2017/9/24 + */ + +public class ScrollSpeedLinearLayoutManger extends LinearLayoutManager { + private float MILLISECONDS_PER_INCH = 0.2F; + private Context context; + private LinearSmoothScroller linearSmoothScroller; + private int lastPosition = -1; + + ScrollSpeedLinearLayoutManger(Context context) { + super(context); + this.context = context; + linearSmoothScroller = new LinearSmoothScroller(context) { + @Override + public PointF computeScrollVectorForPosition(int targetPosition) { + PointF pointF = ScrollSpeedLinearLayoutManger.this + .computeScrollVectorForPosition(targetPosition); + Log.e("Point", pointF.y + ""); + return pointF; + } + + @Override + protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) { + //返回滑动一个pixel需要多少毫秒 + return MILLISECONDS_PER_INCH; + } + + }; + } + + @Override + public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) { + if (linearSmoothScroller.isRunning() && lastPosition != -1) { + scrollToPosition(lastPosition); + } + linearSmoothScroller.setTargetPosition(position); + startSmoothScroll(linearSmoothScroller); + lastPosition = position; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/widget/SliddingView.java b/app/src/main/java/com/chwl/app/avroom/widget/SliddingView.java new file mode 100644 index 0000000..cbdc783 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/widget/SliddingView.java @@ -0,0 +1,51 @@ +package com.chwl.app.avroom.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.widget.HorizontalScrollView; +import android.widget.LinearLayout; + +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; + + +/** + * Created by huangmeng1 on 2018/1/18. + */ +public class SliddingView extends HorizontalScrollView { + private LinearLayout mLayout; + private View delete; + private int deletewidth; + private boolean once; + + public SliddingView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + if (!once) { + mLayout = (LinearLayout) getChildAt(0); + delete = mLayout.getChildAt(1); + deletewidth = delete.getLayoutParams().width = UIUtil.dip2px(getContext(), 63); + once = true; + } + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + switch (ev.getAction()) { + case MotionEvent.ACTION_UP: + int scollx=getScrollX(); + if (scollx>=deletewidth/2) { + smoothScrollTo(deletewidth, 0); + }else { + smoothScrollTo(0, 0); + } + return true; + } + return super.onTouchEvent(ev); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/widget/TeamPKUserListView.kt b/app/src/main/java/com/chwl/app/avroom/widget/TeamPKUserListView.kt new file mode 100644 index 0000000..bc74299 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/widget/TeamPKUserListView.kt @@ -0,0 +1,46 @@ +package com.chwl.app.avroom.widget + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.widget.FrameLayout +import androidx.core.view.isInvisible +import androidx.core.view.isVisible +import com.chwl.app.R +import com.chwl.app.databinding.LayoutRoomTeamPkUserListViewBinding +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.core.room.pk.bean.PKMemberInfo + +class TeamPKUserListView @JvmOverloads constructor( + context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 +) : FrameLayout(context, attrs, defStyleAttr) { + + private val binding = LayoutRoomTeamPkUserListViewBinding.inflate(LayoutInflater.from(context)) + private val ivAvatars = arrayOf(binding.ivAvatar1, binding.ivAvatar2, binding.ivAvatar3) + + init { + addView(binding.root) + } + + fun showBlueStyle() { + binding.ivAvatarSeat1.setImageResource(R.drawable.room_team_pk_bg_seat_blue) + binding.ivAvatarSeat2.setImageResource(R.drawable.room_team_pk_bg_seat_blue) + binding.ivAvatarSeat3.setImageResource(R.drawable.room_team_pk_bg_seat_blue) + } + + fun updateData(data: List?) { + for (i in ivAvatars.indices) { + val item = data?.getOrNull(i) + if (item.isNullOrEmpty()) { + ivAvatars[i].isInvisible = true + } else { + ivAvatars[i].isVisible = true + ImageLoadUtils.loadImage( + context, + item, + ivAvatars[i], R.drawable.default_avatar + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/widget/TemplateMessageAdapter.kt b/app/src/main/java/com/chwl/app/avroom/widget/TemplateMessageAdapter.kt new file mode 100644 index 0000000..8d49669 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/widget/TemplateMessageAdapter.kt @@ -0,0 +1,220 @@ +package com.chwl.app.avroom.widget + +import android.content.Context +import android.graphics.Color +import android.text.SpannableStringBuilder +import android.text.method.LinkMovementMethod +import android.text.style.ForegroundColorSpan +import android.view.View +import android.widget.TextView +import com.chwl.app.common.widget.OriginalDrawStatusClickSpan +import com.chwl.app.ui.widget.TextSpannableBuilder +import com.chwl.app.utils.CommonJumpHelper +import com.chwl.app.utils.SpannableBuilder +import com.chwl.core.home.bean.BannerInfo +import com.chwl.core.im.custom.bean.TemplateMessage +import com.chwl.core.im.custom.bean.TemplateMessage.TemplateNode +import com.chwl.core.im.custom.bean.TemplateMessage.Content +import com.example.lib_utils.UiUtils + + +class TemplateMessageAdapter(val listener: Listener?) { + + /** + * 解析为文本(子节点只支持TEXT类型) + */ + fun parse(context: Context, attachment: TemplateMessage?): SpannableStringBuilder? { + val builder = SpannableBuilder() + if (attachment == null) { + return null + } + val nodeList = attachment.getNodeList() + nodeList.forEach { + if (it is TemplateNode.NormalNode) { + val textColor = parseColor(it.textColor) + if (textColor != null) { + builder.append(it.text, ForegroundColorSpan(textColor)) + } else { + builder.append(it.text) + } + } else if (it is TemplateNode.SpecialNode) { + when (it.content.type) { + Content.TEXT -> { + val text = it.content.text?.getFirstText() + if (!text.isNullOrEmpty()) { + val textColor = parseColor(it.content.textColor) + val clickSpan = createClickSpan(context, it.content, listener) + val list = ArrayList() + if (textColor != null) { + list.add(ForegroundColorSpan(textColor)) + } + if (clickSpan != null) { + list.add(clickSpan) + } + builder.append(text, *list.toArray()) + } + } + } + } + } + return builder.build() + } + + fun convert(textView: TextView, attachment: TemplateMessage?) { + if (attachment == null) { + textView.text = "" + return + } + val nodeList = attachment.getNodeList() + val textBuilder = TextSpannableBuilder(textView) + nodeList.forEach { + if (it is TemplateNode.NormalNode) { + val textColor = parseColor(it.textColor) + if (textColor != null) { + textBuilder.append(it.text, ForegroundColorSpan(textColor)) + } else { + textBuilder.append(it.text) + } + } else if (it is TemplateNode.SpecialNode) { + when (it.content.type) { + Content.TEXT -> { + val text = it.content.text?.getFirstText() + if (!text.isNullOrEmpty()) { + val textColor = parseColor(it.content.textColor) + val clickSpan = createClickSpan(textView.context, it.content, listener) + val list = ArrayList() + if (textColor != null) { + list.add(ForegroundColorSpan(textColor)) + } + if (clickSpan != null) { + list.add(clickSpan) + } + textBuilder.append(text, *list.toArray()) + } + } + + TemplateMessage.Content.IMAGE -> { + val image = it.content.image + val width = it.content.width ?: 0 + val height = it.content.height ?: 0 + val clickSpan = createClickSpan(textView.context, it.content, listener) + if (height > 0 && width == 0) { + if (clickSpan != null) { + textBuilder.append( + image, + UiUtils.dip2px(height.toFloat()), + clickSpan + ) + } else { + textBuilder.append(image, UiUtils.dip2px(height.toFloat())) + } + } else if (height > 0 && width > 0) { + if (clickSpan != null) { + textBuilder.append( + image, + UiUtils.dip2px(width.toFloat()), + UiUtils.dip2px(height.toFloat()), clickSpan + ) + } else { + textBuilder.append( + image, + UiUtils.dip2px(width.toFloat()), + UiUtils.dip2px(height.toFloat()) + ) + } + } else { + if (clickSpan != null) { + textBuilder.appendImg(image, clickSpan) + } else { + textBuilder.appendImg(image) + } + } + } + } + } + } + textView.text = textBuilder.build() + textView.setOnClickListener(null) + textView.movementMethod = LinkMovementMethod() + } + + + fun convertText(textView: TextView, attachment: TemplateMessage?) { + if (attachment == null) { + textView.text = "" + return + } + val nodeList = attachment.getNodeList() + val textBuilder = TextSpannableBuilder(textView) + nodeList.forEach { + if (it is TemplateNode.NormalNode) { + val textColor = parseColor(it.textColor) + if (textColor != null) { + textBuilder.append(it.text, ForegroundColorSpan(textColor)) + } else { + textBuilder.append(it.text) + } + } else if (it is TemplateNode.SpecialNode) { + when (it.content.type) { + Content.TEXT -> { + val text = it.content.text?.getFirstText() + if (!text.isNullOrEmpty()) { + val textColor = parseColor(it.content.textColor) + val clickSpan = createClickSpan(textView.context, it.content, listener) + val list = ArrayList() + if (textColor != null) { + list.add(ForegroundColorSpan(textColor)) + } + if (clickSpan != null) { + list.add(clickSpan) + } + textBuilder.append(text, *list.toArray()) + } + } + } + } + } + textView.text = textBuilder.build() + textView.setOnClickListener(null) + textView.movementMethod = LinkMovementMethod() + } + + + private fun createClickSpan( + context: Context, + content: Content, + listener: Listener? + ): OriginalDrawStatusClickSpan? { + val skipType = content.getSkipType() + val skipUri = content.getSkipUri() + if (skipType > 0 && !skipUri.isNullOrEmpty()) { + return object : OriginalDrawStatusClickSpan() { + override fun onClick(widget: View) { + if (skipType == BannerInfo.SKIP_TYPE_ROOM_USER_CARD) { + listener?.onShowUserCard(skipUri) + } else { + CommonJumpHelper.bannerJump(context, content) + } + } + } + } else { + return null + } + } + + fun parseColor(color: String?): Int? { + if (color == null) { + return null + } + try { + return Color.parseColor(color) + } catch (e: java.lang.Exception) { + e.printStackTrace() + } + return null + } + + interface Listener { + fun onShowUserCard(uid: String) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/avroom/widget/VDHLayout.java b/app/src/main/java/com/chwl/app/avroom/widget/VDHLayout.java new file mode 100644 index 0000000..c136a4a --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/widget/VDHLayout.java @@ -0,0 +1,181 @@ +package com.chwl.app.avroom.widget; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Point; +import android.util.AttributeSet; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; +import androidx.core.view.ViewCompat; +import androidx.customview.widget.ViewDragHelper; + +import com.netease.nim.uikit.common.util.sys.ScreenUtil; + +/** + * 侧滑FrameLayout + * 子View左滑删除,右滑弹起后复位 + */ +public class VDHLayout extends FrameLayout { + private final ViewDragHelper mDragHelper; + + private final Point mAutoBackOriginPos = new Point(); + + private OnViewGoneListener listener; + + + // 新增变量:用于记录初始触摸点 + private float initialX, initialY; + private boolean isDragging; + private static final int INVALID_POINTER_ID = -1; + private int activePointerId = INVALID_POINTER_ID; + private int touchSlop; // 触摸容差值 + + + public VDHLayout(Context context, AttributeSet attrs) { + super(context, attrs); + touchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); + mDragHelper = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() { + @Override + public boolean tryCaptureView(@NonNull View child, int pointerId) { + mAutoBackOriginPos.x = child.getLeft(); + mAutoBackOriginPos.y = child.getTop(); + return true; + } + + /** + * view的left + */ + @Override + public int clampViewPositionHorizontal(@NonNull View child, int left, int dx) { + return left; + } + + /** + * view的top + */ + @Override + public int clampViewPositionVertical(@NonNull View child, int top, int dy) { + return child.getTop(); + } + + + //手指释放的时候回调 + @Override + public void onViewReleased(@NonNull View releasedChild, float xvel, float yvel) { + //mAutoBackView手指释放时可以自动回去 + if (releasedChild.getLeft() < 0 && ((Math.abs(releasedChild.getLeft()) >= releasedChild.getMeasuredWidth() * 0.2))) { + releasedChild.setEnabled(false); + releasedChild.animate() + .setDuration(100L) + .translationX(-ScreenUtil.getDisplayWidth()) + .alpha(0F) + .withEndAction(() -> { + releasedChild.setVisibility(GONE); + releasedChild.setAlpha(1f); + releasedChild.setTranslationX(0); + if(listener != null){ + listener.onViewGone(); + } + }).start(); + } else { + mDragHelper.settleCapturedViewAt(mAutoBackOriginPos.x, mAutoBackOriginPos.y); + ViewCompat.postInvalidateOnAnimation(VDHLayout.this); + } + } + + //在边界拖动时回调 + @Override + public void onEdgeDragStarted(int edgeFlags, int pointerId) { + } + + @Override + public int getViewHorizontalDragRange(@NonNull View child) { + return child.getMeasuredWidth(); + } + + }); + mDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT); + } + + + @Override + public boolean onInterceptTouchEvent(MotionEvent event) { + return mDragHelper.shouldInterceptTouchEvent(event); + } + + private static final String TAG = "VDHLayout"; + + @SuppressLint("ClickableViewAccessibility") + @Override + public boolean onTouchEvent(MotionEvent event) { + final int action = event.getActionMasked(); + + switch (action) { + case MotionEvent.ACTION_DOWN: + initialX = event.getX(); + initialY = event.getY(); + isDragging = false; + activePointerId = event.getPointerId(0); + Log.d(TAG, "ACTION_DOWN: x=" + initialX + ", y=" + initialY); + break; + + case MotionEvent.ACTION_MOVE: + if (activePointerId == INVALID_POINTER_ID) break; + + int pointerIndex = event.findPointerIndex(activePointerId); + if (pointerIndex == -1) break; + + float dx = Math.abs(event.getX(pointerIndex) - initialX); + float dy = Math.abs(event.getY(pointerIndex) - initialY); + + if (dx > touchSlop || dy > touchSlop) { + isDragging = true; + Log.d(TAG, "ACTION_MOVE: 检测到滑动, dx=" + dx + ", dy=" + dy + " -> 开始拖拽"); + } else { + Log.d(TAG, "ACTION_MOVE: 滑动未超过阈值, dx=" + dx + ", dy=" + dy); + } + break; + + case MotionEvent.ACTION_UP: + Log.d(TAG, "ACTION_UP: isDragging=" + isDragging + ", 是否消费事件: " + isDragging); + if (!isDragging) { + Log.d(TAG, "这是一个点击事件,未发生拖动"); + } + isDragging = false; + activePointerId = INVALID_POINTER_ID; + break; + + case MotionEvent.ACTION_CANCEL: + Log.d(TAG, "ACTION_CANCEL: 拖拽被取消"); + isDragging = false; + activePointerId = INVALID_POINTER_ID; + break; + } + + mDragHelper.processTouchEvent(event); + Log.d(TAG, "onTouchEvent end : isDragging = "+isDragging); + // 只有在拖拽时才消费事件,否则不消费,交给子 View + return isDragging; + } + + + @Override + public void computeScroll() { + if (mDragHelper.continueSettling(true)) { + invalidate(); + } + } + + public void setListener(OnViewGoneListener listener) { + this.listener = listener; + } + + public interface OnViewGoneListener{ + void onViewGone(); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/widget/VerticalViewPagerAdapter.java b/app/src/main/java/com/chwl/app/avroom/widget/VerticalViewPagerAdapter.java new file mode 100644 index 0000000..48ff126 --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/widget/VerticalViewPagerAdapter.java @@ -0,0 +1,57 @@ +package com.chwl.app.avroom.widget; + +import android.util.SparseArray; + +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.viewpager2.adapter.FragmentStateAdapter; + +import com.chwl.app.avroom.fragment.FakeSingleRoomBackFragment; +import com.chwl.app.avroom.fragment.FakeSingleRoomFragment; +import com.chwl.app.avroom.fragment.HomePartyFragment; + + +/** + * 作者: ch + * 时间: 2018/7/30 0030-下午 3:42 + * 描述: + * 来源: + */ + + +public class VerticalViewPagerAdapter extends FragmentStateAdapter { + private final SparseArray fragmentList; + + public VerticalViewPagerAdapter(FragmentActivity fm) { + super(fm); + fragmentList = new SparseArray<>(); + } + + + @NonNull + @Override + public Fragment createFragment(int position) { + Fragment fragment = fragmentList.get(position); + if (fragment == null) { + if (position == 0) { + fragment = new FakeSingleRoomBackFragment(); + } else if (position == 1) { + fragment = HomePartyFragment.newInstance(); + } else { + fragment = new FakeSingleRoomFragment(); + } + fragmentList.put(position, fragment); + } + return fragment; + } + + @Override + public int getItemCount() { + return 3; + } + + public Fragment getItem(int position) { + return fragmentList.get(position); + } +} diff --git a/app/src/main/java/com/chwl/app/avroom/widget/ViewItem.java b/app/src/main/java/com/chwl/app/avroom/widget/ViewItem.java new file mode 100644 index 0000000..f48eced --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/widget/ViewItem.java @@ -0,0 +1,119 @@ +package com.chwl.app.avroom.widget; + +import com.chwl.app.R; + +/** + * 从library拿到client + * Created by lvzebiao on 2018/11/9. + */ + +public class ViewItem { + public static final int BUTTON_TYPE_NORMAL = 0; + public static final int BUTTON_TYPE_CANCEL = 1; + /**放置在资料卡片的底部位置的button*/ + public static final int BUTTON_TYPE_USER_CAR_BOTTOM = 2; + + + /** 发送礼物 */ + public static final int SEND_GIFT_ITEM = 0; + /** 锁坑 */ + public static final int SEND_LOCK_MIC_ITEM = 1; + /** 踢下麦 */ + public static final int SEND_KICKDOWN_MIC_ITEM = 2; + /** 踢出房间 */ + public static final int SEND_KICKOUT_ROOM_ITEM = 3; + /** 查看个人信息 */ + public static final int SEND_SHOW_USER_INCO_ITEM = 4; + /** 下麦 */ + public static final int SEND_DOWN_MIC_ITEM = 5; + /** 释放麦 */ + public static final int SEND_FREE_MIC_ITEM = 6; + /** 设置管理员 */ + public static final int SEND_MARK_MANAGER_ITEM = 7; + /** 取消管理员 */ + public static final int SEND_NOMARK_MANAGER_ITEM = 11; + /** 加入黑名单 */ + public static final int SEND_MARK_BLACK_ITEM = 8; + /** 开麦 */ + public static final int SEND_OPEN_MUTE_ITEM = 9; + /** + * 装扮 + */ + public static final int SEND_DECORATION_ITEM = 10; + /** 抱上麦 */ + public static final int SEND_INVITE_MIC_ITEM = 12; + /** 发起竞拍 */ + public static final int START_AUCTION = 13; + /**关注or取消*/ + public static final int ATTENT_ITEM = 15; + /**房间外送礼物*/ + public final static int SEND_GIFT_OUT_ROOM = 16; + /**房间内送礼物*/ + public final static int SEND_MAGIC_OUT_ROOM = 17; + + /**是否是关注按钮*/ + public boolean isAttent = false; + /**ture则的话,则显示在个人资料卡片底部*/ + public boolean isBottom = false; + /** + * 找到Ta + */ + public boolean isFindTa = false; + + /** + * @Ta + */ + public boolean isAt = false; + + public String mText; + public int resourceID; + public int imgRes; + public OnClickListener mClickListener; + public int mButtonType; + public int mTheme = -1; + public boolean noDissmis; + public ViewItem(String text, int imgRes, OnClickListener l) { + this(text, imgRes,BUTTON_TYPE_NORMAL, l); + } + public ViewItem(String text, int imgRes, boolean noDissmis, OnClickListener l) { + this(text, imgRes,BUTTON_TYPE_NORMAL, l); + this.noDissmis = noDissmis; + } + public ViewItem(String text, int imgRes, int buttonType, OnClickListener l) { + mText = text; + mClickListener = l; + mButtonType = buttonType; + this.imgRes = imgRes; + resourceID = R.layout.dialog_user_card_item; + } + + public ViewItem(String text, int imgRes, int buttonType, int theme, OnClickListener l) { + mText = text; + this.imgRes = imgRes; + mClickListener = l; + mButtonType = buttonType; + resourceID = R.layout.dialog_user_card_item; + mTheme = theme; + } + + /**用户卡片的底部item*/ + public ViewItem(String text, OnClickListener l) { + mText = text; + mClickListener = l; + mButtonType = BUTTON_TYPE_USER_CAR_BOTTOM; + resourceID = R.layout.item_room_user_dialog_bottom_button; + } + + public void setText(String text) { + this.mText = text; + } + + public void setClickListener(OnClickListener mClickListener) { + this.mClickListener = mClickListener; + } + + public interface OnClickListener { + void onClick(); + } + +} diff --git a/app/src/main/java/com/chwl/app/avroom/widget/VipProgressBar.kt b/app/src/main/java/com/chwl/app/avroom/widget/VipProgressBar.kt new file mode 100644 index 0000000..66b3f1a --- /dev/null +++ b/app/src/main/java/com/chwl/app/avroom/widget/VipProgressBar.kt @@ -0,0 +1,48 @@ +package com.chwl.app.avroom.widget + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Canvas +import android.util.AttributeSet +import android.widget.ProgressBar +import com.netease.nim.uikit.common.util.sys.ScreenUtil +import com.chwl.app.R +import com.example.lib_utils.UiUtils + +class VipProgressBar(context: Context, attrs: AttributeSet?) : ProgressBar(context, attrs) { + + private var thumbBitmap: Bitmap = + BitmapFactory.decodeResource(context.resources, R.drawable.ic_vip_thumb) + private var thumbWidth: Float = thumbBitmap.width.toFloat() + private var thumbHeight: Float = thumbBitmap.height.toFloat() + private var mWidth = 0 + private var mHeight = 0 + private val leftPadding = ScreenUtil.dip2px(9f) + + private var isRTL = false + init { + isRTL = UiUtils.isRtl(context) + } + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + mWidth = w + mHeight = h + } + + @Synchronized + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + var radio = progress * 1.0f / max + if (isRTL) { + radio = 1 - radio + } + canvas.drawBitmap( + thumbBitmap, + (mWidth - leftPadding * 2) * radio - thumbWidth / 2f + leftPadding, + (mHeight - thumbHeight) / 2f, + null + ) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/base/AbstractMvpActivity.java b/app/src/main/java/com/chwl/app/base/AbstractMvpActivity.java new file mode 100644 index 0000000..ef88b16 --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/AbstractMvpActivity.java @@ -0,0 +1,111 @@ +package com.chwl.app.base; + +import android.os.Bundle; +import android.util.Log; + +import androidx.annotation.Nullable; + +import com.chwl.library.base.IMvpBaseView; +import com.chwl.library.base.factory.AbstractMvpPresenter; +import com.chwl.library.base.factory.BaseMvpProxy; +import com.chwl.library.base.factory.PresenterMvpFactory; +import com.chwl.library.base.factory.PresenterMvpFactoryImpl; +import com.chwl.library.base.factory.PresenterProxyInterface; + +/** + *

1. 子类的Presenter必须继承自AbstractMvpPresenter; + * 2. 子类的View必须继承自IMvpBaseView + *

+ * + * @author jiahui + * @date 2017/12/7 + */ +public abstract class AbstractMvpActivity> extends BaseActivity + implements PresenterProxyInterface { + public static final boolean DEBUG = false; + protected boolean afterOnSavedInstanceState = false; + private static final String TAG_LOG = "Super-mvp"; + private static final String KEY_SAVE_PRESENTER = "key_save_presenter"; + + /** 创建代理对象,传入默认的Presenter工厂 */ + private BaseMvpProxy mMvpProxy = new BaseMvpProxy<>(PresenterMvpFactoryImpl.createFactory(getClass())); + private final String activityName = getClass().getName(); + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + logInfo(activityName + " V onCreate..."); + logInfo(activityName + " V onCreate... mProxy=" + mMvpProxy); + logInfo(activityName + " V onCreate... this=" + this.hashCode()); + if (savedInstanceState != null) { + mMvpProxy.onRestoreInstanceState(savedInstanceState.getBundle(KEY_SAVE_PRESENTER)); + } + } + + @Override + protected void onStart() { + super.onStart(); + logInfo(activityName + " V onStart..."); + mMvpProxy.onStart(); + } + + @Override + protected void onResume() { + super.onResume(); + logInfo(activityName + " V onResume..."); + mMvpProxy.onResume((V) this); + afterOnSavedInstanceState = false; + } + + @Override + protected void onPause() { + mMvpProxy.onPause(); + super.onPause(); + logInfo(activityName + " V onPause..."); + } + + @Override + protected void onStop() { + mMvpProxy.onStop(); + super.onStop(); + logInfo(activityName + " V onStop..."); + } + + @Override + protected void onDestroy() { + mMvpProxy.onDestroy(); + super.onDestroy(); + logInfo(activityName + " V onDestroy..."); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + logInfo(activityName + " V onSaveInstanceState..."); + outState.putBundle(KEY_SAVE_PRESENTER, mMvpProxy.onSaveInstanceState()); + afterOnSavedInstanceState = true; + } + + @Override + public void setPresenterFactory(PresenterMvpFactory presenterFactory) { + logInfo(activityName + " V setPresenterFactory..."); + mMvpProxy.setPresenterFactory(presenterFactory); + } + + @Override + public PresenterMvpFactory getPresenterFactory() { + logInfo(activityName + " V getPresenterFactory..."); + return mMvpProxy.getPresenterFactory(); + } + + @Override + public P getMvpPresenter() { + logInfo(activityName + " V getMvpPresenter..."); + return mMvpProxy.getMvpPresenter(); + } + + private void logInfo(String msg) { + if (false) + Log.e(TAG_LOG, msg); + } +} diff --git a/app/src/main/java/com/chwl/app/base/AbstractMvpFragment.java b/app/src/main/java/com/chwl/app/base/AbstractMvpFragment.java new file mode 100644 index 0000000..5f9a94f --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/AbstractMvpFragment.java @@ -0,0 +1,107 @@ +package com.chwl.app.base; + +import android.os.Bundle; +import android.util.Log; + +import androidx.annotation.Nullable; + +import com.chwl.library.base.IMvpBaseView; +import com.chwl.library.base.factory.AbstractMvpPresenter; +import com.chwl.library.base.factory.BaseMvpProxy; +import com.chwl.library.base.factory.PresenterMvpFactory; +import com.chwl.library.base.factory.PresenterMvpFactoryImpl; +import com.chwl.library.base.factory.PresenterProxyInterface; + +/** + *

1. 子类的Presenter必须继承自AbstractMvpPresenter; + * 2. 子类的View必须继承自IMvpBaseView + *

+ * + * @author jiahui + * @date 2017/12/8 + */ +public abstract class AbstractMvpFragment> extends BaseFragment + implements PresenterProxyInterface { + protected final String TAG = getClass().getSimpleName(); + private static final String TAG_LOG = "Super-mvp"; + private static final String KEY_SAVE_PRESENTER = "key_save_presenter"; + /** 创建代理对象,传入默认的Presenter工厂 */ + private BaseMvpProxy mMvpProxy = new BaseMvpProxy<>(PresenterMvpFactoryImpl.createFactory(getClass())); + private String mFragmentName = getClass().getName(); + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + logInfo(mFragmentName + " V onCreate..."); + logInfo(mFragmentName + " V onCreate... mProxy=" + mMvpProxy); + logInfo(mFragmentName + " V onCreate... this=" + this.hashCode()); + if (savedInstanceState != null) { + mMvpProxy.onRestoreInstanceState(savedInstanceState.getBundle(KEY_SAVE_PRESENTER)); + } + } + + @Override + public void onStart() { + super.onStart(); + logInfo(mFragmentName + " V onStart..."); + mMvpProxy.onStart(); + } + + @Override + public void onResume() { + super.onResume(); + logInfo(mFragmentName + " V onResume..."); + mMvpProxy.onResume((V) this); + } + + @Override + public void onPause() { + mMvpProxy.onPause(); + super.onPause(); + logInfo(mFragmentName + " V onPause..."); + } + + @Override + public void onStop() { + mMvpProxy.onStop(); + super.onStop(); + logInfo(mFragmentName + " V onStop..."); + } + + @Override + public void onDestroy() { + mMvpProxy.onDestroy(); + super.onDestroy(); + logInfo(mFragmentName + " V onDestroy..."); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + logInfo(mFragmentName + " V onSaveInstanceState..."); + outState.putBundle(KEY_SAVE_PRESENTER, mMvpProxy.onSaveInstanceState()); + } + + @Override + public void setPresenterFactory(PresenterMvpFactory presenterFactory) { + logInfo(mFragmentName + " V setPresenterFactory..."); + mMvpProxy.setPresenterFactory(presenterFactory); + } + + @Override + public PresenterMvpFactory getPresenterFactory() { + logInfo(mFragmentName + " V getPresenterFactory..."); + return mMvpProxy.getPresenterFactory(); + } + + @Override + public P getMvpPresenter() { + logInfo(mFragmentName + " V getMvpPresenter..."); + return mMvpProxy.getMvpPresenter(); + } + + private void logInfo(String msg) { + if (false) + Log.e(TAG_LOG, msg); + } +} diff --git a/app/src/main/java/com/chwl/app/base/BaseActivity.java b/app/src/main/java/com/chwl/app/base/BaseActivity.java new file mode 100644 index 0000000..df99fbd --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/BaseActivity.java @@ -0,0 +1,1497 @@ +package com.chwl.app.base; + +import static com.chwl.core.Constants.DEBUG_MAX_UID; +import static com.chwl.core.im.custom.bean.CustomAttachment.BOOM_FIRST; +import static com.chwl.core.im.custom.bean.CustomAttachment.BOOM_SECOND_DIALOG; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MESS_HEAD_NOBLE; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MESS_SUB_OPENNOBLE; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MESS_SUB_RENEWNOBLE; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_FAIRY; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_LUCKY_SEA; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_LUCKY_SEA_GIFT_SERVER_ALL; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_NOTIFY_H5_SUB_WHOLE_SERVICE; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_DRAW_GIFT_L5; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_VIP; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_VIP_USER_ALL_UPGRADE; +import static com.chwl.library.utils.UIUtils.getActivityByContext; + +import android.annotation.SuppressLint; +import android.app.ActivityManager; +import android.app.Dialog; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.res.Configuration; +import android.graphics.Color; +import android.graphics.Typeface; +import android.os.Build; +import android.os.Bundle; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.TextUtils; +import android.text.style.StyleSpan; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.view.inputmethod.InputMethodManager; +import android.widget.Toast; + +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.chwl.app.NimMiddleActivity; +import com.chwl.app.R; +import com.chwl.app.application.App; +import com.chwl.app.application.IReportConstants; +import com.chwl.app.application.ReportManager; +import com.chwl.app.avroom.activity.AVRoomActivity; +import com.chwl.app.common.LoadingFragment; +import com.chwl.app.common.NetworkErrorFragment; +import com.chwl.app.common.NoDataFragment; +import com.chwl.app.common.ReloadFragment; +import com.chwl.app.common.permission.PermissionActivity; +import com.chwl.app.common.widget.StatusLayout; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.app.common.widget.dialog.DialogUiHelper; +import com.chwl.app.notify.GlobalNotifyManager; +import com.chwl.app.ui.im.avtivity.NimP2PMessageActivity; +import com.chwl.app.ui.login.AddUserInfoActivity; +import com.chwl.app.ui.login.LoginCodeActivity; +import com.chwl.app.ui.login.LoginPhoneActivity; +import com.chwl.app.ui.pay.ChargeActivity; +import com.chwl.app.ui.setting.ResetPasswordActivity; +import com.chwl.app.ui.widget.DefaultToolBar; +import com.chwl.app.ui.widget.dialog.AllPlayEffectDialog; +import com.chwl.app.ui.widget.dialog.AllServiceGiftLevelDialog; +import com.chwl.app.ui.widget.dialog.AllServiceVipLevelUPDialog; +import com.chwl.app.ui.widget.dialog.OpenNobleGlobalNoticeDialog; +import com.chwl.app.utils.RoomBoomManager; +import com.chwl.app.utils.UserUtils; +import com.chwl.core.XConstants; +import com.chwl.core.bean.BaseProtocol; +import com.chwl.core.gift.bean.BoomMsgDialogBean; +import com.chwl.core.im.custom.bean.BoomMsgAttachment; +import com.chwl.core.im.custom.bean.CustomAttachment; +import com.chwl.core.im.custom.bean.NotifyH5Info; +import com.chwl.core.im.custom.bean.PlayEffectInfo; +import com.chwl.core.im.custom.bean.RoomLuckySeaMsgBean; +import com.chwl.core.im.custom.bean.TarotMsgBean; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.manager.IMNetEaseManager; +import com.chwl.core.manager.RoomEvent; +import com.chwl.core.mentoring_relationship.event.GrabApprenticesEvent; +import com.chwl.core.newbie.bean.NewbieHelloInfo; +import com.chwl.core.newbie.event.NewbieHelloDialogEvent; +import com.chwl.core.noble.bean.AllServiceGiftProtocol; +import com.chwl.core.noble.bean.NobleInfo; +import com.chwl.core.noble.bean.NobleProtocol; +import com.chwl.core.pay.PayModel; +import com.chwl.core.pay.bean.WalletInfo; +import com.chwl.core.room.model.AvRoomModel; +import com.chwl.core.treasurefairy.bean.FairyMsgInfoBean; +import com.chwl.core.user.UserModel; +import com.chwl.core.utils.LogUtils; +import com.chwl.core.utils.net.RxHelper; +import com.chwl.core.vip.bean.VipMessageInfo; +import com.chwl.library.language.LanguageHelper; +import com.chwl.library.rxbus.RxBus; +import com.chwl.library.utils.NetworkUtils; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; +import com.chwl.library.utils.UIUtils; +import com.chwl.library.utils.codec.DESUtils; +import com.chwl.library.utils.config.BasicConfig; +import com.chwl.library.utils.log.MLog; +import com.example.lib_utils.UiUtils; +import com.google.gson.Gson; +import com.netease.nim.uikit.StatusBarUtil; +import com.netease.nim.uikit.common.util.log.LogUtil; +import com.netease.nimlib.chatroom.model.ChatRoomMessageImpl; +import com.netease.nimlib.sdk.NIMSDK; +import com.netease.nimlib.sdk.Observer; +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage; +import com.netease.nimlib.sdk.msg.constant.MsgTypeEnum; +import com.netease.nimlib.sdk.msg.model.BroadcastMessage; +import com.netease.nimlib.session.IMMessageImpl; +import com.orhanobut.logger.Logger; +import com.readystatesoftware.systembartint.SystemBarTintManager; +import com.tbruyelle.rxpermissions2.RxPermissions; +import com.trello.rxlifecycle3.android.ActivityEvent; +import com.trello.rxlifecycle3.components.support.RxAppCompatActivity; + +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.lang.ref.WeakReference; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; + +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.CompositeDisposable; + + +/** + * @author alvin hwang + */ +public abstract class BaseActivity extends RxAppCompatActivity + implements IDataStatus, DialogManagerInterface { + + /** + * -------------------------------------------------- + * -------------------------数据状态状态相关------------- + * -------------------------------------------------- + */ + + protected static final String STATUS_TAG = "STATUS_TAG"; + private final RxPermissions rxPermissions = new RxPermissions(this); + protected TitleBar mTitleBar; + protected DefaultToolBar mToolBar; + protected CompositeDisposable mCompositeDisposable; + protected Context context; + private DialogManager mDialogManager; + private BroadcastObserver broadcastObserver; + private OpenNobleGlobalNoticeDialog mNoticeDialog; + private boolean isShowingChargeDialog; + + private Dialog giftDialog; + private LinkedList giftList; + + private Dialog playEffectDialog; + private LinkedList playEffectList; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + context = this; + mCompositeDisposable = new CompositeDisposable(); + if (needSteepStateBar()) { + setStatusBar(); + } + mCompositeDisposable.add(IMNetEaseManager.get().getChatRoomEventObservable() + .subscribe(roomEvent -> { + if (roomEvent == null) return; + onReceiveChatRoomEvent(roomEvent); + })); + GlobalNotifyManager.INSTANCE.bindActivity(this); + } + + protected void onReceiveChatRoomEvent(RoomEvent roomEvent) { + } + + /** + * 注册云信全服广播接收器 + * + * @param register true为注册,false为注销 + */ + protected void registerNimBroadcastMessage(boolean register) { + if (broadcastObserver == null) { + broadcastObserver = new BroadcastObserver(this); + } + NIMSDK.getMsgServiceObserve().observeBroadcastMessage(broadcastObserver, register); + } + + /** + * 当前Activity 是否有效 + */ + protected boolean isValid() { + return !isFinishing() && !isDestroyed(); + } + + public void initToolBar(int resId) { + initToolBar(getString(resId)); + } + + public void initToolBar(CharSequence title) { + mToolBar = findViewById(R.id.toolbar); + if (mToolBar != null) { + mToolBar.setCenterTitle(title); + mToolBar.setNavigationIcon(R.drawable.arrow_left); + mToolBar.setNavigationOnClickListener(v -> onLeftClickListener()); + } + } + + public void initTitleBar() { + mTitleBar = findViewById(R.id.title_bar); + if (mTitleBar != null) { + if (needSteepStateBar()) { + mTitleBar.setImmersive(false); + } + mTitleBar.setBackgroundColor(getResources().getColor(R.color.white)); + mTitleBar.setTitleColor(getResources().getColor(R.color.text_primary)); + } + } + + public void initTitleBar(int title) { + initTitleBar(getResources().getString(title)); + } + + public void initTitleBar(String title) { + mTitleBar = findViewById(R.id.title_bar); + if (mTitleBar != null) { + mTitleBar.setTitle(title); + mTitleBar.setImmersive(false); + mTitleBar.setTitleColor(getResources().getColor(R.color.back_font)); + mTitleBar.setLeftImageResource(R.drawable.arrow_left); + mTitleBar.setBackgroundResource(R.color.transparent); + mTitleBar.setLeftClickListener(v -> onLeftClickListener()); + } + } + + public void initVipCenterBar(String title) { + mTitleBar = findViewById(R.id.title_bar); + if (mTitleBar != null) { + mTitleBar.setTitle(title); + mTitleBar.setImmersive(true); + mTitleBar.setTitleColor(getResources().getColor(R.color.color_FFE3AF)); + mTitleBar.setLeftImageResource(R.drawable.vip_center_back_button); + mTitleBar.setBackgroundResource(R.color.transparent); + mTitleBar.setLeftClickListener(v -> onLeftClickListener()); + if(UiUtils.INSTANCE.isRtl(context)){ + mTitleBar.leftTextViewUpdateScaleXForRTL(); + } + } + } + + public void initWhiteTitleBar(String title) { + mTitleBar = findViewById(R.id.title_bar); + if (mTitleBar != null) { + mTitleBar.setTitle(title); + mTitleBar.setImmersive(false); + mTitleBar.setTitleColor(getResources().getColor(R.color.text_title_color)); + mTitleBar.setLeftImageResource(R.drawable.arrow_left); + mTitleBar.setBackgroundResource(R.color.transparent); + mTitleBar.setLeftClickListener(v -> onLeftClickListener()); + } + } + + /** + * 透明状态栏, 白色字 + */ + public void initDarkTitleBar(String title) { + mTitleBar = findViewById(R.id.title_bar); + if (mTitleBar != null) { + mTitleBar.setTitle(title); + mTitleBar.setImmersive(false); + mTitleBar.setTitleColor(getResources().getColor(R.color.white)); + mTitleBar.setLeftImageResource(R.drawable.icon_user_back); + mTitleBar.setBackgroundResource(R.color.transparent); + mTitleBar.setLeftClickListener(v -> onLeftClickListener()); + StatusBarUtil.StatusBarLightMode(this,false); + StatusBarUtil.transparencyBar(this); + } + } + + /** + * 透明状态栏, 黑色字 + */ + public void initLightTitleBar(String title) { + mTitleBar = findViewById(R.id.title_bar); + if (mTitleBar != null) { + mTitleBar.setTitle(title); + mTitleBar.setImmersive(false); + mTitleBar.setTitleColor(getResources().getColor(R.color.text_title_color)); + mTitleBar.setLeftImageResource(R.drawable.arrow_left); + mTitleBar.setBackgroundResource(R.color.transparent); + mTitleBar.setLeftClickListener(v -> onLeftClickListener()); +// StatusBarUtil.StatusBarLightMode(this,true); +// StatusBarUtil.transparencyBar(this); + StatusBarUtil.transparencyBar(this); + StatusBarUtil.StatusBarLightMode(this); + } + } + + public void initTitleBar(String title, TitleBar.Action action) { + mTitleBar = findViewById(R.id.title_bar); + if (mTitleBar != null) { + mTitleBar.setTitle(title); + mTitleBar.setImmersive(false); + mTitleBar.setTitleColor(getResources().getColor(R.color.back_font)); + mTitleBar.setLeftImageResource(R.drawable.arrow_left); + mTitleBar.setLeftClickListener(v -> onLeftClickListener()); + // action + if (action != null) { + mTitleBar.addAction(action); + } + } + } + + protected void onLeftClickListener() { + finish(); + } + + protected boolean needSteepStateBar() { + return false; + } + + /** + * 设置沉浸式状态栏 + */ + protected void setStatusBar() { + //透明状态栏 + getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + //透明导航栏 +// getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); + // create our manager instance after the content view is set + SystemBarTintManager tintManager = new SystemBarTintManager(this); + // enable status bar tint + tintManager.setStatusBarTintEnabled(true); + // enable navigation bar tint + tintManager.setNavigationBarTintEnabled(true); + tintManager.setTintColor(Color.parseColor("#00000000")); + } + + /** + * 通知栏白底黑字 + * + * @param isDark true:黑色 + */ + public void StatusBarLightModes(boolean isDark) { + getWindow().setStatusBarColor(getResources().getColor(R.color.white)); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (isDark) { + getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); + } else { + getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + } + } + } + + /** + * 获取状态栏的高度 + * + * @return + */ + protected int getStatusBarHeight() { + try { + Class c = Class.forName("com.android.internal.R$dimen"); + Object obj = c.newInstance(); + Field field = c.getField("status_bar_height"); + int x = Integer.parseInt(field.get(obj).toString()); + return getResources().getDimensionPixelSize(x); + } catch (Exception e) { + e.printStackTrace(); + } + return 0; + } + + @Override + public void setContentView(int layoutResID) { + super.setContentView(layoutResID); + initTitleBar(); + } + + /** + * 是否需要渲染成主题色的status bar + * + * @return + */ + protected boolean shouldConfigStatusBar() { + return true; + } + + @Override + protected void onStart() { + super.onStart(); + registerNimBroadcastMessage(true); + } + + @Override + protected void onStop() { + super.onStop(); + registerNimBroadcastMessage(false); + } + + @Override + protected void onDestroy() { + if (mCompositeDisposable != null) { + mCompositeDisposable.dispose(); + mCompositeDisposable = null; + } + + try { + if (mNoticeDialog != null && mNoticeDialog.isShowing()) { + mNoticeDialog.dismiss(); + mNoticeDialog = null; + } + if (giftDialog != null && giftDialog.isShowing()) { + giftDialog.setOnDismissListener(null); + giftDialog.dismiss(); + giftDialog = null; + } + if (playEffectDialog != null && playEffectDialog.isShowing()) { + playEffectDialog.setOnDismissListener(null); + playEffectDialog.dismiss(); + playEffectDialog = null; + } + if (giftList != null) { + giftList.clear(); + } + if(playEffectList != null){ + playEffectList.clear(); + } + + if (mDialogManager != null) { + mDialogManager.dismissDialog(); + mDialogManager = null; + } + } catch (Exception e){ + Logger.i("关闭弹窗失败" + e.getMessage()); + } + + super.onDestroy(); + LogUtil.i(this.getClass().getName(), "onDestroy"); + + /* ImageLoadUtils.clearMemory(this);*/ + + } + + @Override + public DialogManager getDialogManager() { + if (mDialogManager == null) { + mDialogManager = new DialogManager(this); + mDialogManager.setCanceledOnClickOutside(false); + } + return mDialogManager; + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + Fragment fragment = getTopFragment(); + if (fragment instanceof BaseFragment) { + if (((BaseFragment) fragment).onKeyDown(keyCode, event)) { + return true; + } + } + + return super.onKeyDown(keyCode, event); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + Fragment fragment = getTopFragment(); + if (fragment instanceof BaseFragment) { + fragment.onActivityResult(requestCode, resultCode, data); + } + super.onActivityResult(requestCode, resultCode, data); + } + + public Fragment getTopFragment() { + FragmentManager fragmentManager = getSupportFragmentManager(); + List fragments = fragmentManager.getFragments(); + for (Fragment fragment : fragments) { + if (fragment != null && fragment.isVisible()) { + return fragment; + } + } + return null; + } + + @Override + public void onBackPressed() { + hideIME(); + try { + super.onBackPressed(); + } catch (Exception ex) { + MLog.error(this, ex); + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + + if (item.getItemId() == android.R.id.home) { + Fragment fragment = getTopFragment(); + if (fragment != null && fragment instanceof BaseFragment) { + if (fragment.onOptionsItemSelected(item)) { + return true; + } + } + onBackPressed(); + return true; + } + + return super.onOptionsItemSelected(item); + } + + @Override + public boolean onMenuOpened(int featureId, Menu menu) { + if (featureId == Window.FEATURE_ACTION_BAR && menu != null) { + if (menu.getClass().getSimpleName().equals("MenuBuilder")) { + try { + Method m = menu.getClass().getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE); + m.setAccessible(true); + m.invoke(menu, true); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + return super.onMenuOpened(featureId, menu); + } + + /** + * 获取backstack top + * + * @return + */ + private Fragment getLastFragment() { + List fragments = getSupportFragmentManager().getFragments(); + if (fragments.size() > 0) { + for (int i = fragments.size() - 1; i >= 0; i--) { + Fragment f = fragments.get(i); + if (f instanceof BaseFragment) { + return f; + } + } + } + + return null; + } + + /** + * @param fragmentName Fragment.class.getName() + */ + public void popFragment(String fragmentName) { + getSupportFragmentManager().popBackStack(fragmentName, FragmentManager.POP_BACK_STACK_INCLUSIVE); + } + + public String getTopFragmentName() { + FragmentManager fragmentManager = getSupportFragmentManager(); + if (fragmentManager.getBackStackEntryCount() > 0) { + return fragmentManager.getBackStackEntryAt(fragmentManager.getBackStackEntryCount() - 1).getName(); + } + return null; + } + + protected void updateBottomBar(boolean isShow) { + + } + + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(LanguageHelper.INSTANCE.wrapContext(newBase)); + LanguageHelper.INSTANCE.wrapContext(newBase.getApplicationContext()); + } + + @Override + public void onConfigurationChanged(@NonNull Configuration newConfig) { + super.onConfigurationChanged(newConfig); + LanguageHelper.INSTANCE.changeLanguage(this, LanguageHelper.INSTANCE.getCurrentLanguage()); + } + + @SuppressLint("CheckResult") + @Override + protected void onResume() { + super.onResume(); + //GlideApp.with(this).resumeRequests(); + RxBus.get().toFlowable(String.class) + .compose(bindUntilEvent(ActivityEvent.PAUSE)) + .subscribe((s) -> { + if (XConstants.SHOW.equals(s)) { + getDialogManager().showProgressDialog(this, ResUtil.getString(R.string.erban_base_baseactivity_01), true); + } else if (XConstants.HIDE.equals(s)) { + getDialogManager().dismissDialog(); + } + }, throwable -> { + }); + + IMNetEaseManager.get().getChatRoomEventObservable() + .compose(bindUntilEvent(ActivityEvent.PAUSE)) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(this::onRoomEventReceived); + + if (giftList != null) { + giftList.clear(); + } + if(playEffectList != null){ + playEffectList.clear(); + } + } + + @Override + protected void onPause() { + super.onPause(); + } + + protected boolean checkActivityValid() { + return UIUtils.checkActivityValid(this); + } + + @Override + public View.OnClickListener getLoadListener() { + return new View.OnClickListener() { + @Override + public void onClick(View v) { + onReloadDate(); + } + }; + } + + /** + * 网络错误重新加载数据 + */ + public void onReloadDate() { + + } + + @Override + public View.OnClickListener getLoadMoreListener() { + return null; + } + + @Override + public View.OnClickListener getNoMobileLiveDataListener() { + return null; + } + + @Override + public void showLoading() { + showLoading(0, 0); + } + + @Override + public void showLoading(View view) { + showLoading(view, 0, 0); + } + + public void showReload(@ColorInt int bgColor) { + showReload(0, bgColor); + } + + @Override + public void showReload() { + showReload(0, 0); + } + + @Override + public void showNoData() { + showNoData(0, ""); + } + + @Override + public void showNoLogin() { + + } + + @SuppressLint("ResourceType") + @Override + public void showLoading(int drawable, int tips) { + if (!checkActivityValid()) { + return; + } + + View status = findViewById(R.id.status_layout); + if (status == null || status.getId() <= 0) { + MLog.error(this, "xuwakao, had not set layout id "); + return; + } + Fragment fragment = LoadingFragment.newInstance(drawable, tips); + getSupportFragmentManager().beginTransaction().replace(status.getId(), fragment, STATUS_TAG).commitAllowingStateLoss(); + } + + @Override + public void showLoading(View view, int drawable, int tips) { + + } + + @SuppressLint("ResourceType") + @Override + public void showReload(int drawable, int tips) { + if (!checkActivityValid()) { + return; + } + + View status = findViewById(R.id.status_layout); + if (status == null || status.getId() <= 0) { + MLog.error(this, "xuwakao, had not set layout id "); + return; + } + ReloadFragment fragment = ReloadFragment.newInstance(drawable, tips); + fragment.setListener(getLoadListener()); + getSupportFragmentManager().beginTransaction().replace(status.getId(), fragment, STATUS_TAG).commitAllowingStateLoss(); + } + + @Override + public void showReload(View view, int drawable, int tips) { + + } + + @Override + public void showNoData(CharSequence charSequence) { + showNoData(0, charSequence); + } + + @SuppressLint("ResourceType") + @Override + public void showNoData(int drawable, CharSequence charSequence) { + if (!checkActivityValid()) { + return; + } + + View status = findViewById(R.id.status_layout); + if (status == null || status.getId() <= 0) { + MLog.error(this, "xuwakao, had not set layout id "); + return; + } + NoDataFragment fragment = NoDataFragment.newInstance(drawable, charSequence); + fragment.setListener(getLoadListener()); + getSupportFragmentManager().beginTransaction().replace(status.getId(), fragment, STATUS_TAG).commitAllowingStateLoss(); + } + + @Override + public void showNoData(View view, int drawable, CharSequence charSequence) { + + } + + @SuppressLint("ResourceType") + @Override + public void showNetworkErr() { + if (!checkActivityValid()) { + return; + } + + View status = findViewById(R.id.status_layout); + if (status == null || status.getId() <= 0) { + MLog.error(this, "xuwakao, had not set layout id "); + return; + } + NetworkErrorFragment fragment = new NetworkErrorFragment(); + fragment.setListener(getLoadListener()); + getSupportFragmentManager().beginTransaction().replace(status.getId(), fragment, STATUS_TAG).commitAllowingStateLoss(); + } + + @Override + public void hideStatus() { + Fragment fragment = getSupportFragmentManager().findFragmentByTag(STATUS_TAG); + if (fragment != null) { + getSupportFragmentManager().beginTransaction().remove(fragment).commitAllowingStateLoss(); + } + } + + @Override + public void showPageError(int tips) { + if (!checkActivityValid()) { + return; + } + + View more = findViewById(R.id.loading_more); + if (more == null) { + MLog.error(this, "xuwakao, showReload more is NULL"); + return; + } + StatusLayout statusLayout = (StatusLayout) more.getParent(); + statusLayout.showErrorPage(tips, getLoadMoreListener()); + } + + @Override + public void showPageError(View view, int tips) { + + } + + @Override + public void showPageLoading() { + if (!checkActivityValid()) { + return; + } + + View more = findViewById(R.id.loading_more); + if (more == null) { + MLog.error(this, "xuwakao, showReload more is NULL"); + return; + } + StatusLayout statusLayout = (StatusLayout) more.getParent(); + statusLayout.showLoadMore(); + } + + /** + * 当前网络是否可用 + * + * @return + */ + public boolean isNetworkAvailable() { + return NetworkUtils.isNetworkStrictlyAvailable(this); + } + + public boolean checkNetToast() { + boolean flag = isNetworkAvailable(); + if (!flag) { + SingleToastUtil.showToast(BasicConfig.INSTANCE.getAppContext(), R.string.str_network_not_capable); + } + return flag; + } + + /** + * -------------------------------------------------- + * -------------------------UI基本功能------------------ + * -------------------------------------------------- + */ + public void hideIME() { + View v = getCurrentFocus(); + if (null != v) + hideIME(v); + } + + public void hideIME(View v) { + InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(v.getWindowToken(), 0); + } + + public void showIME(final View vv) { + View v = vv; + if (null == v) { + v = getCurrentFocus(); + if (null == v) + return; + } + ((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE)) + .showSoftInput(v, InputMethodManager.SHOW_FORCED); + } + + /** + * 当前无Fragment 或 无Fragment添加 视为顶部激活状态 + * + * @return + */ + public boolean isTopActive() { + + if (isTopActivity()) { + FragmentManager fragmentManager = getSupportFragmentManager(); + + List fragments = fragmentManager.getFragments(); + if (fragments == null || fragments.size() == 0) { + return true; + } else { + int size = fragments.size(); + for (int i = 0; i < size; i++) { + //TODO why null? + if (fragments.get(i) != null && fragments.get(i).isAdded()) + return false; + } + return true; + } + } + return false; + } + + public boolean isTopActivity() { + return UIUtils.isTopActivity(this); + } + + /** + * 通用消息提示 + * + * @param resId + */ + public void toast(int resId) { + toast(resId, Toast.LENGTH_SHORT); + } + + public void toast(String toast) { + toast(toast, Toast.LENGTH_SHORT); + } + + /** + * 通用消息提示 + * + * @param resId + * @param length + */ + public void toast(int resId, int length) { + SingleToastUtil.showToast(resId); + } + + public void toast(String toast, int length) { + SingleToastUtil.showToast(toast); + } + + @SuppressLint("CheckResult") + public void checkPermission(PermissionActivity.CheckPermListener listener, int resString, String... mPerms) { + /** + * 权限回调接口 + */ + rxPermissions.request(mPerms) + .subscribe(aBoolean -> { + if (aBoolean && listener != null) { + listener.superPermission(); + } + }, Throwable::printStackTrace); + } + + @SuppressLint("CheckResult") + public Observable checkPermission(String... mPerms) { + return rxPermissions.request(mPerms); + } + + public RxPermissions getRxPermissions() { + return rxPermissions; + } + + /** + * 接收到全局广播信息 + * + * @param body 信息实体 + */ + protected void onReceivedNimBroadcastMessage(String body) { + if (!isNeedToHandleBroadcastMessageActivity()) { + return; + } + BaseProtocol baseProtocol; + try { + baseProtocol = JSON.parseObject(body, BaseProtocol.class); + } catch (Exception e) { + baseProtocol = null; + } + if (baseProtocol == null) return; + + int second = baseProtocol.getSecond(); + switch (baseProtocol.getFirst()) { + case CUSTOM_MESS_HEAD_NOBLE: + if (second == CUSTOM_MESS_SUB_OPENNOBLE || second == CUSTOM_MESS_SUB_RENEWNOBLE) { + NobleProtocol.DataBean data = JSON.parseObject(String.valueOf(baseProtocol.getData()), NobleProtocol.DataBean.class); + NobleInfo nobleInfo; + if (data == null || (nobleInfo = data.getNobleInfo()) == null || (data.getUid() < DEBUG_MAX_UID && !App.isDebug())) + return; + + int type = data.getType(); + String nick = data.getNick(); + String content = null; + String noticeBefore = getString(R.string.global_notice_before); + if (type == 1) { + //恭喜 xxxx 开通“国王”贵族,速来膜拜 + if (TextUtils.isEmpty(data.getRoomTitle())) { + content = noticeBefore + getString(R.string.noble_open_notice, nick, nobleInfo.getName()); + } else { + content = noticeBefore + getString(R.string.noble_open_in_room_notice, nick, nobleInfo.getName(), + String.valueOf(data.getRoomErbanNo()), data.getRoomTitle()); + } + } else if (type == 2) { + //恭喜 xxxx 续费“国王”贵族 + content = noticeBefore + getString(R.string.noble_reopen_notice, nick, nobleInfo.getName()); + } + if (!TextUtils.isEmpty(content)) { + + String nobleName = nobleInfo.getName(); + Spannable spannable = new SpannableString(content); + + spannable.setSpan(new StyleSpan(Typeface.BOLD), 0, noticeBefore.length() - 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + + int start = content.lastIndexOf(nick); + int end = start + nick.length(); + spannable.setSpan(new StyleSpan(Typeface.BOLD), start - 1, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + start = content.lastIndexOf(nobleName); + end = start + nobleName.length(); + spannable.setSpan(new StyleSpan(Typeface.BOLD), start - 1, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + if (!isFinishing()) { + if (mNoticeDialog != null && mNoticeDialog.isShowing()) + mNoticeDialog.dismiss(); + mNoticeDialog = new OpenNobleGlobalNoticeDialog(this, spannable); + mNoticeDialog.show(); + } + } + } + break; + case CUSTOM_MSG_VIP: + if (baseProtocol.getSecond() == CUSTOM_MSG_VIP_USER_ALL_UPGRADE) { + VipMessageInfo vipMessageInfo = new Gson().fromJson(String.valueOf(baseProtocol.getData()), VipMessageInfo.class); + if (vipMessageInfo != null && !TextUtils.isEmpty(vipMessageInfo.getFloatPic())) { + new AllServiceVipLevelUPDialog(context, vipMessageInfo).show(); + } + } + break; +// case CUSTOM_MSG_HEADER_TYPE_GIFT: +// if (!isValid() || getWindow().getDecorView().getVisibility() != View.VISIBLE) return; +// if (this instanceof AddUserInfoActivity || this instanceof AVRoomActivity +//// || this instanceof TreasureBoxActivity || this instanceof HomeFairyActivity +// || UserUtils.getUserInfo() == null) +// return; +// if (giftList == null) { +// giftList = new LinkedList<>(); +// } +// int second2 = baseProtocol.getSecond(); +// AllServiceGiftProtocol.DataBean data = JSON.parseObject(String.valueOf(baseProtocol.getData()), AllServiceGiftProtocol.DataBean.class); +// if (data == null || data.getGiftUrl() == null) return; +// giftList.add(data); +// if (second2 == CUSTOM_MSG_ALL_SERVICE_GIFT) { +// if (giftDialog != null && giftDialog.isShowing()) { +// // 如果当前以及有礼物弹窗在展示,则需要等到他 dismiss 后再显示下一个 +// AllServiceGiftProtocol.DataBean dataBean = giftList.peekFirst(); +// if (dataBean != null) { +// return; +// } else { +// giftDialog.dismiss(); +// } +// } else { +// showGiftDialog(); +// } +// } +// break; +// case CUSTOM_MSG_BOX://寻爱之旅 +// if (!isValid() || getWindow().getDecorView().getVisibility() != View.VISIBLE) return; +// if (this instanceof AddUserInfoActivity || this instanceof AVRoomActivity +//// || this instanceof TreasureBoxActivity || this instanceof HomeFairyActivity +// || UserUtils.getUserInfo() == null) +// return; +// if (playEffectList == null) { +// playEffectList = new LinkedList<>(); +// } +// RoomBoxPrizeInfo roomBoxPrizeInfo = JSON.parseObject(String.valueOf(baseProtocol.getData()), RoomBoxPrizeInfo.class); +// if (roomBoxPrizeInfo == null) return; +// if (baseProtocol.getSecond() == CUSTOM_MSG_SUB_BOX_ALL_ROOM_NOTIFY_BY_SVGA) { +// PlayEffectInfo playEffectInfo = new PlayEffectInfo(); +// playEffectInfo.setSecond(CUSTOM_MSG_SUB_BOX_ALL_ROOM_NOTIFY_BY_SVGA); +// playEffectInfo.setRoomBoxPrizeInfo(roomBoxPrizeInfo); +// playEffectList.add(playEffectInfo); +// if (playEffectDialog != null && playEffectDialog.isShowing()) { +// // 如果当前以及有礼物弹窗在展示,则需要等到他 dismiss 后再显示下一个 +// PlayEffectInfo dataBean = playEffectList.peekFirst(); +// if (dataBean != null) { +// return; +// } else { +// playEffectDialog.dismiss(); +// } +// } else { +// showPlayEffectDialog(); +// } +// } +// break; + case CustomAttachment.CUSTOM_MESS_TAROT: + if (!isValid() || getWindow().getDecorView().getVisibility() != View.VISIBLE) return; + if (this instanceof AddUserInfoActivity || this instanceof AVRoomActivity +// || this instanceof TreasureBoxActivity || this instanceof HomeFairyActivity + || UserUtils.getUserInfo() == null) + return; + if (playEffectList == null) { + playEffectList = new LinkedList<>(); + } + if (baseProtocol.getSecond() == CustomAttachment.CUSTOM_MESS_TAROT_SENIOR_PRIZE_WINNING) { + TarotMsgBean tarotMsgBean = JSON.parseObject(String.valueOf(baseProtocol.getData()), TarotMsgBean.class); + PlayEffectInfo playEffectInfo = new PlayEffectInfo(); + playEffectInfo.setSecond(CustomAttachment.CUSTOM_MESS_TAROT_SENIOR_PRIZE_WINNING); + playEffectInfo.setTarotMsgBean(tarotMsgBean); + if (playEffectList == null) { + playEffectList = new LinkedList<>(); + } + playEffectList.add(playEffectInfo); + if (playEffectDialog != null && playEffectDialog.isShowing()) { + // 如果当前以及有礼物弹窗在展示,则需要等到他 dismiss 后再显示下一个 + PlayEffectInfo dataBean = playEffectList.peekFirst(); + if (dataBean != null) { + return; + } else { + playEffectDialog.dismiss(); + } + } else { + showPlayEffectDialog(); + } + } + break; + case CustomAttachment.CUSTOM_MSG_NOTIFY_H5: + if (!isValid() || getWindow().getDecorView().getVisibility() != View.VISIBLE) return; + if (this instanceof AddUserInfoActivity || this instanceof AVRoomActivity +// || this instanceof TreasureBoxActivity || this instanceof HomeFairyActivity + || UserUtils.getUserInfo() == null) + return; + if (baseProtocol.getSecond() == CustomAttachment.CUSTOM_MSG_NOTIFY_H5_SUB_WHOLE_SERVICE) { + NotifyH5Info bean = JSON.parseObject(String.valueOf(baseProtocol.getData()), NotifyH5Info.class); + PlayEffectInfo playEffectInfo = new PlayEffectInfo(); + playEffectInfo.setSecond(CUSTOM_MSG_NOTIFY_H5_SUB_WHOLE_SERVICE); + playEffectInfo.setNotifyH5(bean); + if (playEffectList == null) { + playEffectList = new LinkedList<>(); + } + playEffectList.add(playEffectInfo); + if (playEffectDialog != null && playEffectDialog.isShowing()) { + // 如果当前以及有礼物弹窗在展示,则需要等到他 dismiss 后再显示下一个 + PlayEffectInfo dataBean = playEffectList.peekFirst(); + if (dataBean != null) { + return; + } else { + playEffectDialog.dismiss(); + } + } else { + showPlayEffectDialog(); + } + } + break; + case CUSTOM_MSG_LUCKY_SEA://星级厨房 + if (!isValid() || getWindow().getDecorView().getVisibility() != View.VISIBLE) return; + if (this instanceof AddUserInfoActivity || this instanceof AVRoomActivity +// || this instanceof TreasureBoxActivity || this instanceof HomeFairyActivity + || UserUtils.getUserInfo() == null) + return; + if (playEffectList == null) { + playEffectList = new LinkedList<>(); + } + RoomLuckySeaMsgBean roomLuckySeaMsgBean = JSON.parseObject(String.valueOf(baseProtocol.getData()), RoomLuckySeaMsgBean.class); + if (roomLuckySeaMsgBean == null) return; + if (baseProtocol.getSecond() == CUSTOM_MSG_LUCKY_SEA_GIFT_SERVER_ALL) { + PlayEffectInfo playEffectInfo = new PlayEffectInfo(); + playEffectInfo.setSecond(CUSTOM_MSG_LUCKY_SEA_GIFT_SERVER_ALL); + playEffectInfo.setRoomLuckySeaMsgBean(roomLuckySeaMsgBean); + playEffectList.add(playEffectInfo); + if (playEffectDialog != null && playEffectDialog.isShowing()) { + // 如果当前以及有礼物弹窗在展示,则需要等到他 dismiss 后再显示下一个 + PlayEffectInfo dataBean = playEffectList.peekFirst(); + if (dataBean != null) { + return; + } else { + playEffectDialog.dismiss(); + } + } else { + showPlayEffectDialog(); + } + } + break; +// case CUSTOM_MSG_LUCKY_GIFT://福袋 +// if (!isValid() || getWindow().getDecorView().getVisibility() != View.VISIBLE) return; +// if (this instanceof AddUserInfoActivity || this instanceof AVRoomActivity +//// || this instanceof TreasureBoxActivity || this instanceof HomeFairyActivity +// || UserUtils.getUserInfo() == null) +// return; +// if (playEffectList == null) { +// playEffectList = new LinkedList<>(); +// } +// LuckyBagNoticeInfo luckyBagNoticeInfo = JSON.parseObject(String.valueOf(baseProtocol.getData()), LuckyBagNoticeInfo.class); +// if (luckyBagNoticeInfo == null) return; +// if (baseProtocol.getSecond() == CUSTOM_MSG_LUCKY_GIFT_SERVER_ALL) { +// PlayEffectInfo playEffectInfo = new PlayEffectInfo(); +// playEffectInfo.setSecond(CUSTOM_MSG_LUCKY_GIFT_SERVER_ALL); +// playEffectInfo.setLuckyBagNoticeInfo(luckyBagNoticeInfo); +// playEffectList.add(playEffectInfo); +// if (playEffectDialog != null && playEffectDialog.isShowing()) { +// // 如果当前以及有礼物弹窗在展示,则需要等到他 dismiss 后再显示下一个 +// PlayEffectInfo dataBean = playEffectList.peekFirst(); +// if (dataBean != null) { +// return; +// } else { +// playEffectDialog.dismiss(); +// } +// } else { +// showPlayEffectDialog(); +// } +// } +// break; + case CUSTOM_MSG_FAIRY://夺宝精灵 + if (!isValid() || getWindow().getDecorView().getVisibility() != View.VISIBLE) return; + if (this instanceof AddUserInfoActivity || this instanceof AVRoomActivity +// || this instanceof TreasureBoxActivity || this instanceof HomeFairyActivity + || UserUtils.getUserInfo() == null) + return; + if (playEffectList == null) { + playEffectList = new LinkedList<>(); + } + FairyMsgInfoBean fairyMsgInfo = JSON.parseObject(String.valueOf(baseProtocol.getData()), FairyMsgInfoBean.class); + if (fairyMsgInfo == null) return; + if (baseProtocol.getSecond() == CUSTOM_MSG_SUB_DRAW_GIFT_L5) { + PlayEffectInfo playEffectInfo = new PlayEffectInfo(); + playEffectInfo.setSecond(CUSTOM_MSG_SUB_DRAW_GIFT_L5); + playEffectInfo.setFairyMsgInfo(fairyMsgInfo); + playEffectList.add(playEffectInfo); + if (playEffectDialog != null && playEffectDialog.isShowing()) { + // 如果当前以及有礼物弹窗在展示,则需要等到他 dismiss 后再显示下一个 + PlayEffectInfo dataBean = playEffectList.peekFirst(); + if (dataBean != null) { + return; + } else { + playEffectDialog.dismiss(); + } + } else { + showPlayEffectDialog(); + } + } + break; + case BOOM_FIRST: + LogUtils.dd(" RoomBoomManager BaseAct BOOM_SECOND_DIALOG start second="+second); + try { + if (second == BOOM_SECOND_DIALOG) { + BoomMsgDialogBean bean = JSON.parseObject(String.valueOf(baseProtocol.getData()), BoomMsgDialogBean.class); + + if (bean == null) { + LogUtils.dd(" RoomBoomManager BaseAct BOOM_SECOND_DIALOG bean == null second="+second); + return; + } + + if (bean.getPartitionId() != UserModel.get().getPartitionId()) { + LogUtils.dd(" RoomBoomManager BaseAct BOOM_SECOND_DIALOG PartitionId != second="+second + " bean.getPartitionId() = "+bean.getPartitionId() + " UserModel.get().getPartitionId() = "+UserModel.get().getPartitionId()); + return; + } + + LogUtils.dd(" RoomBoomManager BaseAct BOOM_SECOND_DIALOG (PartitionId bean ok) second="+second); + //全服飘屏 + RoomBoomManager.INSTANCE.addDialog(bean); + LogUtils.dd(" RoomBoomManager BaseAct BOOM_SECOND_DIALOG addDialog-- second="+second); + //房间内动画跟进度 + RoomBoomManager.INSTANCE.notify(bean); + LogUtils.dd(" RoomBoomManager BaseAct BOOM_SECOND_DIALOG notify-- second="+second); + //房间内公屏 + BoomMsgAttachment boomMsgAttachment = new BoomMsgAttachment(BOOM_FIRST, BOOM_SECOND_DIALOG); + boomMsgAttachment.DialogBean = bean; + ChatRoomMessage chatRoomMessage = new ChatRoomMessageImpl(); + chatRoomMessage.setAttachment(boomMsgAttachment); + ((IMMessageImpl)chatRoomMessage).setMsgType(MsgTypeEnum.custom.getValue()); + AvRoomDataManager.get().addChatRoomMessage(chatRoomMessage); + LogUtils.dd(" RoomBoomManager BaseAct BOOM_SECOND_DIALOG addChatRoomMessage-- second="+second +" level = "+bean.getLevel() + " pic = "+bean.getPic()); + } + }catch (Exception e){ + LogUtils.dd(" RoomBoomManager BaseAct BOOM_SECOND_DIALOG bean == null second="+second+ " error = "+e.getMessage()); + } + + break; + default: + break; + + + } + } + + private void showPlayEffectDialog() { + if (playEffectList.size() == 0) return; + playEffectDialog = new AllPlayEffectDialog(this, playEffectList.peekFirst()); + playEffectDialog.setOnDismissListener(dialog -> { + playEffectList.pollFirst(); + PlayEffectInfo dataBean = playEffectList.peekFirst(); + if (dataBean != null) { + if (isValid()) { + showPlayEffectDialog(); + } else { + playEffectList.clear(); + } + } + }); + try { + playEffectDialog.show(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void showGiftDialog() { + if (giftList.size() == 0) return; + AllServiceGiftProtocol.DataBean data = giftList.peekFirst(); + if (data == null) { + return; + } + if (!data.isHomeShow()) { + return; + } + giftDialog = generateAllServiceGiftDialog(this, data); + giftDialog.setOnDismissListener(dialog -> { + giftList.pollFirst(); + AllServiceGiftProtocol.DataBean dataBean = giftList.peekFirst(); + if (dataBean != null) { + if (isValid()) { + showGiftDialog(); + } else { + giftList.clear(); + } + } + }); + try { + giftDialog.show(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private AllServiceGiftLevelDialog generateAllServiceGiftDialog(@NonNull Context context, @NonNull AllServiceGiftProtocol.DataBean dataBean) { + return new AllServiceGiftLevelDialog(context, dataBean); + } + + public void onGrabApprenticesEvent(GrabApprenticesEvent event) { + if (!isTopActivity()) return; + } + + public void onRoomEventReceived(RoomEvent roomEvent) { + switch (roomEvent.getEvent()) { + case RoomEvent.RECHARGE: + onNeedCharge(); + break; + + case RoomEvent.RADISH_NOT_ENOUGH: + DialogUiHelper.showRadishNotEnoughDialog(this, null); + break; + + case RoomEvent.GIFT_OUT_OF_DATE: + SingleToastUtil.showToast(roomEvent.getMessage()); + break; + } + } + + public String DESAndBase64(String psw) { + String pwd = ""; + try { + pwd = DESUtils.DESAndBase64Encrypt(psw); + } catch (Exception e) { + e.printStackTrace(); + } + return pwd; + } + + + /** + * 把不需要处理云信广播的activity 添加到这里。 + * + * @return + */ + private boolean isNeedToHandleBroadcastMessageActivity() { + List acts = new ArrayList<>(); + acts.add(LoginPhoneActivity.class); + acts.add(LoginCodeActivity.class); + acts.add(ResetPasswordActivity.class); + acts.add(AddUserInfoActivity.class); + acts.add(NimMiddleActivity.class); + + for (Class act : acts) { + if (this.getClass().isInstance(act)) { + return false; + } + } + return true; + } + + @SuppressLint("CheckResult") + private void onNeedCharge() { + if (isShowingChargeDialog) { + return; + } + isShowingChargeDialog = true; + + UserModel.get().getCurrentUserInfo() + .compose(bindToLifecycle()) + .doOnError(throwable -> isShowingChargeDialog = false) + .subscribe( + userInfo -> { + new DialogManager(context).showOkCancelDialog(getString(R.string.tips_need_charge), + new DialogManager.OkCancelDialogListener() { + @Override + public void onOk() { + isShowingChargeDialog = false; + //充值 + WalletInfo goldWalletInfo = PayModel.get().getCurrentWalletInfo(); + HashMap map = new HashMap<>(5); + map.put(IReportConstants.PAYPAGE_TYPE, IReportConstants.TWO); + if (goldWalletInfo != null) { + map.put(IReportConstants.ACCOUNT_BALANCE, goldWalletInfo.getDiamondNum()); + } + map.put(IReportConstants.MODULE, IReportConstants.MOLISTAR_PAY); + ReportManager.get().reportEvent(IReportConstants.PAYPAGE_SHOW, map); +// if (AppMetaDataUtil.getChannelID().equals(Constants.GOOGLE)) { + ChargeActivity.start(context); +// } else { +// CommonWebViewActivity.start( +// context, UriProvider.getOfficialPay( +// 4, +// DeviceUtil.getDeviceId(context) +// ) +// ); +// } + } + + @Override + public void onCancel() { + isShowingChargeDialog = false; + } + }); + } + ); + + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onReceiveHello(NewbieHelloDialogEvent event) { + ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE); + if (am == null) return; + ComponentName cn = am.getRunningTasks(1).get(0).topActivity; + if (cn == null) return; + if (cn.getShortClassName().equals(getActivityByContext(context).getLocalClassName())) { + showHelloDialog(event.getHelloInfo()); + } + } + + /** + * 打招呼 + * + * @param helloInfo + */ + private void showHelloDialog(final NewbieHelloInfo helloInfo) { + String message = helloInfo.getMessage(); + int gender = helloInfo.getGender(); + String nick = helloInfo.getNick(); + String avatar = helloInfo.getAvatar(); + getDialogManager().showNewbieHelloDialog(avatar, gender, nick, message, ResUtil.getString(R.string.erban_base_baseactivity_03), ResUtil.getString(R.string.erban_base_baseactivity_04), true, new DialogManager.OkCancelDialogListener() { + @SuppressLint("CheckResult") + @Override + public void onOk() { + if (helloInfo.getInRoomUid() == 0) { + NimP2PMessageActivity.start(context, helloInfo.getUid()); + return; + } + + AvRoomModel.get() + .getUserRoom(Long.parseLong(helloInfo.getUid())) + .compose(RxHelper.singleMainResult()) + .compose(RxHelper.handleSchAndExce()) + .compose(bindToLifecycle()) + .subscribe((roomInfo, throwable) -> { + if (throwable == null) { + if (roomInfo != null && roomInfo.getUid() > 0 && roomInfo.getUid() == helloInfo.getInRoomUid()) { + AVRoomActivity.startForFromType(context, helloInfo.getInRoomUid(), + AVRoomActivity.FROM_TYPE_USER, nick, helloInfo.getUid()); + } else { + SingleToastUtil.showToast(ResUtil.getString(R.string.erban_base_baseactivity_05)); + } + } else { + SingleToastUtil.showToast(ResUtil.getString(R.string.erban_base_baseactivity_06)); + } + }); + } + }, context); + } + + private static class BroadcastObserver implements Observer { + private final WeakReference mReference; + + BroadcastObserver(BaseActivity baseMvpActivity) { + mReference = new WeakReference<>(baseMvpActivity); + } + + @Override + public void onEvent(BroadcastMessage broadcastMessage) { + if (broadcastMessage != null) { + String contentStr = broadcastMessage.getContent(); + Logger.i(ResUtil.getString(R.string.erban_base_baseactivity_07) + contentStr); + if (TextUtils.isEmpty(contentStr)) return; + BaseActivity baseMvpActivity = mReference.get(); + if (baseMvpActivity == null) return; + if (baseMvpActivity.isValid()) { + JSONObject jsonObject; + try { + jsonObject = JSON.parseObject(contentStr); + if (jsonObject == null) return; + if (jsonObject.containsKey("body")) { + String body = jsonObject.getString("body"); + if (TextUtils.isEmpty(body)) return; + baseMvpActivity.onReceivedNimBroadcastMessage(body); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/base/BaseBindingActivity.java b/app/src/main/java/com/chwl/app/base/BaseBindingActivity.java new file mode 100644 index 0000000..845b687 --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/BaseBindingActivity.java @@ -0,0 +1,39 @@ +package com.chwl.app.base; + +import android.content.Intent; +import android.os.Bundle; +import android.view.View; + +import androidx.databinding.DataBindingUtil; +import androidx.databinding.ViewDataBinding; + +import com.chwl.app.BR; +import com.chwl.library.annatation.ActLayoutRes; + +/** + * Created by huangmeng1 on 2018/5/7. + * 以包裹的布局文件会生成自动ViewDataBinding类 + * 如activity_main生成的文件类名是ActivityMainBinding,如果没有这个类 build一下 + */ + +public abstract class BaseBindingActivity extends BaseActivity implements View.OnClickListener { + public V mBinding; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mBinding = DataBindingUtil.setContentView(this, getClass().getAnnotation(ActLayoutRes.class).value()); + mBinding.setVariable(BR.click, this); + init(); + } + + protected abstract void init(); + + @Override + public void onClick(View v) { + } + + protected void start(Class c) { + startActivity(new Intent(this, c)); + } +} diff --git a/app/src/main/java/com/chwl/app/base/BaseBindingDialog.java b/app/src/main/java/com/chwl/app/base/BaseBindingDialog.java new file mode 100644 index 0000000..98f900c --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/BaseBindingDialog.java @@ -0,0 +1,91 @@ +package com.chwl.app.base; + +import android.content.Context; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; + +import androidx.appcompat.app.AppCompatDialog; +import androidx.databinding.DataBindingUtil; +import androidx.databinding.ViewDataBinding; + +import com.chwl.library.annatation.ActLayoutRes; +import com.netease.nim.uikit.common.util.sys.ScreenUtil; + +/** + * Created by huangmeng1 on 2018/4/12. + */ + +public abstract class BaseBindingDialog extends AppCompatDialog { + + + protected int width, height; + protected Context context; + protected int gravity; + + public BaseBindingDialog(Context context) { + this(context, 0); + } + + public BaseBindingDialog(Context context, int theme) { + super(context, theme); + this.context = context; + width = ScreenUtil.getDialogWidth(); + height = WindowManager.LayoutParams.WRAP_CONTENT; + gravity = Gravity.CENTER; + } + + protected T binding; + + @Override + protected void onStart() { + super.onStart(); + Window window = getWindow(); + if (window != null) { + window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); + WindowManager.LayoutParams windowParams = window.getAttributes(); + windowParams.width = width; + windowParams.height = height; + windowParams.dimAmount = 0.5f; + windowParams.gravity = gravity; + windowParams.x = 0; + windowParams.y = 0; + // window.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL); + window.setAttributes(windowParams); + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + View inflate = LayoutInflater.from(getContext()).inflate(getClass().getAnnotation(ActLayoutRes.class).value(), null); + setContentView(inflate.getRootView()); + setCancelable(true); + setCanceledOnTouchOutside(true); + binding = DataBindingUtil.bind(inflate); + init(); + } + + protected abstract void init(); + + public void openDialog() { + try { + show(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void closeDialog() { + try { + dismiss(); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/app/src/main/java/com/chwl/app/base/BaseBindingFragment.java b/app/src/main/java/com/chwl/app/base/BaseBindingFragment.java new file mode 100644 index 0000000..e318486 --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/BaseBindingFragment.java @@ -0,0 +1,32 @@ +package com.chwl.app.base; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.Nullable; +import androidx.databinding.DataBindingUtil; +import androidx.databinding.ViewDataBinding; + +import com.chwl.library.annatation.ActLayoutRes; + +/** + * Created by huangmeng1 on 2018/5/7. + */ + +public abstract class BaseBindingFragment extends BaseFragment { + public V mBinding; + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + mBinding = DataBindingUtil.bind(inflater.inflate(getClass().getAnnotation(ActLayoutRes.class).value(),container,false)); + return mBinding.getRoot(); + } + + @Override + public int getRootLayoutId() { + return getClass().getAnnotation(ActLayoutRes.class).value(); + } +} diff --git a/app/src/main/java/com/chwl/app/base/BaseBindingTakePhotoActivity.java b/app/src/main/java/com/chwl/app/base/BaseBindingTakePhotoActivity.java new file mode 100644 index 0000000..5b32909 --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/BaseBindingTakePhotoActivity.java @@ -0,0 +1,82 @@ +package com.chwl.app.base; + +import android.net.Uri; +import android.os.Bundle; +import android.view.View; + +import androidx.databinding.DataBindingUtil; +import androidx.databinding.ViewDataBinding; + +import com.chwl.app.R; +import com.chwl.app.ui.widget.ButtonItem; +import com.chwl.library.annatation.ActLayoutRes; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.file.JXFileUtils; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +/** + * 可以拍照的 binding activity + * Created by MadisonRong on 21/06/2018. + */ +public abstract class BaseBindingTakePhotoActivity extends BaseActivity implements View.OnClickListener { + + private static final String CAMERA_PREFIX = "picture_"; + public V mBinding; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mBinding = DataBindingUtil.setContentView(this, getClass().getAnnotation(ActLayoutRes.class).value()); + init(); + } + + protected abstract void init(); + + @Override + public void onClick(View v) { + } + + protected void showTakePhotoOperationDialog() { +// ButtonItem buttonItem = new ButtonItem(ResUtil.getString(R.string.erban_base_basebindingtakephotoactivity_01), this::checkPermissionAndStartCamera); + ButtonItem buttonItem1 = new ButtonItem(ResUtil.getString(R.string.erban_base_basebindingtakephotoactivity_02), () -> { + String mCameraCapturingName = CAMERA_PREFIX + System.currentTimeMillis() + ".jpg"; + File cameraOutFile = JXFileUtils.getTempFile(BaseBindingTakePhotoActivity.this, mCameraCapturingName); + if (!cameraOutFile.getParentFile().exists()) { + cameraOutFile.getParentFile().mkdirs(); + } + Uri uri = Uri.fromFile(cameraOutFile); + + }); + List buttonItems = new ArrayList<>(); +// buttonItems.add(buttonItem); + buttonItems.add(buttonItem1); + getDialogManager().showCommonPopupDialog(buttonItems, ResUtil.getString(R.string.erban_base_basebindingtakephotoactivity_03), false); + } + + + public void onUpload(String url) { + if (onUploadListener != null) { + onUploadListener.onUploadSuccess(url); + } + getDialogManager().dismissDialog(); + } + + public void onUploadFail() { + toast(ResUtil.getString(R.string.erban_base_basebindingtakephotoactivity_04)); + getDialogManager().dismissDialog(); + } + + + private OnUploadListener onUploadListener; + + public void setOnUploadListener(OnUploadListener onUploadListener) { + this.onUploadListener = onUploadListener; + } + + public interface OnUploadListener { + void onUploadSuccess(String url); + } +} diff --git a/app/src/main/java/com/chwl/app/base/BaseBsDialog.java b/app/src/main/java/com/chwl/app/base/BaseBsDialog.java new file mode 100644 index 0000000..c53e488 --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/BaseBsDialog.java @@ -0,0 +1,58 @@ +package com.chwl.app.base; + +import android.content.Context; +import android.os.Bundle; +import android.view.WindowManager; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; + +import com.google.android.material.bottomsheet.BottomSheetBehavior; +import com.google.android.material.bottomsheet.BottomSheetDialog; +import com.chwl.app.R; + +/** + * 定义一些通用的属性 + *

+ * Created by lvzebiao on 2019/2/28. + */ + +public abstract class BaseBsDialog extends BottomSheetDialog { + + protected Context context; + + public BaseBsDialog(@NonNull Context context) { + super(context, R.style.ErbanBottomSheetDialog); + this.context = context; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(getDialogLayout()); + setCanceledOnTouchOutside(isCanceledOnTouchOutside()); + FrameLayout bottomSheet = (FrameLayout) findViewById(R.id.design_bottom_sheet); + if (bottomSheet != null) { + BottomSheetBehavior.from(bottomSheet).setSkipCollapsed(false); + } + WindowManager.LayoutParams params = getWindow().getAttributes(); + params.width = WindowManager.LayoutParams.MATCH_PARENT; + //原来的计算方法在全面屏手机不适配 getResources().getDisplayMetrics().heightPixels 获取的高度不对 + //使用MATCH_PARENT + params.height = WindowManager.LayoutParams.MATCH_PARENT; + getWindow().setAttributes(params); + init(); + } + + protected abstract int getDialogLayout(); + + protected abstract void init(); + + /** + * 默认支持点击取消 + */ + protected boolean isCanceledOnTouchOutside() { + return true; + } + +} diff --git a/app/src/main/java/com/chwl/app/base/BaseDialogFragment.kt b/app/src/main/java/com/chwl/app/base/BaseDialogFragment.kt new file mode 100644 index 0000000..bccd4f3 --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/BaseDialogFragment.kt @@ -0,0 +1,132 @@ +package com.chwl.app.base + +import android.content.Context +import android.content.DialogInterface +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.WindowManager +import androidx.fragment.app.FragmentActivity +import androidx.fragment.app.FragmentManager +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.withResumed +import androidx.viewbinding.ViewBinding +import com.netease.nim.uikit.common.util.sys.ScreenUtil +import com.trello.rxlifecycle3.components.support.RxDialogFragment +import kotlinx.coroutines.launch +import java.lang.reflect.ParameterizedType + +abstract class BaseDialogFragment : RxDialogFragment() { + + val isViewLoaded: Boolean get() = _binding != null + protected var _binding: VB? = null + private var onDismissListener: (() -> Unit)? = null + val binding get() = _binding!! + open var width = ScreenUtil.getDialogWidth() + open var height = WindowManager.LayoutParams.WRAP_CONTENT + open var gravity = Gravity.CENTER + open var dimAmount = 0.5f + var mActionCallBack : Action?= null + + override fun onStart() { + super.onStart() + val window = dialog?.window + if (window != null) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + val windowParams = window.attributes + windowParams.width = width + windowParams.height = height + windowParams.dimAmount = dimAmount + windowParams.gravity = gravity + window.attributes = windowParams + } + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + //反射没有想象中的那么耗时 + val type = javaClass.genericSuperclass as ParameterizedType + val aClass = type.actualTypeArguments[0] as Class<*> + val method = aClass.getDeclaredMethod("inflate", LayoutInflater::class.java) + _binding = method.invoke(null, layoutInflater) as VB + return binding?.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + init() + } + + fun show(context: Context?) { + try { + show((context as FragmentActivity).supportFragmentManager, null) + } catch (e: Exception) { + e.printStackTrace() + } + } + + private var safeShowTask: ((FragmentManager, String?) -> Unit)? = null + + fun safeShow(fragmentManager: FragmentManager, lifecycleOwner: LifecycleOwner, tag: String? = null) { + lifecycleOwner.lifecycleScope.launch { + safeShowTask = { fm, tag -> + try { + show(fm, tag) + } catch (e: Exception) { + e.printStackTrace() + } + } + lifecycleOwner.withResumed { + safeShowTask?.invoke(fragmentManager, tag) + } + } + } + + fun safeDismiss() { + try { + dismissAllowingStateLoss() + } catch (e: Exception) { + e.printStackTrace() + } + } + + override fun onDestroy() { + super.onDestroy() + safeShowTask = null + } + + override fun dismiss() { + super.dismiss() + safeShowTask = null + } + + override fun dismissAllowingStateLoss() { + super.dismissAllowingStateLoss() + safeShowTask = null + } + + override fun onDismiss(dialog: DialogInterface) { + super.onDismiss(dialog) + onDismissListener?.invoke() + } + + fun setOnDismissListener(onDismissListener: () -> Unit) { + this.onDismissListener = onDismissListener + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + this.onDismissListener = null + } + + abstract fun init() + + public interface Action{ + fun onAction(type:Int,data:Any?) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/base/BaseFragment.java b/app/src/main/java/com/chwl/app/base/BaseFragment.java new file mode 100644 index 0000000..2ebd29c --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/BaseFragment.java @@ -0,0 +1,677 @@ +package com.chwl.app.base; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Toast; + +import androidx.annotation.Nullable; +import androidx.core.util.Consumer; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; + +import com.chwl.app.R; +import com.chwl.app.application.App; +import com.chwl.app.common.AbsStatusFragment; +import com.chwl.app.common.LoadingFragment; +import com.chwl.app.common.NetworkErrorFragment; +import com.chwl.app.common.NoDataFragment; +import com.chwl.app.common.ReloadFragment; +import com.chwl.app.common.widget.StatusLayout; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.library.utils.NetworkUtils; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; +import com.chwl.library.utils.UIUtils; +import com.chwl.library.utils.config.BasicConfig; +import com.chwl.library.utils.log.MLog; +import com.tbruyelle.rxpermissions2.RxPermissions; +import com.trello.rxlifecycle3.components.support.RxFragment; + +import java.util.List; +import java.util.Stack; + +import io.reactivex.Observable; +import io.reactivex.disposables.CompositeDisposable; + +/** + * @author alvin hwang + */ +public abstract class BaseFragment extends RxFragment implements KeyEvent.Callback, IDataStatus, + FragmentManager.OnBackStackChangedListener, IAcitivityBase { + + protected CompositeDisposable mCompositeDisposable; + + protected View mView; + protected Context mContext; + + protected boolean isDestroyView; + protected boolean mIsViewCreated; + protected RxPermissions rxPermissions; + + private boolean isLoaded = false; + public Consumer onHiddenChangedListener; + + private DialogManager dialogManager; + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mContext = getContext(); + onInitArguments(getArguments()); + if (getContext() != null) { + dialogManager = new DialogManager(getContext()); + } + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + rxPermissions = new RxPermissions(this); + } + + public void onNewIntent(Intent intent) { + + } + + protected void onInitArguments(Bundle bundle) { + + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + int rootLayoutId = getRootLayoutId(); + mView = inflater.inflate(rootLayoutId, container, false); + return mView; + } + + @Override + public void onDestroyView() { + mIsViewCreated = false; + isDestroyView = true; + isLoaded = false; + if (dialogManager != null) { + dialogManager.dismissDialog(); + } + dialogManager = null; + super.onDestroyView(); + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + mCompositeDisposable = new CompositeDisposable(); + } + + @Override + public void onDetach() { + super.onDetach(); + if (mCompositeDisposable != null) { + mCompositeDisposable.dispose(); + mCompositeDisposable = null; + } + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + mIsViewCreated = true; + onFindViews(); + onSetListener(); + } + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + restoreState(savedInstanceState); + initiate(); + } + + protected void restoreState(@Nullable Bundle savedInstanceState) { + + } + + @Override + public void onSetListener() { + + } + + @Override + public void onFindViews() { + + } + + @Override + public void onStart() { + super.onStart(); + getFragmentManager().addOnBackStackChangedListener(this); + } + + @Override + public void onResume() { + super.onResume(); + if (!isLoaded && !isHidden()) { + onLazyLoad(); + isLoaded = true; + } + } + + /** + * 重写该方法可实现懒加载数据,即当前Fragment第一次可见时才会执行一次,不同与setView()方法和onResume()方法 + */ + protected void onLazyLoad() { + + } + + @Override + public void onStop() { + super.onStop(); + getFragmentManager().removeOnBackStackChangedListener(this); + } + + @Override + public void onDestroy() { + super.onDestroy(); + } + + public int getRootLayoutId() { + return 0; + } + + @Override + public void onBackStackChanged() { + } + + @Override + public void onHiddenChanged(boolean hidden) { + super.onHiddenChanged(hidden); + if (onHiddenChangedListener != null) { + onHiddenChangedListener.accept(hidden); + } + } + + public Stack activityForResult = new Stack(); + + /** + * 为解决嵌套Fragment 收不到onActivityResult消息问题, Fragment需要调用onFragment + * + * @param requestCode + * @param resultCode + * @param data + */ + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + + while (!activityForResult.isEmpty()) { + Integer index = activityForResult.pop(); + + FragmentManager manager = getChildFragmentManager(); + if (manager == null) { //说明为activity是manager + manager = getFragmentManager(); + } + if (manager != null) { + @SuppressLint("RestrictedApi") + List list = manager.getFragments(); + if (list != null && list.size() > index) { + list.get(index).onActivityResult(requestCode, resultCode, data); + } + } else { + MLog.error(this, ResUtil.getString(R.string.erban_base_basefragment_01)); + } + } + + super.onActivityResult(requestCode, resultCode, data); + } + + @Override + public void startActivityForResult(Intent intent, int requestCode) { + + Fragment fragment = getFragmentInParent(); + if (fragment == null) { + super.startActivityForResult(intent, requestCode); + } else { + fragment.startActivityForResult(intent, requestCode); + } + } + + protected Fragment getFragmentInParent() { + + FragmentManager manager; + + Fragment parentFragment = this.getParentFragment(); + + if (parentFragment != null) { + manager = parentFragment.getChildFragmentManager(); + } else { + manager = this.getFragmentManager(); + } + + @SuppressLint("RestrictedApi") + List list = manager.getFragments(); + if (list != null) { + int index = list.indexOf(this); + + if (parentFragment != null && parentFragment instanceof BaseFragment) { + ((BaseFragment) parentFragment).activityForResult.push(index); + } + } + return parentFragment; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + return super.onOptionsItemSelected(item); + } + + /** + * 权限回调 + */ + @SuppressLint("CheckResult") + public Observable checkPermission(String... mPerms) { + return rxPermissions.request(mPerms); + } + + /** + * -------------------------------------------------- + * -------------------------数据状态相关----------------- + * -------------------------------------------------- + */ + + protected static final String STATUS_TAG = "STATUS_TAG"; + + @Override + public View.OnClickListener getLoadListener() { + return new View.OnClickListener() { + @Override + public void onClick(View v) { + onReloadData(); + } + }; + } + + /** + * 重新加载页面数据:通常应用于无网络切换到有网络情况,重新刷新页面 + */ + public void onReloadData() { + + } + + @Override + public View.OnClickListener getLoadMoreListener() { + return null; + } + + @Override + public View.OnClickListener getNoMobileLiveDataListener() { + return null; + } + + @Override + public void showLoading() { + showLoading(0, 0); + } + + @Override + public void showLoading(View view) { + showLoading(view, 0, 0); + } + + @Override + public void showReload() { + showReload(0, 0); + } + + @Override + public void showNoData() { + showNoData(0, ""); + } + + @Override + public void showNoData(CharSequence charSequence) { + showNoData(0, charSequence); + } + + @Override + public void showNoLogin() { + + } + + @Override + public void showLoading(int drawable, int tips) { + showLoading(getView(), drawable, tips); + } + + @Override + public void showLoading(View view, int drawable, int tips) { + showLoading(view, drawable, tips, 0); + } + + protected void showLoading(View view, int drawable, int tips, int paddingBottom) { + if (!checkActivityValid()) { + return; + } + if (view == null) { + return; + } + View status = view.findViewById(R.id.status_layout); + if (status == null || view.getId() == View.NO_ID) { + return; + } + Fragment fragment; + if (paddingBottom == 0) { + fragment = LoadingFragment.newInstance(drawable, tips); + } else { + fragment = LoadingFragment.newInstance(drawable, tips, paddingBottom); + } + getChildFragmentManager().beginTransaction().replace(status.getId(), fragment, STATUS_TAG).commitAllowingStateLoss(); + } + + @Override + public void showReload(int drawable, int tips) { + showReload(getView(), drawable, tips); + } + + @Override + public void showReload(View view, int drawable, int tips) { + if (!checkActivityValid()) + return; + + if (view == null) { + MLog.error(this, "xuwakao, showReload view is NULL"); + return; + } + View status = view.findViewById(R.id.status_layout); + if (status == null || view.getId() == View.NO_ID) { + MLog.error(this, "xuwakao, had not set layout id "); + return; + } + ReloadFragment fragment = ReloadFragment.newInstance(drawable, tips); + fragment.setListener(getLoadListener()); + getChildFragmentManager().beginTransaction().replace(status.getId(), fragment, STATUS_TAG).commitAllowingStateLoss(); + } + + @Override + public void showNoData(int drawable, CharSequence charSequence) { + showNoData(getView(), drawable, charSequence); + } + + @Override + public void showNoData(View view, int drawable, CharSequence charSequence) { + if (!checkActivityValid()) + return; + + if (view == null) { + MLog.error(this, "xuwakao, showNoData view is NULL"); + return; + } + View status = view.findViewById(R.id.status_layout); + if (status == null || view.getId() == View.NO_ID) { + MLog.error(this, "xuwakao, had not set layout id "); + return; + } + NoDataFragment fragment = NoDataFragment.newInstance(drawable, charSequence); + fragment.setListener(getLoadListener()); + getChildFragmentManager().beginTransaction().replace(status.getId(), fragment, STATUS_TAG).commitAllowingStateLoss(); + } + + @Override + public void showNetworkErr() { + if (!checkActivityValid()) { + return; + } + + if (getView() == null) { + MLog.error(this, "xuwakao, showNetworkErr view is NULL"); + return; + } + View view = getView().findViewById(R.id.status_layout); + if (view == null || view.getId() == View.NO_ID) { + MLog.error(this, "xuwakao, had not set layout id "); + return; + } + NetworkErrorFragment fragment = new NetworkErrorFragment(); + fragment.setListener(getLoadListener()); + getChildFragmentManager().beginTransaction().replace(view.getId(), fragment, STATUS_TAG).commitAllowingStateLoss(); + } + + @Override + public void hideStatus() { + Fragment fragment = getChildFragmentManager().findFragmentByTag(STATUS_TAG); + if (fragment != null) { + getChildFragmentManager().beginTransaction().remove(fragment).commitAllowingStateLoss(); + } else { + MLog.warn(this, "xuwakao, status fragment is NULL"); + } + } + + @Override + public void showPageError(int tips) { + showPageError(getView(), tips); + } + + @Override + public void showPageError(View view, int tips) { + if (!checkActivityValid()) + return; + + if (view == null) { + MLog.error(this, "xuwakao, showReload view is NULL"); + return; + } + View more = view.findViewById(R.id.loading_more); + if (more == null) { + MLog.error(this, "xuwakao, showReload more is NULL"); + return; + } + StatusLayout statusLayout = (StatusLayout) more.getParent(); + statusLayout.showErrorPage(tips, getLoadMoreListener()); + } + + @Override + public void showPageLoading() { + if (!checkActivityValid()) + return; + + if (getView() == null) { + MLog.error(this, "xuwakao, showReload view is NULL"); + return; + } + View more = getView().findViewById(R.id.loading_more); + if (more == null) { + MLog.error(this, "xuwakao, showReload more is NULL"); + return; + } + StatusLayout statusLayout = (StatusLayout) more.getParent(); + statusLayout.showLoadMore(); + } + + protected boolean checkActivityValid() { + return UIUtils.checkActivityValid(getActivity()); + } + + //====================================================================================// + //==============================请求过滤条件筛选的返回================================// + //====================================================================================// + public boolean isTopActive() {//FIXME 到我的音乐后,RecommendFragment仍然是isTopActive() + boolean isVisible = this.isResumed() && this.isVisible() && getUserVisibleHint(); + if (!isVisible) { + return false; + } + + FragmentManager manager = this.getChildFragmentManager(); + if (manager == null) { + return true; + } + + int count = manager.getFragments() == null ? 0 : manager.getFragments().size(); + if (count > 0) { + for (int i = 0; i < count; i++) { + Fragment fragment = manager.getFragments().get(i); + if (fragment == null) { + return true; + } + + if (fragment instanceof AbsStatusFragment) { + return true; + } + + if (fragment.isVisible()) { + return false; + } + } + } + + return true; + } + + + /** + * 当前网络是否可用 + * + * @return + */ + public boolean isNetworkAvailable() { + return NetworkUtils.isNetworkStrictlyAvailable(getActivity()); + } + + /** + * 通用消息提示 + * + * @param resId + */ + public void toast(int resId) { + toast(resId, Toast.LENGTH_SHORT); + } + + /** + * 通用消息提示 + * + * @param tip + */ + public void toast(String tip) { + toast(tip, Toast.LENGTH_SHORT); + } + + /** + * 通用消息提示 + * + * @param resId + * @param length + */ + public void toast(int resId, int length) { + SingleToastUtil.showToast(BasicConfig.INSTANCE.getAppContext(), resId); + } + + /** + * 通用消息提示 + * + * @param tip + * @param length + */ + public void toast(String tip, int length) { + SingleToastUtil.showToast(BasicConfig.INSTANCE.getAppContext(), tip, length); + } + + public boolean checkNetToast() { + boolean flag = isNetworkAvailable(); + if (!flag) + toast(R.string.str_network_not_capable); + return flag; + } + + + protected DialogManager getDialogManager() { + + + FragmentActivity activity = getActivity(); + try { + if (activity instanceof BaseMvpActivity) { + DialogManager dialogManager1 = ((BaseMvpActivity) activity).getDialogManager(); + if (dialogManager1 != null) { + dialogManager = dialogManager1; + } + return dialogManager1; + } else if (activity instanceof BaseActivity) { + DialogManager dialogManager2 = ((BaseActivity) activity).getDialogManager(); + if (dialogManager2 != null) { + dialogManager = dialogManager2; + } + return dialogManager2; + } + + Context fragmentContext = getContext(); + if (dialogManager == null && fragmentContext != null) { + dialogManager = new DialogManager(fragmentContext); + } + + if (dialogManager == null) { + Activity topActivity = App.gStack.getTopActivity(); + if (topActivity != null) { + dialogManager = new DialogManager(topActivity); + } + } + } catch (Exception e) { + e.printStackTrace(); + dialogManager = new DialogManager(true); + } + + return dialogManager; + } + + public BaseActivity getBaseActivity() { + return (BaseActivity) getActivity(); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_MENU) { + showOptionsMenu(); + } +// if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { +// AudioManager audio = (AudioManager) (getContext().getSystemService(Service.AUDIO_SERVICE)); +// audio.adjustStreamVolume( +// AudioManager.STREAM_VOICE_CALL, +// AudioManager.ADJUST_LOWER, +// AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_SHOW_UI); +// return true; +// } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) { +// AudioManager audio = (AudioManager) (getContext().getSystemService(Service.AUDIO_SERVICE)); +// audio.adjustStreamVolume( +// AudioManager.STREAM_VOICE_CALL, +// AudioManager.ADJUST_RAISE, +// AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_SHOW_UI); +// return true; +// } + return false; + } + + protected void showOptionsMenu() { + + } + + @Override + public boolean onKeyLongPress(int keyCode, KeyEvent event) { + return false; + } + + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + return false; + } + + @Override + public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) { + return false; + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/base/BaseLazyFragment.java b/app/src/main/java/com/chwl/app/base/BaseLazyFragment.java new file mode 100644 index 0000000..a7ed398 --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/BaseLazyFragment.java @@ -0,0 +1,58 @@ +package com.chwl.app.base; + +import android.os.Bundle; +import android.view.View; + +import androidx.annotation.Nullable; + +/** + *

具备懒加载的fragment

+ * + * @author Administrator + * @date 2017/11/23 + */ +public abstract class BaseLazyFragment extends BaseFragment { + + private boolean mIsInitView; + private boolean mIsLoaded; + /** 当前fragment是否还活着 */ + private boolean mIsDestroyView = true; + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + } + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + mIsInitView = true; + if (getUserVisibleHint() && !mIsLoaded && mIsDestroyView) { + mIsDestroyView = false; + onLazyLoadData(); + } + } + + @Override + public void setUserVisibleHint(boolean isVisibleToUser) { + super.setUserVisibleHint(isVisibleToUser); + if (isVisibleToUser) { + if (mIsInitView && !mIsLoaded && mIsDestroyView) { + mIsDestroyView = false; + mIsLoaded = true; + onLazyLoadData(); + } + } else { + mIsLoaded = false; + } + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + mIsDestroyView = true; + } + + /** 数据懒加载 */ + protected abstract void onLazyLoadData(); +} diff --git a/app/src/main/java/com/chwl/app/base/BaseListFragment.kt b/app/src/main/java/com/chwl/app/base/BaseListFragment.kt new file mode 100644 index 0000000..10c800c --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/BaseListFragment.kt @@ -0,0 +1,109 @@ +package com.chwl.app.base + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chwl.app.R +import com.chwl.app.bindadapter.BaseBindingAdapter +import com.chwl.app.databinding.BaseListFragmentBinding +import com.chwl.library.common.util.setVis +import com.scwang.smart.refresh.layout.api.RefreshLayout +import com.scwang.smart.refresh.layout.listener.OnRefreshLoadMoreListener + + +abstract class BaseListFragment: + BaseViewBindingFragment() { + + lateinit var mAdapter: BaseBindingAdapter<*, D> + protected var mPageSize = 20; + protected var mPage = 1; + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + _binding = BaseListFragmentBinding.inflate(layoutInflater) + return binding.root + } + + + + override fun init() { + mAdapter = getAdapter() + + binding.rvList.layoutManager = getLayoutManager() + binding.rvList.adapter = mAdapter + + binding.srlLayout.setOnRefreshLoadMoreListener(object : OnRefreshLoadMoreListener { + override fun onRefresh(refreshLayout: RefreshLayout) { + onRefresh() + } + + override fun onLoadMore(refreshLayout: RefreshLayout) { + onLoad() + } + }) + mAdapter.onItemClickListener = BaseQuickAdapter.OnItemClickListener { adapter, view, position -> + onItemClicks(mAdapter, view, position) + } + mAdapter.onItemChildClickListener = BaseQuickAdapter.OnItemChildClickListener { adapter, view, position -> + onItemChildClicks(mAdapter, view, position) + } + initView() + } + + abstract fun getAdapter(): BaseBindingAdapter<*, D> + + protected open fun getLayoutManager(): RecyclerView.LayoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false) + protected open fun hasTitle(): Boolean = false + + protected open fun onItemClicks( + adapter: BaseBindingAdapter<*, D>?, + view: View?, + position: Int + ) {} + protected open fun onItemChildClicks( + adapter: BaseBindingAdapter<*, D>?, + view: View?, + position: Int + ) {} + + abstract fun onLoad() + abstract fun onRefresh() + + + abstract fun initView() + + protected open fun stopAnim() { + binding.srlLayout.finishLoadMore() + binding.srlLayout.finishRefresh() + } + + var mTitleBar : TitleBar?=null + open fun initWhiteTitleBar(title: String?,listener:View.OnClickListener) { + mTitleBar = _binding?.root?.findViewById(R.id.title_bar) + if (mTitleBar != null) { + mTitleBar?.setTitle(title) + mTitleBar?.setImmersive(false) + mTitleBar?.setTitleColor(resources.getColor(R.color.text_title_color)) + mTitleBar?.setLeftImageResource(R.drawable.arrow_left) + mTitleBar?.setBackgroundResource(R.color.transparent) + mTitleBar?.setLeftClickListener(listener) + mTitleBar?.setVis(true) + } + } + + fun initBlackTitleBar(title: String?,listener:View.OnClickListener) { + mTitleBar = _binding?.root?.findViewById(R.id.title_bar) + if (mTitleBar != null) { + mTitleBar?.setTitle(title) + mTitleBar?.setImmersive(false) + mTitleBar?.setTitleColor(resources.getColor(R.color.white)) + mTitleBar?.setLeftImageResource(R.drawable.icon_user_back) + mTitleBar?.setBackgroundResource(R.color.transparent) + mTitleBar?.setLeftClickListener(listener) + mTitleBar?.setVis(true) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/base/BaseListViewModel.java b/app/src/main/java/com/chwl/app/base/BaseListViewModel.java new file mode 100644 index 0000000..2f57146 --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/BaseListViewModel.java @@ -0,0 +1,66 @@ +package com.chwl.app.base; + +import androidx.databinding.ObservableArrayList; +import androidx.databinding.ObservableBoolean; +import androidx.databinding.ObservableField; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chwl.core.Constants; +import com.chwl.core.bean.response.ServiceResult; +import com.chwl.core.utils.net.RxHelper; +import com.chwl.library.utils.SingleToastUtil; +import com.chwl.library.utils.config.BasicConfig; + +import java.util.List; + +import io.reactivex.Single; +import io.reactivex.functions.Consumer; + +/** + * Created by huangmeng1 on 2018/5/10. + */ + +public abstract class BaseListViewModel { + public int page = 1; + public int pageSize = Constants.PAGE_SIZE; + + public ObservableBoolean loading = new ObservableBoolean(false); + public ObservableBoolean isLode = new ObservableBoolean(false); + public ObservableArrayList data = new ObservableArrayList<>(); + public ObservableArrayList loadData = new ObservableArrayList<>(); + public ObservableField throwable = new ObservableField<>(); + + public SwipeRefreshLayout.OnRefreshListener onRefreshListener = () -> loadData(false).subscribe(); + public BaseQuickAdapter.RequestLoadMoreListener loadMoreListener = () -> loadData(true).subscribe(); + + public Single> loadData(boolean isLode) { + this.isLode.set(isLode); + if (isLode) { + page++; + } else { + page = 1; + loading.set(true); + } + return getSingle().compose(RxHelper.handleBeanData()) + .doAfterTerminate(() -> loading.set(false)) + .doOnSuccess(carInfos -> { + throwable.set(null); + loadData.clear(); + loadData.addAll(carInfos); + if (!isLode) data.clear(); + data.addAll(carInfos); + }) + .doOnError(new Consumer() { + @Override + public void accept(Throwable e) throws Exception { + SingleToastUtil.showToast(BasicConfig.INSTANCE.getAppContext(), e.getMessage()); + loading.set(false); + throwable.set(e); + } + }); + } + + public abstract Single>> getSingle(); + +} diff --git a/app/src/main/java/com/chwl/app/base/BaseMsListViewModel.java b/app/src/main/java/com/chwl/app/base/BaseMsListViewModel.java new file mode 100644 index 0000000..169f9ae --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/BaseMsListViewModel.java @@ -0,0 +1,72 @@ +package com.chwl.app.base; + +import androidx.databinding.ObservableArrayList; +import androidx.databinding.ObservableBoolean; +import androidx.databinding.ObservableField; +import androidx.databinding.ViewDataBinding; + +import com.trello.rxlifecycle3.LifecycleProvider; +import com.chwl.core.Constants; +import com.chwl.core.bean.response.ServiceResult; +import com.chwl.core.utils.net.RxHelper; + +import java.util.List; + +import io.reactivex.Single; +import io.reactivex.functions.Consumer; + +/** + * 移植萌声ktv复制的类 + * Created by lvzebiao on 2018/11/1. + */ + +public abstract class BaseMsListViewModel { + public V mBinding; + public int page=1; + public int pageSize= Constants.PAGE_SIZE; + + public ObservableBoolean loading=new ObservableBoolean(false); + public ObservableBoolean isLode=new ObservableBoolean(false); + public ObservableArrayList data=new ObservableArrayList<>(); + public ObservableArrayList loadData=new ObservableArrayList<>(); + public ObservableField throwable=new ObservableField<>(); + + public BaseMsListViewModel(V mBinding) { + this.mBinding = mBinding; + } + + public Single> loadData(boolean isLode){ + this.isLode.set(isLode); + if (isLode){ + page++; + }else { + page=1; + loading.set(true); + } + return getSingle().compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()) + .doAfterTerminate(() -> loading.set(false)) + .doOnSuccess(carInfos -> { + throwable.set(null); + loadData.clear(); + loadData.addAll(carInfos); + if (!isLode) data.clear(); + data.addAll(carInfos); + }) + .doOnError(new Consumer(){ + @Override + public void accept(Throwable e) throws Exception { + loading.set(false); + throwable.set(e); + } + }); + } + + public abstract Single>> getSingle(); + + public void loadData(LifecycleProvider provider, boolean isLoad){ + loadData(isLoad) + .compose(provider.bindToLifecycle()) + .subscribe(); + } +} diff --git a/app/src/main/java/com/chwl/app/base/BaseMvpActivity.java b/app/src/main/java/com/chwl/app/base/BaseMvpActivity.java new file mode 100644 index 0000000..7c4b4cc --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/BaseMvpActivity.java @@ -0,0 +1,12 @@ +package com.chwl.app.base; + +import com.chwl.library.base.IMvpBaseView; +import com.chwl.library.base.factory.AbstractMvpPresenter; + +/** + * @author alvin hwang + */ +public abstract class BaseMvpActivity> extends AbstractMvpActivity + implements IDataStatus, DialogManagerInterface { + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/base/BaseMvpFragment.java b/app/src/main/java/com/chwl/app/base/BaseMvpFragment.java new file mode 100644 index 0000000..2d6bb4a --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/BaseMvpFragment.java @@ -0,0 +1,15 @@ +package com.chwl.app.base; + +import android.view.KeyEvent; + +import androidx.fragment.app.FragmentManager; + +import com.chwl.library.base.IMvpBaseView; +import com.chwl.library.base.factory.AbstractMvpPresenter; + +/** + * @author alvin hwang + */ +public abstract class BaseMvpFragment> extends AbstractMvpFragment + implements KeyEvent.Callback, IDataStatus, FragmentManager.OnBackStackChangedListener, IAcitivityBase { +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/base/BaseMvpPresenter.java b/app/src/main/java/com/chwl/app/base/BaseMvpPresenter.java new file mode 100644 index 0000000..15bc59f --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/BaseMvpPresenter.java @@ -0,0 +1,28 @@ +package com.chwl.app.base; + +import android.os.Bundle; + +import androidx.annotation.Nullable; + +import com.chwl.library.base.IMvpBaseView; +import com.chwl.library.base.factory.AbstractMvpPresenter; + + +/** + * @author jack + * @Description + * @Date 2018/5/9 + */ + +public class BaseMvpPresenter extends AbstractMvpPresenter { + + @Override + public void onCreatePresenter(@Nullable Bundle saveState) { + super.onCreatePresenter(saveState); + } + + @Override + public void onDestroyPresenter() { + super.onDestroyPresenter(); + } +} diff --git a/app/src/main/java/com/chwl/app/base/BaseSdDialog.java b/app/src/main/java/com/chwl/app/base/BaseSdDialog.java new file mode 100644 index 0000000..c2ff5d4 --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/BaseSdDialog.java @@ -0,0 +1,43 @@ +package com.chwl.app.base; + +import android.content.Context; + +import androidx.appcompat.app.AppCompatDialog; + + +/** + * save dismiss dialog + * create by lvzebiao @2019/7/19 + */ +public class BaseSdDialog extends AppCompatDialog { + + public Context context; + + public BaseSdDialog(Context context) { + super(context); + init(context); + } + + public BaseSdDialog(Context context, int theme) { + super(context, theme); + init(context); + } + + protected BaseSdDialog(Context context, boolean cancelable, OnCancelListener cancelListener) { + super(context, cancelable, cancelListener); + init(context); + } + + private void init(Context context) { + this.context = context; + } + + @Override + public void dismiss() { + try { + super.dismiss(); + } catch (Exception ex) { + ex.printStackTrace(); + } + } +} diff --git a/app/src/main/java/com/chwl/app/base/BaseVM.java b/app/src/main/java/com/chwl/app/base/BaseVM.java new file mode 100644 index 0000000..85a9693 --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/BaseVM.java @@ -0,0 +1,9 @@ +package com.chwl.app.base; + +/** + * Created by huangmeng1 on 2018/5/7. + */ + +public class BaseVM { + +} diff --git a/app/src/main/java/com/chwl/app/base/BaseViewBindingActivity.kt b/app/src/main/java/com/chwl/app/base/BaseViewBindingActivity.kt new file mode 100644 index 0000000..29b801b --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/BaseViewBindingActivity.kt @@ -0,0 +1,39 @@ +package com.chwl.app.base + +import android.os.Bundle +import android.view.LayoutInflater +import androidx.annotation.Nullable +import androidx.viewbinding.ViewBinding +import com.netease.nim.uikit.StatusBarUtil +import java.lang.reflect.ParameterizedType + + +abstract class BaseViewBindingActivity : BaseActivity(){ + + lateinit var binding : T + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + this.initBefore(savedInstanceState) + //反射没有想象中的那么耗时 + val type = javaClass.genericSuperclass as ParameterizedType + val aClass = type.actualTypeArguments[0] as Class<*> + val method = aClass.getDeclaredMethod("inflate", LayoutInflater::class.java) + binding = method.invoke(null,layoutInflater) as T + setContentView(binding.root) + + if (transparencyBar()) { + StatusBarUtil.transparencyBar(this) + } + + init() + } + + /** + * 该方法是在onCreate()方法里执行,在setContentView()方法被调用之前触发,可用于处理解析Activity#getIntent()中的数据时的场景 + */ + protected open fun initBefore(@Nullable savedInstanceState: Bundle?) {} + + abstract fun init() + protected open fun transparencyBar():Boolean=false +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/base/BaseViewBindingFragment.kt b/app/src/main/java/com/chwl/app/base/BaseViewBindingFragment.kt new file mode 100644 index 0000000..d6f01bd --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/BaseViewBindingFragment.kt @@ -0,0 +1,42 @@ +package com.chwl.app.base + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.viewbinding.ViewBinding +import java.lang.reflect.ParameterizedType + +abstract class BaseViewBindingFragment : BaseFragment() { + + protected var _binding: T? = null + + val binding get() = _binding!! + fun getViewBinding():T?{ + return _binding + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + //反射没有想象中的那么耗时 + val type = javaClass.genericSuperclass as ParameterizedType + val aClass = type.actualTypeArguments[0] as Class<*> + val method = aClass.getDeclaredMethod("inflate", LayoutInflater::class.java) + _binding = method.invoke(null, layoutInflater) as T + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + init() + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + + override fun initiate() { + } + + abstract fun init() +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/base/BaseViewModel.kt b/app/src/main/java/com/chwl/app/base/BaseViewModel.kt new file mode 100644 index 0000000..1bf416f --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/BaseViewModel.kt @@ -0,0 +1,64 @@ +package com.chwl.app.base + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.chwl.core.utils.extension.toast +import com.chwl.library.net.rxnet.exception.ExceptionHandle +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.disposables.Disposable +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch + +open class BaseViewModel : ViewModel() { + + private var compositeDisposable: CompositeDisposable? = null + private val _loadingLiveData by lazy { MutableLiveData() } + val loadingLiveData: LiveData = _loadingLiveData + + fun safeLaunch( + needLoading: Boolean = false, + onError: suspend(e: Throwable) -> Unit = { + if (it.message != "Job was cancelled") { + val message = ExceptionHandle.handleException(it) + message.toast() + } + }, + onComplete: (() -> Unit)? = null, + block: suspend CoroutineScope.() -> Unit + ) { + viewModelScope.launch { + try { + if (needLoading) _loadingLiveData.value = true + block() + } catch (e: Throwable) { + e.printStackTrace() + onError(e) + } finally { + if (needLoading) _loadingLiveData.value = false + onComplete?.invoke() + } + + } + } + + private fun getCompositeDisposable(): CompositeDisposable { + var disposable = compositeDisposable + if (disposable == null) { + disposable = CompositeDisposable() + compositeDisposable = disposable + } + return disposable + } + + protected fun addDisposable(disposable: Disposable) { + getCompositeDisposable().add(disposable) + } + + override fun onCleared() { + super.onCleared() + compositeDisposable?.dispose() + compositeDisposable = null + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/base/DialogManagerInterface.java b/app/src/main/java/com/chwl/app/base/DialogManagerInterface.java new file mode 100644 index 0000000..131f376 --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/DialogManagerInterface.java @@ -0,0 +1,10 @@ +package com.chwl.app.base; + +import com.chwl.app.common.widget.dialog.DialogManager; + +/** + * 返回通用的dialogmanager + */ +public interface DialogManagerInterface { + DialogManager getDialogManager(); +} diff --git a/app/src/main/java/com/chwl/app/base/Event.kt b/app/src/main/java/com/chwl/app/base/Event.kt new file mode 100644 index 0000000..3a66752 --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/Event.kt @@ -0,0 +1,27 @@ +package com.chwl.app.base + +/** + * Used as a wrapper for data that is exposed via a LiveData that represents an event. + */ +open class Event(private val content: T) { + + var hasBeenHandled = false + private set // Allow external read but not write + + /** + * Returns the content and prevents its use again. + */ + fun getContentIfNotHandled(): T? { + return if (hasBeenHandled) { + null + } else { + hasBeenHandled = true + content + } + } + + /** + * Returns the content, even if it's already been handled. + */ + fun peekContent(): T = content +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/base/GlobalViewModelOwner.kt b/app/src/main/java/com/chwl/app/base/GlobalViewModelOwner.kt new file mode 100644 index 0000000..ae54ab0 --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/GlobalViewModelOwner.kt @@ -0,0 +1,22 @@ +package com.chwl.app.base + + +import androidx.lifecycle.ViewModelStore +import androidx.lifecycle.ViewModelStoreOwner +import com.example.lib_utils.ICleared + +class GlobalViewModelOwner : ViewModelStoreOwner, ICleared { + + companion object { + private val viewModelStore by lazy { ViewModelStore() } + val instance by lazy { GlobalViewModelOwner() } + } + + override fun onCleared() { + super.onCleared() + viewModelStore.clear() + } + + override val viewModelStore: ViewModelStore + get() = GlobalViewModelOwner.viewModelStore +} diff --git a/app/src/main/java/com/chwl/app/base/IAcitivityBase.java b/app/src/main/java/com/chwl/app/base/IAcitivityBase.java new file mode 100644 index 0000000..659d769 --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/IAcitivityBase.java @@ -0,0 +1,15 @@ +package com.chwl.app.base; + +/** + * Created by zhouxiangfeng on 17/3/5. + */ + +public interface IAcitivityBase extends IBase { + + void onFindViews(); + + void onSetListener(); + + void initiate(); + +} diff --git a/app/src/main/java/com/chwl/app/base/IBase.java b/app/src/main/java/com/chwl/app/base/IBase.java new file mode 100644 index 0000000..59e4652 --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/IBase.java @@ -0,0 +1,7 @@ +package com.chwl.app.base; + +/** + * Created by zhouxiangfeng on 17/3/5. + */ +public interface IBase { +} diff --git a/app/src/main/java/com/chwl/app/base/IDataStatus.java b/app/src/main/java/com/chwl/app/base/IDataStatus.java new file mode 100644 index 0000000..df9148e --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/IDataStatus.java @@ -0,0 +1,50 @@ +package com.chwl.app.base; + +import android.view.View; + +/** + * Created by xujiexing on 14-7-15. + */ +public interface IDataStatus { + + public View.OnClickListener getLoadListener(); + + public View.OnClickListener getLoadMoreListener(); + + public View.OnClickListener getNoMobileLiveDataListener(); + + public void showLoading(); + + public void showLoading(View view); + + public void showReload(); + + public void showNoLogin(); + + public void showLoading(int drawable, int tips); + + public void showLoading(View view, int drawable, int tips); + + public void showReload(int drawable, int tips); + + public void showReload(View view, int drawable, int tips); + + public void showNoData(); + + public void showNoData(CharSequence charSequence); + + public void showNoData(int drawable, CharSequence charSequence); + + public void showNoData(View view, int drawable, CharSequence charSequence); + + public void showNetworkErr(); + + public void hideStatus(); + + public void showPageError(int tips); + + public void showPageError(View view, int tips); + + public void showPageLoading(); + +} diff --git a/app/src/main/java/com/chwl/app/base/PhotoPickActivity.kt b/app/src/main/java/com/chwl/app/base/PhotoPickActivity.kt new file mode 100644 index 0000000..882904c --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/PhotoPickActivity.kt @@ -0,0 +1,204 @@ +package com.chwl.app.base + +import android.Manifest +import android.app.Activity +import android.content.Intent +import android.net.Uri +import android.os.Build +import android.os.Bundle +import android.provider.Settings +import androidx.activity.ComponentActivity +import androidx.activity.result.ActivityResultLauncher +import androidx.activity.result.PickVisualMediaRequest +import androidx.activity.result.contract.ActivityResultContracts +import com.chwl.app.R +import com.chwl.app.ui.widget.dialog.CommonTipDialog +import com.chwl.core.utils.DialogUtil +import com.chwl.library.common.util.SPUtils +import com.chwl.library.common.util.doToast +import com.chwl.library.constants.ConstantsLib +import com.chwl.library.easypermisssion.EasyPermissions +import com.hjq.toast.ToastUtils +import com.netease.nim.uikit.common.ui.dialog.EasyAlertDialogHelper + +class PhotoPickActivity : ComponentActivity(), EasyPermissions.PermissionCallbacks { + + companion object { + + + @JvmStatic + fun start(act: Activity, mediaType: String,code :Int) { + val intent = Intent(act, PhotoPickActivity::class.java) + intent.putExtra(PICK_ACT_TYPE, mediaType) + act.startActivityForResult(intent, code) + } + @JvmStatic + fun getIntent(act: Activity, mediaType: String,code :Int) :Intent{ + val intent = Intent(act, PhotoPickActivity::class.java) + intent.putExtra(PICK_ACT_TYPE, mediaType) + return intent + } + + @JvmStatic + fun start(act: Activity, mediaType: String) { + val intent = Intent(act, PhotoPickActivity::class.java) + intent.putExtra(PICK_ACT_TYPE, mediaType) + act.startActivityForResult(intent, PICK_ACT_RESULT) + } + + + fun startImg(act: Activity) { + val intent = Intent(act, PhotoPickActivity::class.java) + intent.putExtra(PICK_ACT_TYPE, IMG) + act.startActivityForResult(intent, PICK_ACT_RESULT) + } + + fun startImg(act: Activity,code: Int) { + val intent = Intent(act, PhotoPickActivity::class.java) + intent.putExtra(PICK_ACT_TYPE, IMG) + act.startActivityForResult(intent, code) + } + + const val PICK_ACT_RESULT = 1234566789; + private const val PERMISSION_RESULT = 123; + private const val PICK_ACT_TYPE = "PICK_ACT_TYPE"; + + const val IMG = "image/*" + const val GIF = "image/gif" + } + + var pickMedia: ActivityResultLauncher? = null + var pickMediaForDocument: ActivityResultLauncher>? = null + var mMediaType = IMG + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) +// setContentView(R.layout.activity_photo_pick) + try { + window?.setDimAmount(0f) + mMediaType = intent?.getStringExtra(PICK_ACT_TYPE) ?: IMG + pickMedia = registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri -> + if (uri != null) { + val intent = Intent() + intent.setData(uri) + setResult(RESULT_OK, intent) + // 接收方 用 intent.data 来获取 + finish() + } else { + finish() + } + } + + pickMediaForDocument = registerForActivityResult(ActivityResultContracts.OpenDocument()) { + if (it != null) { + val intent = Intent() + intent.setData(it) + setResult(RESULT_OK, intent) + } + finish() + } + + + checkStoragePermission() + } catch (e: Exception) { + R.string.error_tips.doToast() + } + } + + + private fun checkStoragePermission() { + + if (Build.VERSION.SDK_INT >= 29) { + DialogUtil.getDialog(this, object : EasyAlertDialogHelper.OnDialogActionListener { + override fun doCancelAction() { + finish() + } + + override fun doOkAction() { + try { + SPUtils.putBoolean(ConstantsLib.Key.Permissions_Img, true) + pickMedia?.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.SingleMimeType(mMediaType))) + } catch (e: Exception) { + R.string.error_tips.doToast() + } + } + }) + } else { + if (!EasyPermissions.hasPermissions(this, Manifest.permission.READ_EXTERNAL_STORAGE)) { + EasyPermissions.requestPermissions( + this, + getString(R.string.permission_storage_rationale), + PERMISSION_RESULT, + Manifest.permission.READ_EXTERNAL_STORAGE + ) + } else { +// val intent = Intent(Intent.ACTION_OPEN_DOCUMENT) +// intent.setType("*/*") +// intent.putExtra(Intent.EXTRA_MIME_TYPES,mMediaType) + try { + pickMediaForDocument?.launch(arrayOf(mMediaType)) + } catch (e: Exception) { + R.string.error_tips.doToast() + } + } + } + } + +// override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { +// super.onActivityResult(requestCode, resultCode, data) +// if (requestCode == PICK_ACT_RESULT && resultCode == RESULT_OK) { +// val uri = data?.data +// if (uri != null) { +// val intent = Intent() +// intent.setData(uri) +// setResult(RESULT_OK, intent) +// } +// } +// } + + override fun onRequestPermissionsResult( + requestCode: Int, + permissions: Array, + grantResults: IntArray + ) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) + EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this) + } + + override fun onPermissionsDenied(requestCode: Int, perms: MutableList) { + if (requestCode == PERMISSION_RESULT) { + val requestTip = getString(R.string.permission_storage_denied) + val mPrivacyDialog = CommonTipDialog(this) + mPrivacyDialog.setTipMsg(requestTip) + mPrivacyDialog.setOkText(getString(R.string.room_perform_go_update)) + mPrivacyDialog.setOnActionListener( + object : CommonTipDialog.OnActionListener { + override fun onOk() { + //同意跳到应用详情页面 + val packageUri = Uri.parse("package:${packageName}") + val intent = + Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, packageUri) + startActivity(intent) + finish() + } + + override fun onCancel() { + super.onCancel() + //取消跳到应用详情页面 + ToastUtils.show(getString(R.string.permission_storage_refused)) + finish() + } + } + ) + mPrivacyDialog.show() + } + } + + override fun onPermissionsGranted(requestCode: Int, perms: MutableList) { + if (requestCode == PERMISSION_RESULT) { + checkStoragePermission() + } + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/base/TitleBar.java b/app/src/main/java/com/chwl/app/base/TitleBar.java new file mode 100644 index 0000000..ffbce74 --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/TitleBar.java @@ -0,0 +1,609 @@ +package com.chwl.app.base; + +/** + * Created by zhouxiangfeng on 2017/4/9. + */ + + +import android.content.Context; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.graphics.drawable.Drawable; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.util.LayoutDirection; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import androidx.core.text.TextUtilsCompat; + +import com.chwl.app.R; + +import java.util.LinkedList; +import java.util.Locale; + +/** + * 类描述: + * 创建人:Bob + * 创建时间:2015/9/25 11:36 + */ +public class TitleBar extends ViewGroup implements View.OnClickListener { + private static final int DEFAULT_MAIN_TEXT_SIZE = 18; + private static final int DEFAULT_SUB_TEXT_SIZE = 12; + private static final int DEFAULT_ACTION_TEXT_SIZE = 18; + private static final int DEFAULT_TITLE_BAR_HEIGHT = 48; + + private static final String STATUS_BAR_HEIGHT_RES_NAME = "status_bar_height"; + + private TextView mLeftText; + private View mLeftView; + private RelativeLayout mLeftLayout; + private LinearLayout mRightLayout; + private LinearLayout mCenterLayout; + private TextView mCenterText; + private TextView mSubTitleText; + private View mCustomCenterView; + private View mDividerView; + + private boolean mImmersive; + + private int mScreenWidth; + private int mStatusBarHeight; + private int mActionPadding; + private int mDrawablePadding; + private int mOutPadding; + private int mActionTextColor; + private int mHeight; + + private LayoutInflater mInflater; + + public void leftTextViewUpdateScaleXForRTL() { + mLeftText.setScaleX(-1); + } + + public TitleBar(Context context) { + super(context); + init(context); + } + + public TitleBar(Context context, AttributeSet attrs) { + super(context, attrs); + init(context); + } + + public TitleBar(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context); + } + + private void init(Context context) { + mInflater = LayoutInflater.from(context); + mScreenWidth = getResources().getDisplayMetrics().widthPixels; + if (mImmersive) { + mStatusBarHeight = getStatusBarHeight(); + } + mActionPadding = dip2px(5); + mOutPadding = dip2px(10); + mDrawablePadding = dip2px(5); + mHeight = dip2px(DEFAULT_TITLE_BAR_HEIGHT); + initView(context); + } + + private void initView(Context context) { + + mLeftLayout = new RelativeLayout(context); + mCenterLayout = new LinearLayout(context); + mRightLayout = new LinearLayout(context); + mDividerView = new View(context); + + LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); + + mLeftText = new TextView(context); + mLeftText.setTextSize(DEFAULT_ACTION_TEXT_SIZE); + mLeftText.setSingleLine(); + mLeftText.setGravity(Gravity.CENTER_VERTICAL); + mLeftText.setPadding(mOutPadding + mActionPadding, 0, mOutPadding, 0); + setLeftView(mLeftText); + + mCenterText = new TextView(context); + mSubTitleText = new TextView(context); + mCenterLayout.addView(mCenterText); + mCenterLayout.addView(mSubTitleText); + + mCenterLayout.setGravity(Gravity.CENTER); + mCenterText.setTextSize(DEFAULT_MAIN_TEXT_SIZE); + mCenterText.setSingleLine(); + mCenterText.setGravity(Gravity.CENTER); + mCenterText.setEllipsize(TextUtils.TruncateAt.END); + + mSubTitleText.setTextSize(DEFAULT_SUB_TEXT_SIZE); + mSubTitleText.setSingleLine(); + mSubTitleText.setGravity(Gravity.CENTER); + mSubTitleText.setEllipsize(TextUtils.TruncateAt.END); + + mRightLayout.setPadding(mOutPadding, 0, mOutPadding, 0); + + addView(mLeftLayout, layoutParams); + addView(mCenterLayout); + addView(mRightLayout, layoutParams); + addView(mDividerView, new LayoutParams(LayoutParams.MATCH_PARENT, 1)); + + } + + public void setImmersive(boolean immersive) { + mImmersive = immersive; + if (mImmersive) { + mStatusBarHeight = getStatusBarHeight(); + } else { + mStatusBarHeight = 0; + } + } + + public void setHeight(int height) { + mHeight = height; + setMeasuredDimension(getMeasuredWidth(), mHeight); + } + + public int getmHeight() { + return mHeight; + } + + public void setLeftLayout(int leftLayout) { + if (leftLayout > 0) { + setLeftView(mInflater.inflate(leftLayout, null)); + } + } + + public void setLeftView(View leftView) { + if (leftView == null) { + return; + } + if (this.mLeftView != null) { + removeView(this.mLeftView); + } + this.mLeftView = leftView; + RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); + params.addRule(RelativeLayout.CENTER_VERTICAL); + mLeftLayout.addView(leftView, params); + } + + public void setLeftImageResource(int resId) { +// mLeftText.setBackgroundResource(resId); + mLeftText.setCompoundDrawablesWithIntrinsicBounds(resId, 0, 0, 0); + } + + public void setLeftDrawPadding(int padding) { + mLeftText.setCompoundDrawablePadding(padding); + } + + public void setLeftClickListener(OnClickListener l) { + mLeftLayout.setOnClickListener(l); + } + + public void setLeftText(CharSequence title) { + mLeftText.setText(title); + } + + public void setLeftText(int resid) { + mLeftText.setText(resid); + } + + public void setLeftTextSize(float size) { + mLeftText.setTextSize(size); + } + + public void setLeftTextColor(int color) { + mLeftText.setTextColor(color); + } + + public void setLeftVisible(boolean visible) { + mLeftText.setVisibility(visible ? View.VISIBLE : View.GONE); + } + + public void setTitle(CharSequence title) { + int index = title.toString().indexOf("\n"); + if (index > 0) { + setTitle(title.subSequence(0, index), title.subSequence(index + 1, title.length()), LinearLayout.VERTICAL); + } else { + index = title.toString().indexOf("\t"); + if (index > 0) { + setTitle(title.subSequence(0, index), " " + title.subSequence(index + 1, title.length()), LinearLayout.HORIZONTAL); + } else { + mCenterText.setText(title); + mSubTitleText.setVisibility(View.GONE); + } + } + } + + private void setTitle(CharSequence title, CharSequence subTitle, int orientation) { + mCenterLayout.setOrientation(orientation); + mCenterText.setText(title); + + mSubTitleText.setText(subTitle); + mSubTitleText.setVisibility(View.VISIBLE); + } + + public void setCenterClickListener(OnClickListener l) { + mCenterLayout.setOnClickListener(l); + } + + public void setTitle(int resid) { + setTitle(getResources().getString(resid)); + } + + public void setTitleColor(int resid) { + mCenterText.setTextColor(resid); + } + + public void setTitleSize(float size) { + mCenterText.setTextSize(size); + } + + public void setTitleBackground(int resid) { + mCenterText.setBackgroundResource(resid); + } + + public void setSubTitleColor(int resid) { + mSubTitleText.setTextColor(resid); + } + + public void setSubTitleSize(float size) { + mSubTitleText.setTextSize(size); + } + + public void setCustomTitle(View titleView) { + if (titleView == null) { + mCenterText.setVisibility(View.VISIBLE); + if (mCustomCenterView != null) { + mCenterLayout.removeView(mCustomCenterView); + } + + } else { + if (mCustomCenterView != null) { + mCenterLayout.removeView(mCustomCenterView); + } + LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); + mCustomCenterView = titleView; + mCenterLayout.addView(titleView, layoutParams); + mCenterText.setVisibility(View.GONE); + } + } + + public void setDivider(Drawable drawable) { + mDividerView.setBackgroundDrawable(drawable); + } + + public void setDividerColor(int color) { + mDividerView.setBackgroundColor(color); + } + + public void setDividerHeight(int dividerHeight) { + mDividerView.getLayoutParams().height = dividerHeight; + } + + public void setActionTextColor(int colorResId) { + mActionTextColor = colorResId; + } + + /** + * Function to set a click listener for Title TextView + * + * @param listener the onClickListener + */ + public void setOnTitleClickListener(OnClickListener listener) { + mCenterText.setOnClickListener(listener); + } + + @Override + public void onClick(View view) { + final Object tag = view.getTag(); + if (tag instanceof Action) { + final Action action = (Action) tag; + action.performAction(view); + } + } + + /** + * Adds a list of {@link Action}s. + * + * @param actionList the actions to add + */ + public void addActions(ActionList actionList) { + int actions = actionList.size(); + for (int i = 0; i < actions; i++) { + addAction(actionList.get(i)); + } + } + + /** + * Adds a new {@link Action}. + * + * @param action the action to add + */ + public View addAction(Action action) { + final int index = mRightLayout.getChildCount(); + return addAction(action, index); + } + + /** + * Adds a new {@link Action} at the specified index. + * + * @param action the action to add + * @param index the position at which to add the action + */ + public View addAction(Action action, int index) { + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, + LayoutParams.MATCH_PARENT); + View view = inflateAction(action); + view.setPadding(mActionPadding, 0, mActionPadding, 0); + view.setTag(action); + view.setOnClickListener(this); + mRightLayout.addView(view, index, params); + return view; + } + + /** + * Removes all action views from this action bar + */ + public void removeAllActions() { + mRightLayout.removeAllViews(); + } + + /** + * Remove a action from the action bar. + * + * @param index position of action to remove + */ + public void removeActionAt(int index) { + mRightLayout.removeViewAt(index); + } + + /** + * Remove a action from the action bar. + * + * @param action The action to remove + */ + public void removeAction(Action action) { + int childCount = mRightLayout.getChildCount(); + for (int i = 0; i < childCount; i++) { + View view = mRightLayout.getChildAt(i); + if (view != null) { + final Object tag = view.getTag(); + if (tag instanceof Action && tag.equals(action)) { + mRightLayout.removeView(view); + } + } + } + } + + /** + * Returns the number of actions currently registered with the action bar. + * + * @return action count + */ + public int getActionCount() { + return mRightLayout.getChildCount(); + } + + /** + * Inflates a {@link View} with the given {@link Action}. + * + * @param action the action to inflate + * @return a view + */ + private View inflateAction(Action action) { + if (TextUtils.isEmpty(action.getText())) { + ImageView img = new ImageView(getContext()); + img.setScaleType(ImageView.ScaleType.CENTER); + img.setImageResource(action.getDrawable()); + return img; + } else { + TextView text = new TextView(getContext()); + text.setGravity(Gravity.CENTER); + text.setText(action.getText()); + text.setTextColor(action.getTextColor()); + text.setTextSize(DEFAULT_ACTION_TEXT_SIZE); + if (mActionTextColor != 0) { + text.setTextColor(mActionTextColor); + } + + if (action.getTextDrawableLeft() != 0){ + Drawable drawableLeft = getResources().getDrawable(action.getTextDrawableLeft()); + text.setCompoundDrawablesWithIntrinsicBounds(drawableLeft, + null, null, null); + text.setCompoundDrawablePadding(mDrawablePadding); + } + return text; + } + } + + public View getViewByAction(Action action) { + View view = findViewWithTag(action); + return view; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int heightMode = MeasureSpec.getMode(heightMeasureSpec); + int height; + if (heightMode != MeasureSpec.EXACTLY) { + height = mHeight + mStatusBarHeight; + heightMeasureSpec = MeasureSpec.makeMeasureSpec(mHeight, MeasureSpec.EXACTLY); + } else { + height = MeasureSpec.getSize(heightMeasureSpec) + mStatusBarHeight; + } + + measureChild(mLeftLayout, widthMeasureSpec, heightMeasureSpec); + measureChild(mRightLayout, widthMeasureSpec, heightMeasureSpec); + if (mLeftLayout.getMeasuredWidth() > mRightLayout.getMeasuredWidth()) { + mCenterLayout.measure( + MeasureSpec.makeMeasureSpec(mScreenWidth - 2 * mLeftLayout.getMeasuredWidth(), MeasureSpec.EXACTLY) + , heightMeasureSpec); + } else { + mCenterLayout.measure( + MeasureSpec.makeMeasureSpec(mScreenWidth - 2 * mRightLayout.getMeasuredWidth(), MeasureSpec.EXACTLY) + , heightMeasureSpec); + } + measureChild(mDividerView, widthMeasureSpec, heightMeasureSpec); + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), height); + } + + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + if(TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault()) == LayoutDirection.RTL) { + mRightLayout.layout(0, mStatusBarHeight, mRightLayout.getMeasuredWidth(), mRightLayout.getMeasuredHeight() + mStatusBarHeight); + mLeftLayout.layout(mScreenWidth - mLeftLayout.getMeasuredWidth(), mStatusBarHeight, + mScreenWidth, mLeftLayout.getMeasuredHeight() + mStatusBarHeight); + if (mRightLayout.getMeasuredWidth() > mLeftLayout.getMeasuredWidth()) { + mCenterLayout.layout(mRightLayout.getMeasuredWidth(), mStatusBarHeight, + mScreenWidth - mRightLayout.getMeasuredWidth(), getMeasuredHeight()); + } else { + mCenterLayout.layout(mLeftLayout.getMeasuredWidth(), mStatusBarHeight, + mScreenWidth - mLeftLayout.getMeasuredWidth(), getMeasuredHeight()); + } + } else { + mLeftLayout.layout(0, mStatusBarHeight, mLeftLayout.getMeasuredWidth(), mLeftLayout.getMeasuredHeight() + mStatusBarHeight); + mRightLayout.layout(mScreenWidth - mRightLayout.getMeasuredWidth(), mStatusBarHeight, + mScreenWidth, mRightLayout.getMeasuredHeight() + mStatusBarHeight); + if (mLeftLayout.getMeasuredWidth() > mRightLayout.getMeasuredWidth()) { + mCenterLayout.layout(mLeftLayout.getMeasuredWidth(), mStatusBarHeight, + mScreenWidth - mLeftLayout.getMeasuredWidth(), getMeasuredHeight()); + } else { + mCenterLayout.layout(mRightLayout.getMeasuredWidth(), mStatusBarHeight, + mScreenWidth - mRightLayout.getMeasuredWidth(), getMeasuredHeight()); + } + } + + mDividerView.layout(0, getMeasuredHeight() - mDividerView.getMeasuredHeight(), getMeasuredWidth(), getMeasuredHeight()); + } + + public static int dip2px(int dpValue) { + final float scale = Resources.getSystem().getDisplayMetrics().density; + return (int) (dpValue * scale + 0.5f); + } + + /** + * 计算状态栏高度高度 + * getStatusBarHeight + * + * @return + */ + public static int getStatusBarHeight() { + return getInternalDimensionSize(Resources.getSystem(), STATUS_BAR_HEIGHT_RES_NAME); + } + + private static int getInternalDimensionSize(Resources res, String key) { + int result = 0; + int resourceId = res.getIdentifier(key, "dimen", "android"); + if (resourceId > 0) { + result = res.getDimensionPixelSize(resourceId); + } + return result; + } + + + /** + * A {@link LinkedList} that holds a list of {@link Action}s. + */ + @SuppressWarnings("serial") + public static class ActionList extends LinkedList { + } + + /** + * Definition of an action that could be performed, along with a icon to + * show. + */ + public interface Action { + String getText(); + + int getDrawable(); + + int getTextColor(); + + int getTextDrawableLeft(); + + void performAction(View view); + } + + public static abstract class ImageAction implements Action { + private int mDrawable; + + public ImageAction(int drawable) { + mDrawable = drawable; + } + + @Override + public int getDrawable() { + return mDrawable; + } + + @Override + public String getText() { + return null; + } + + @Override + public int getTextDrawableLeft() { + return 0; + } + + @Override + public int getTextColor() { + return 0; + } + } + + public static abstract class TextAction implements Action { + final private String mText; + final private int mTextColor; + final private int mDrawableLeft; + + + public TextAction(String text) { + mText = text; + mTextColor = 0; + mDrawableLeft = 0; + } + + public TextAction(String text,int textColor) { + mText = text; + mTextColor = textColor; + mDrawableLeft = 0; + } + + public TextAction(String text,int textColor,int drawableLeft) { + mText = text; + mTextColor = textColor; + mDrawableLeft = drawableLeft; + } + + @Override + public int getDrawable() { + return 0; + } + + @Override + public String getText() { + return mText; + } + + @Override + public int getTextColor () { + return mTextColor; + } + + @Override + public int getTextDrawableLeft() { + return mDrawableLeft; + } + + } + +} diff --git a/app/src/main/java/com/chwl/app/base/list/BaseRecyclerView.java b/app/src/main/java/com/chwl/app/base/list/BaseRecyclerView.java new file mode 100644 index 0000000..fbe3235 --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/list/BaseRecyclerView.java @@ -0,0 +1,341 @@ +package com.chwl.app.base.list; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.util.AttributeSet; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.StaggeredGridLayoutManager; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import com.trello.rxlifecycle3.LifecycleProvider; +import com.trello.rxlifecycle3.android.ActivityEvent; +import com.trello.rxlifecycle3.android.FragmentEvent; +import com.trello.rxlifecycle3.components.RxActivity; +import com.trello.rxlifecycle3.components.support.RxAppCompatActivity; +import com.trello.rxlifecycle3.components.support.RxFragment; +import com.chwl.library.utils.ListUtils; + +import java.util.ArrayList; +import java.util.List; + +import io.reactivex.Single; +import io.reactivex.SingleTransformer; + +/** + * 通用的刷新列表控件 + * Created by lvzebiao on 2018/12/13. + */ + +public abstract class BaseRecyclerView extends SwipeRefreshLayout { + + private List
headerList = new ArrayList<>(); + + private RecyclerView recyclerView; + + private Context context; + + private int page; + + private IStatusView statusView; + + private int pageSize; + + public BaseRecyclerView(@NonNull Context context) { + this(context, null); + } + + public BaseRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + this.context = context; + recyclerView = new RecyclerView(context); + LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, + LayoutParams.MATCH_PARENT); + addView(recyclerView, params); + page = 1; + loadMoreEnable = true; + statusView = createStatus(); + if (getDefalutPageSize() > 0) { + pageSize = getDefalutPageSize(); + } else { + pageSize = 15; + } + //画间距 + + } + + private WrapperAdapter wrapper; + + public void addHeader(Header header) { + headerList.add(header); + } + + public WrapperAdapter getWrapper() { + return wrapper; + } + + private CommonAdapter mInnerAdapter; + private IRecyclerListener mListener; + private LifecycleProvider mProvider; + + public void setRecyclerListener(final LifecycleProvider provider, final IRecyclerListener listener) { + if (listener == null) { + return; + } + RecyclerView.LayoutManager layoutManager = listener.createLayoutManager(); + final CommonAdapter adapter = listener.createAdapter(context); + this.mInnerAdapter = adapter; + this.mListener = listener; + this.mProvider = provider; + if (layoutManager == null) { + throw new IllegalArgumentException("you must to Override createLayoutManager methor!"); + } + if (adapter == null) { + throw new IllegalArgumentException("you must to Override createAdapter methor!"); + } + + wrapper = new WrapperAdapter(context, adapter, headerList); + if (mSpanSizeLookup != null) { + wrapper.setSpanSizeLookup(mSpanSizeLookup); + } + if (mItemDecoration != null) { + recyclerView.addItemDecoration(mItemDecoration); + } + + wrapper.setReloadListener(new WrapperAdapter.ReloadListener() { + @Override + public void onEmptyClick() { + if (isLoading) { + return; + } + wrapper.clearStatusView(); + noMoreData = false; + page = 1; + loadingData(provider, listener, adapter, true, true); + } + + @Override + public void onNetErrorClick() { + if (isLoading) { + return; + } + wrapper.clearStatusView(); + noMoreData = false; + page = 1; + loadingData(provider, listener, adapter, true, true); + } + }); + recyclerView.setLayoutManager(layoutManager); + recyclerView.setAdapter(wrapper); + + setOnRefreshListener(() -> { + if (isLoading) { + setRefreshing(false); + return; + } + noMoreData = false; + page = 1; + loadingData(provider, listener, adapter, false, true); + }); + + recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrollStateChanged(RecyclerView view, int newState) { + super.onScrollStateChanged(view, newState); + if (!loadMoreEnable) { + return; + } + if (isLoading) { + return; + } + if (noMoreData) { + return; + } + if (wrapper.isEmptyOrNetError()) { + return; + } + int itemCount = recyclerView.getAdapter().getItemCount(); + if (newState == RecyclerView.SCROLL_STATE_IDLE) { + if (recyclerView.getLayoutManager() instanceof LinearLayoutManager) { + LinearLayoutManager manager = (LinearLayoutManager) recyclerView.getLayoutManager(); + int lastVisiItem = manager.findLastVisibleItemPosition(); + if (lastVisiItem >= itemCount - 2) { + if (loadMoreListener != null) { + loadMoreListener.onLoadMore(); + } + } + } + } + } + }); + + setLoadMoreListener(new LoadMoreListener() { + @Override + public void onLoadMore() { + loadingData(provider, listener, adapter, false, false); + } + }); + + loadingData(provider, listener, adapter, true, true); + + } + + public void onRefreshList() { + page = 1; + if (mInnerAdapter == null || mListener == null) { + return; + } + loadingData(mProvider, mListener, mInnerAdapter, false, true); + } + + private boolean isLoading; + + private boolean loadMoreEnable; + + private boolean noMoreData; + + public void setLoadMoreEnable(boolean enable) { + loadMoreEnable = enable; + } + + private LoadMoreListener loadMoreListener; + + public void setLoadMoreListener(LoadMoreListener listener) { + loadMoreListener = listener; + } + + public interface LoadMoreListener { + void onLoadMore(); + } + + @SuppressLint("CheckResult") + private void loadingData(final LifecycleProvider provider, + final IRecyclerListener listener, + final CommonAdapter adapter, + final boolean startLoading, + final boolean isRefresh) { + isLoading = true; + if (startLoading) { + wrapper.startLoading(statusView.getStartLoadingView()); + } + Single> single = listener.getSingle(page, pageSize); + if (provider != null) { + single = single.compose(bindDestroy(provider)); + } + //noinspection ResultOfMethodCallIgnored + single.subscribe((list, throwable) -> { + setRefreshing(false); + isLoading = false; + if (wrapper.isEmptyOrNetError()) { + wrapper.clearStatusView(); + } + if (startLoading) { + wrapper.startLoadingComplete(); + } + wrapper.loadMoreComplete(); + if (throwable != null) { + if (page == 1 && ListUtils.isListEmpty(adapter.getData())) { + wrapper.setNetError(statusView.getNetErrorView()); + } + } else { + if (page == 1 && list.size() == 0) { + adapter.getData().clear(); + wrapper.setEmpty(statusView.getEmptyView(), listener.getEmptyTips(), listener.getEmptyResId()); + return; + } + if (isRefresh) { + adapter.getData().clear(); + adapter.getData().addAll(list); + wrapper.notifyDataSetChanged(); + } else { + int insertPos = wrapper.getItemCount() - wrapper.getStatusViewCount(); + adapter.getData().addAll(list); + wrapper.notifyItemInserted(insertPos); + } + if (loadMoreEnable) { + if (list.size() == 0) { + noMoreData = true; + } else { + noMoreData = false; + wrapper.setLoadMoreView(statusView.getLoadMoreView()); + recyclerView.post(() -> { + RecyclerView.LayoutManager manager = recyclerView.getLayoutManager(); + if (manager instanceof StaggeredGridLayoutManager) { + return; + } + if (manager instanceof LinearLayoutManager) { + int lastCplPos = ((LinearLayoutManager) manager).findLastVisibleItemPosition(); + //加个兼容,只要最后一个可视项是倒数几项,就自动加载第二页 + if (lastCplPos >= wrapper.getItemCount() - 3) { + page++; + loadingData(provider, listener, adapter, false, false); + } else { + page++; + } + } + }); + } + } + + } + }); + } + + /** + * ============================= recyclerview的属性 ================================ + */ + + public RecyclerView getRealRecyclerView() { + return recyclerView; + } + + public void setPageSize(int number) { + this.pageSize = number; + } + + private WrapperAdapter.SpanSizeLookup mSpanSizeLookup; + + public void setSpanSizeLookup(WrapperAdapter.SpanSizeLookup spanSizeLookup) { + this.mSpanSizeLookup = spanSizeLookup; + } + + private RecyclerView.ItemDecoration mItemDecoration; + + public void addItemDecoration(RecyclerView.ItemDecoration itemDecoration) { + this.mItemDecoration = itemDecoration; + } + + public abstract IStatusView createStatus(); + + public abstract int getDefalutPageSize(); + + /** + * ============================= 静态方法 ================================ + */ + + public static SingleTransformer bindDestroy(LifecycleProvider provider) { + return upstream -> { + if (provider == null) { + return upstream; + } + if (provider instanceof RxFragment) { + RxFragment fragment = (RxFragment) provider; + return upstream.compose(fragment.bindUntilEvent(FragmentEvent.DESTROY)); + } else if (provider instanceof RxAppCompatActivity) { + RxAppCompatActivity appCompatActivity = (RxAppCompatActivity) provider; + return upstream.compose(appCompatActivity.bindUntilEvent(ActivityEvent.DESTROY)); + } else if (provider instanceof RxActivity) { + RxActivity activity = (RxActivity) provider; + return upstream.compose(activity.bindUntilEvent(ActivityEvent.DESTROY)); + } else if (provider instanceof com.trello.rxlifecycle3.components.RxFragment) { + com.trello.rxlifecycle3.components.RxFragment fragment = + (com.trello.rxlifecycle3.components.RxFragment) provider; + return upstream.compose(fragment.bindUntilEvent(FragmentEvent.DESTROY)); + } + return upstream; + }; + } +} diff --git a/app/src/main/java/com/chwl/app/base/list/BaseViewHolder.java b/app/src/main/java/com/chwl/app/base/list/BaseViewHolder.java new file mode 100644 index 0000000..b6e6694 --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/list/BaseViewHolder.java @@ -0,0 +1,508 @@ +/** + * Copyright 2013 Joan Zapata + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.chwl.app.base.list; + +import android.graphics.Bitmap; +import android.graphics.Paint; +import android.graphics.Typeface; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.text.util.Linkify; +import android.util.SparseArray; +import android.view.View; +import android.view.animation.AlphaAnimation; +import android.widget.Adapter; +import android.widget.AdapterView; +import android.widget.Checkable; +import android.widget.CompoundButton; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.RatingBar; +import android.widget.TextView; + +import androidx.annotation.ColorInt; +import androidx.annotation.DrawableRes; +import androidx.annotation.IdRes; +import androidx.annotation.StringRes; +import androidx.recyclerview.widget.RecyclerView; + +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Set; + + +/** + * https://github.com/CymChad/BaseRecyclerViewAdapterHelper + */ +public class BaseViewHolder extends RecyclerView.ViewHolder { + + /** + * Views indexed with their IDs + */ + private final SparseArray views; + + public Set getNestViews() { + return nestViews; + } + + private final HashSet nestViews; + + private final LinkedHashSet childClickViewIds; + + private final LinkedHashSet itemChildLongClickViewIds; + private CommonAdapter adapter; + /** + * use itemView instead + */ + @Deprecated + public View convertView; + + /** + * Package private field to retain the associated user object and detect a change + */ + Object associatedObject; + + + public BaseViewHolder(final View view) { + super(view); + this.views = new SparseArray<>(); + this.childClickViewIds = new LinkedHashSet<>(); + this.itemChildLongClickViewIds = new LinkedHashSet<>(); + this.nestViews = new HashSet<>(); + convertView = view; + + + } + + public HashSet getItemChildLongClickViewIds() { + return itemChildLongClickViewIds; + } + + public HashSet getChildClickViewIds() { + return childClickViewIds; + } + + /** + * use itemView instead + * + * @return the ViewHolder root view + */ + @Deprecated + public View getConvertView() { + + return convertView; + } + + /** + * Will set the text of a TextView. + * + * @param viewId The view id. + * @param value The text to put in the text view. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setText(@IdRes int viewId, CharSequence value) { + TextView view = getView(viewId); + view.setText(value); + return this; + } + + public BaseViewHolder setText(@IdRes int viewId, @StringRes int strId) { + TextView view = getView(viewId); + view.setText(strId); + return this; + } + + /** + * Will set the image of an ImageView from a resource id. + * + * @param viewId The view id. + * @param imageResId The image resource id. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setImageResource(@IdRes int viewId, @DrawableRes int imageResId) { + ImageView view = getView(viewId); + view.setImageResource(imageResId); + return this; + } + + /** + * Will set background color of a view. + * + * @param viewId The view id. + * @param color A color, not a resource id. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setBackgroundColor(@IdRes int viewId, @ColorInt int color) { + View view = getView(viewId); + view.setBackgroundColor(color); + return this; + } + + /** + * Will set background of a view. + * + * @param viewId The view id. + * @param backgroundRes A resource to use as a background. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setBackgroundRes(@IdRes int viewId, @DrawableRes int backgroundRes) { + View view = getView(viewId); + view.setBackgroundResource(backgroundRes); + return this; + } + + /** + * Will set text color of a TextView. + * + * @param viewId The view id. + * @param textColor The text color (not a resource id). + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setTextColor(@IdRes int viewId, @ColorInt int textColor) { + TextView view = getView(viewId); + view.setTextColor(textColor); + return this; + } + + + /** + * Will set the image of an ImageView from a drawable. + * + * @param viewId The view id. + * @param drawable The image drawable. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setImageDrawable(@IdRes int viewId, Drawable drawable) { + ImageView view = getView(viewId); + view.setImageDrawable(drawable); + return this; + } + + /** + * Add an action to set the image of an image view. Can be called multiple times. + */ + public BaseViewHolder setImageBitmap(@IdRes int viewId, Bitmap bitmap) { + ImageView view = getView(viewId); + view.setImageBitmap(bitmap); + return this; + } + + /** + * Add an action to set the alpha of a view. Can be called multiple times. + * Alpha between 0-1. + */ + public BaseViewHolder setAlpha(@IdRes int viewId, float value) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + getView(viewId).setAlpha(value); + } else { + // Pre-honeycomb hack to set Alpha value + AlphaAnimation alpha = new AlphaAnimation(value, value); + alpha.setDuration(0); + alpha.setFillAfter(true); + getView(viewId).startAnimation(alpha); + } + return this; + } + + /** + * Set a view visibility to VISIBLE (true) or GONE (false). + * + * @param viewId The view id. + * @param visible True for VISIBLE, false for GONE. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setGone(@IdRes int viewId, boolean visible) { + View view = getView(viewId); + view.setVisibility(visible ? View.VISIBLE : View.GONE); + return this; + } + + /** + * Set a view visibility to VISIBLE (true) or INVISIBLE (false). + * + * @param viewId The view id. + * @param visible True for VISIBLE, false for INVISIBLE. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setVisible(@IdRes int viewId, boolean visible) { + View view = getView(viewId); + view.setVisibility(visible ? View.VISIBLE : View.INVISIBLE); + return this; + } + + /** + * Add links into a TextView. + * + * @param viewId The id of the TextView to linkify. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder linkify(@IdRes int viewId) { + TextView view = getView(viewId); + Linkify.addLinks(view, Linkify.ALL); + return this; + } + + /** + * Apply the typeface to the given viewId, and enable subpixel rendering. + */ + public BaseViewHolder setTypeface(@IdRes int viewId, Typeface typeface) { + TextView view = getView(viewId); + view.setTypeface(typeface); + view.setPaintFlags(view.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG); + return this; + } + + /** + * Apply the typeface to all the given viewIds, and enable subpixel rendering. + */ + public BaseViewHolder setTypeface(Typeface typeface, int... viewIds) { + for (int viewId : viewIds) { + TextView view = getView(viewId); + view.setTypeface(typeface); + view.setPaintFlags(view.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG); + } + return this; + } + + /** + * Sets the progress of a ProgressBar. + * + * @param viewId The view id. + * @param progress The progress. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setProgress(@IdRes int viewId, int progress) { + ProgressBar view = getView(viewId); + view.setProgress(progress); + return this; + } + + /** + * Sets the progress and max of a ProgressBar. + * + * @param viewId The view id. + * @param progress The progress. + * @param max The max value of a ProgressBar. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setProgress(@IdRes int viewId, int progress, int max) { + ProgressBar view = getView(viewId); + view.setMax(max); + view.setProgress(progress); + return this; + } + + /** + * Sets the range of a ProgressBar to 0...max. + * + * @param viewId The view id. + * @param max The max value of a ProgressBar. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setMax(@IdRes int viewId, int max) { + ProgressBar view = getView(viewId); + view.setMax(max); + return this; + } + + /** + * Sets the rating (the number of stars filled) of a RatingBar. + * + * @param viewId The view id. + * @param rating The rating. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setRating(@IdRes int viewId, float rating) { + RatingBar view = getView(viewId); + view.setRating(rating); + return this; + } + + /** + * Sets the rating (the number of stars filled) and max of a RatingBar. + * + * @param viewId The view id. + * @param rating The rating. + * @param max The range of the RatingBar to 0...max. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setRating(@IdRes int viewId, float rating, int max) { + RatingBar view = getView(viewId); + view.setMax(max); + view.setRating(rating); + return this; + } + + /** + * Sets the on click listener of the view. + * + * @param viewId The view id. + * @param listener The on click listener; + * @return The BaseViewHolder for chaining. + */ + @Deprecated + public BaseViewHolder setOnClickListener(@IdRes int viewId, View.OnClickListener listener) { + View view = getView(viewId); + view.setOnClickListener(listener); + return this; + } + + + /** + * Sets the on touch listener of the view. + * + * @param viewId The view id. + * @param listener The on touch listener; + * @return The BaseViewHolder for chaining. + */ + @Deprecated + public BaseViewHolder setOnTouchListener(@IdRes int viewId, View.OnTouchListener listener) { + View view = getView(viewId); + view.setOnTouchListener(listener); + return this; + } + + /** + * Sets the listview or gridview's item long click listener of the view + * + * @param viewId The view id. + * @param listener The item long click listener; + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setOnItemLongClickListener(@IdRes int viewId, AdapterView.OnItemLongClickListener listener) { + AdapterView view = getView(viewId); + view.setOnItemLongClickListener(listener); + return this; + } + + /** + * Sets the listview or gridview's item selected click listener of the view + * + * @param viewId The view id. + * @param listener The item selected click listener; + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setOnItemSelectedClickListener(@IdRes int viewId, AdapterView.OnItemSelectedListener listener) { + AdapterView view = getView(viewId); + view.setOnItemSelectedListener(listener); + return this; + } + + /** + * Sets the on checked change listener of the view. + * + * @param viewId The view id. + * @param listener The checked change listener of compound button. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setOnCheckedChangeListener(@IdRes int viewId, CompoundButton.OnCheckedChangeListener listener) { + CompoundButton view = getView(viewId); + view.setOnCheckedChangeListener(listener); + return this; + } + + /** + * Sets the tag of the view. + * + * @param viewId The view id. + * @param tag The tag; + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setTag(@IdRes int viewId, Object tag) { + View view = getView(viewId); + view.setTag(tag); + return this; + } + + /** + * Sets the tag of the view. + * + * @param viewId The view id. + * @param key The key of tag; + * @param tag The tag; + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setTag(@IdRes int viewId, int key, Object tag) { + View view = getView(viewId); + view.setTag(key, tag); + return this; + } + + /** + * Sets the checked status of a checkable. + * + * @param viewId The view id. + * @param checked The checked status; + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setChecked(@IdRes int viewId, boolean checked) { + View view = getView(viewId); + // View unable cast to Checkable + if (view instanceof Checkable) { + ((Checkable) view).setChecked(checked); + } + return this; + } + + /** + * Sets the adapter of a adapter view. + * + * @param viewId The view id. + * @param adapter The adapter; + * @return The BaseViewHolder for chaining. + */ + @SuppressWarnings("unchecked") + public BaseViewHolder setAdapter(@IdRes int viewId, Adapter adapter) { + AdapterView view = getView(viewId); + view.setAdapter(adapter); + return this; + } + + /** + * Sets the adapter of a adapter view. + * + * @param adapter The adapter; + * @return The BaseViewHolder for chaining. + */ + protected BaseViewHolder setAdapter(CommonAdapter adapter) { + this.adapter = adapter; + return this; + } + + @SuppressWarnings("unchecked") + public T getView(@IdRes int viewId) { + View view = views.get(viewId); + if (view == null) { + view = itemView.findViewById(viewId); + views.put(viewId, view); + } + return (T) view; + } + + /** + * Retrieves the last converted object on this view. + */ + public Object getAssociatedObject() { + return associatedObject; + } + + /** + * Should be called during convert + */ + public void setAssociatedObject(Object associatedObject) { + this.associatedObject = associatedObject; + } +} diff --git a/app/src/main/java/com/chwl/app/base/list/CommonAdapter.java b/app/src/main/java/com/chwl/app/base/list/CommonAdapter.java new file mode 100644 index 0000000..09fa3da --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/list/CommonAdapter.java @@ -0,0 +1,117 @@ +package com.chwl.app.base.list; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.recyclerview.widget.RecyclerView; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by lvzebiao on 2018/12/18. + */ + +public abstract class CommonAdapter extends RecyclerView.Adapter { + + private int mLayoutId; + + private List mData; + + private OnItemParentClickListener mOnItemParentClickListener; + + private OnItemChildClickListener mOnItemChildClickListener; + + private List mClickViewIds = new ArrayList<>(); + + public CommonAdapter setOnItemChildClickListener(OnItemChildClickListener onItemChildClickListener) { + this.mOnItemChildClickListener = onItemChildClickListener; + return this; + } + + public CommonAdapter addChildClickIds(int... viewIds) { + for (int index : viewIds) { + mClickViewIds.add(index); + } + return this; + } + + public CommonAdapter setOnItemClickListener(OnItemParentClickListener onItemParentClickListener) { + this.mOnItemParentClickListener = onItemParentClickListener; + return this; + } + + public CommonAdapter(int layoutId, List data) { + this.mLayoutId = layoutId; + this.mData = data == null ? new ArrayList() : data; + } + + public CommonAdapter(int layoutId) { + this(layoutId, null); + } + + @Override + public K onCreateViewHolder(ViewGroup parent, int viewType) { + return onCreateDefViewHolder(parent, viewType); + } + + protected K onCreateDefViewHolder(ViewGroup parent, int viewType) { + View view = LayoutInflater.from(parent.getContext()) + .inflate(mLayoutId, parent, false); + return createBaseViewHolder(view); + } + + public K createBaseViewHolder(View view) { + K holder = (K) new BaseViewHolder(view); + return holder; + } + + @Override + public void onBindViewHolder(K holder, int position) { + convert(holder, getItem(position)); + convert(holder, getItem(position), position); + bindClick(holder, position); + } + + private void bindClick(final K holder, final int position) { + if (mOnItemParentClickListener != null) { + holder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mOnItemParentClickListener.onItemClick(holder, getItem(position), position); + } + }); + } + if (mOnItemChildClickListener != null) { + for (int viewId : mClickViewIds) { + holder.getView(viewId).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mOnItemChildClickListener.onItemChildClick(holder, v.getId(), + getItem(position), position); + } + }); + } + } + } + + public T getItem(int position) { + return mData.get(position); + } + + @Override + public int getItemCount() { + return mData == null ? 0 : mData.size(); + } + + public List getData() { + return mData; + } + + protected abstract void convert(K holder, T item); + + protected void convert(K holder, T item, int position) { + + } +} diff --git a/app/src/main/java/com/chwl/app/base/list/DefalutStatus.java b/app/src/main/java/com/chwl/app/base/list/DefalutStatus.java new file mode 100644 index 0000000..20f262b --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/list/DefalutStatus.java @@ -0,0 +1,31 @@ +package com.chwl.app.base.list; + +import com.chwl.app.R; + +/** + * 默认列表状态view + * Created by lvzebiao on 2018/12/14. + */ + +public class DefalutStatus implements IStatusView { + + @Override + public int getStartLoadingView() { + return R.layout.item_default_common_loading_view; + } + + @Override + public int getLoadMoreView() { + return R.layout.item_default_common_load_more_view; + } + + @Override + public int getEmptyView() { + return R.layout.item_default_common_empty_view; + } + + @Override + public int getNetErrorView() { + return R.layout.item_default_common_network_error_view; + } +} diff --git a/app/src/main/java/com/chwl/app/base/list/Header.java b/app/src/main/java/com/chwl/app/base/list/Header.java new file mode 100644 index 0000000..120220e --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/list/Header.java @@ -0,0 +1,15 @@ +package com.chwl.app.base.list; + +/** + * Created by lvzebiao on 2018/12/18. + */ + +public class Header { + public int layoutId; + public IHeaderHolderListener listener; + + public Header(int layoutId, IHeaderHolderListener listener) { + this.layoutId = layoutId; + this.listener = listener; + } +} diff --git a/app/src/main/java/com/chwl/app/base/list/IHeaderHolderListener.java b/app/src/main/java/com/chwl/app/base/list/IHeaderHolderListener.java new file mode 100644 index 0000000..348a820 --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/list/IHeaderHolderListener.java @@ -0,0 +1,9 @@ +package com.chwl.app.base.list; + +/** + * Created by lvzebiao on 2018/12/18. + */ + +public interface IHeaderHolderListener { + void onViewHolder(BaseViewHolder holder); +} diff --git a/app/src/main/java/com/chwl/app/base/list/IRecyclerListener.java b/app/src/main/java/com/chwl/app/base/list/IRecyclerListener.java new file mode 100644 index 0000000..003ae48 --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/list/IRecyclerListener.java @@ -0,0 +1,34 @@ +package com.chwl.app.base.list; + +import android.content.Context; + +import androidx.recyclerview.widget.RecyclerView; + +import com.chwl.app.R; +import com.chwl.library.utils.ResUtil; + +import java.util.List; + +import io.reactivex.Single; + +/** + * Created by lvzebiao on 2018/12/13. + */ + +public interface IRecyclerListener { + + CommonAdapter createAdapter(Context context); + + RecyclerView.LayoutManager createLayoutManager(); + + Single> getSingle(int page, int size); + + default String getEmptyTips() { + return ResUtil.getString(R.string.base_list_irecyclerlistener_01); + } + + default int getEmptyResId() { + return R.drawable.icon_common_failure; + } + +} diff --git a/app/src/main/java/com/chwl/app/base/list/IStatusView.java b/app/src/main/java/com/chwl/app/base/list/IStatusView.java new file mode 100644 index 0000000..e133f83 --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/list/IStatusView.java @@ -0,0 +1,17 @@ +package com.chwl.app.base.list; + +/** + * Created by lvzebiao on 2018/12/14. + */ + +public interface IStatusView { + + int getStartLoadingView(); + + int getLoadMoreView(); + + int getEmptyView(); + + int getNetErrorView(); + +} diff --git a/app/src/main/java/com/chwl/app/base/list/LineColorDecoration.java b/app/src/main/java/com/chwl/app/base/list/LineColorDecoration.java new file mode 100644 index 0000000..2f95db3 --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/list/LineColorDecoration.java @@ -0,0 +1,96 @@ +package com.chwl.app.base.list; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.view.View; + +import androidx.recyclerview.widget.RecyclerView; + +import com.chwl.library.utils.SizeUtils; + + +/** + * 水平带颜色左右padding的分割线 + * Created by lvzebiao on 2018/10/26. + */ + +public class LineColorDecoration extends RecyclerView.ItemDecoration { + + private Context context; + private int startPos; + private Drawable drawable; + private int leftPadding; + private int rightPadding; + + /** + * 1px + */ + private int divider = 1; + /**为ture,则表示需要底部的线*/ + private boolean needBottom; + + public LineColorDecoration(Context context, int startPos, int dividerPx, int color, int leftPadding, int rightPadding, boolean bottom) { + this.context = context; + this.divider = dividerPx; + drawable = new ColorDrawable(context.getResources().getColor(color)); + this.leftPadding = SizeUtils.dp2px(context, leftPadding); + this.rightPadding = SizeUtils.dp2px(context, rightPadding); + this.startPos = startPos; + this.needBottom = bottom; + } + + public LineColorDecoration(Context context, int color, int leftPadding, int rightPadding, boolean bottom) { + this(context, 0, 1, color, leftPadding, rightPadding, bottom); + } + + public LineColorDecoration(Context context, int color, int leftPadding, int rightPadding) { + this(context, 0, 1, color, leftPadding, rightPadding, true); + } + + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { + super.getItemOffsets(outRect, view, parent, state); + int postion = parent.getChildAdapterPosition(view); + int bottom; + if (postion < startPos) { + bottom = 0; + } else if (!needBottom && postion == parent.getAdapter().getItemCount() - 1) { + bottom = 0; + } else { + bottom = divider; + } + outRect.set(0, 0, 0, bottom); + } + + @Override + public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { + super.onDraw(c, parent, state); + if (drawable == null) { + return; + } + int left = leftPadding; + int right = parent.getWidth() - rightPadding; + for (int i = 0; i < parent.getChildCount(); i++) { + View childView = parent.getChildAt(i); + RecyclerView.LayoutParams childViewParams = (RecyclerView.LayoutParams) childView.getLayoutParams(); + int position = childViewParams.getViewAdapterPosition(); + if (position < startPos) { + //头不画 + continue; + } else if (!needBottom && position == parent.getAdapter().getItemCount() - 1) { + //尾部不画 + continue; + } + //int traX = (int)(ViewCompat.getTranslationX(childView)); 偏移值,暂时没用到 + //int traY = (int)(ViewCompat.getTranslationY(childView)); + final int top = childView.getTop() + childViewParams.height; + final int bottom = top + divider; + //drawable.setBounds(left + traX, top + traY, right + traX, bottom + traY); + drawable.setBounds(left, top, right, bottom); + drawable.draw(c); + } + } +} diff --git a/app/src/main/java/com/chwl/app/base/list/LoadingViewHolder.java b/app/src/main/java/com/chwl/app/base/list/LoadingViewHolder.java new file mode 100644 index 0000000..db9462f --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/list/LoadingViewHolder.java @@ -0,0 +1,23 @@ +package com.chwl.app.base.list; + +import android.view.View; + +/** + * Created by lvzebiao on 2018/12/27. + */ + +public class LoadingViewHolder extends BaseViewHolder { + + public LoadingViewHolder(View view) { + super(view); + } + + public void startAnim() { + + } + + public void stopAnim() { + + } + +} diff --git a/app/src/main/java/com/chwl/app/base/list/MultiCommonAdapter.java b/app/src/main/java/com/chwl/app/base/list/MultiCommonAdapter.java new file mode 100644 index 0000000..e81929f --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/list/MultiCommonAdapter.java @@ -0,0 +1,42 @@ +package com.chwl.app.base.list; + +import android.util.SparseIntArray; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.LayoutRes; + +import java.util.List; + +/** + * Created by lvzebiao on 2018/12/18. + */ + +public abstract class MultiCommonAdapter extends CommonAdapter { + + private SparseIntArray layouts; + + public MultiCommonAdapter(List data) { + super(0, data); + } + + @Override + public int getItemViewType(int position) { + return getItem(position).getItemType(); + } + + @Override + public K onCreateViewHolder(ViewGroup parent, int viewType) { + int layoutId = layouts.get(viewType); + View view = LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false); + return createBaseViewHolder(view); + } + + protected void addItemType(int type, @LayoutRes int layoutResId) { + if (layouts == null) { + layouts = new SparseIntArray(); + } + layouts.put(type, layoutResId); + } +} diff --git a/app/src/main/java/com/chwl/app/base/list/MultiItemEntity.java b/app/src/main/java/com/chwl/app/base/list/MultiItemEntity.java new file mode 100644 index 0000000..d8d5def --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/list/MultiItemEntity.java @@ -0,0 +1,9 @@ +package com.chwl.app.base.list; + +/** + * Created by lvzebiao on 2018/12/18. + */ + +public interface MultiItemEntity { + int getItemType(); +} diff --git a/app/src/main/java/com/chwl/app/base/list/OnItemChildClickListener.java b/app/src/main/java/com/chwl/app/base/list/OnItemChildClickListener.java new file mode 100644 index 0000000..aa87b44 --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/list/OnItemChildClickListener.java @@ -0,0 +1,9 @@ +package com.chwl.app.base.list; + +/** + * Created by lvzebiao on 2018/12/18. + */ + +public interface OnItemChildClickListener { + void onItemChildClick(K holder, int viewId, T item, int position); +} diff --git a/app/src/main/java/com/chwl/app/base/list/OnItemParentClickListener.java b/app/src/main/java/com/chwl/app/base/list/OnItemParentClickListener.java new file mode 100644 index 0000000..826cbf9 --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/list/OnItemParentClickListener.java @@ -0,0 +1,9 @@ +package com.chwl.app.base.list; + +/** + * Created by lvzebiao on 2018/12/18. + */ + +public interface OnItemParentClickListener { + void onItemClick(K holder, T item, int position); +} diff --git a/app/src/main/java/com/chwl/app/base/list/RefreshRecyclerView.java b/app/src/main/java/com/chwl/app/base/list/RefreshRecyclerView.java new file mode 100644 index 0000000..fad0f96 --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/list/RefreshRecyclerView.java @@ -0,0 +1,34 @@ +package com.chwl.app.base.list; + +import android.content.Context; +import android.util.AttributeSet; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +/** + * Created by lvzebiao on 2018/12/28. + */ + +public class RefreshRecyclerView extends BaseRecyclerView { + + public final static int DEFALUT_SIZE = 15; + + public RefreshRecyclerView(@NonNull Context context) { + super(context); + } + + public RefreshRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + @Override + public IStatusView createStatus() { + return new DefalutStatus(); + } + + @Override + public int getDefalutPageSize() { + return DEFALUT_SIZE; + } +} diff --git a/app/src/main/java/com/chwl/app/base/list/WrapperAdapter.java b/app/src/main/java/com/chwl/app/base/list/WrapperAdapter.java new file mode 100644 index 0000000..5d7ef26 --- /dev/null +++ b/app/src/main/java/com/chwl/app/base/list/WrapperAdapter.java @@ -0,0 +1,324 @@ +package com.chwl.app.base.list; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.chwl.app.R; + +import java.util.ArrayList; +import java.util.List; + + +/** + * Created by lvzebiao on 2018/12/13. + */ + +public class WrapperAdapter extends RecyclerView.Adapter { + + private final static int VIEW_TYPE_HEADER = -10; + private final static int VIEW_TYPE_LOAD_MORE = -11; + private final static int VIEW_TYPE_NET_ERROR = -12; + private final static int VIEW_TYPE_EMPTY = -13; + private final static int VIEW_TYPE_START_LOADING = -14; + + private boolean mIsEmpty; + private boolean mIsNetError; + private boolean mIsStartLoading; + + private String emptyTips; + + private int emptyResId; + + private int mCurrentHeader = 0; + + private List

mHeaderViews = new ArrayList<>(); + + private List mStatusViews = new ArrayList<>(); + + public int getStatusViewCount() { + return mStatusViews.size(); + } + + public int getHeaderCount() { + return mHeaderViews.size(); + } + + private Integer mLoadMoreView = 0; + + private Integer mEmptyView = 0; + + private Integer mStartLoadingView = 0; + + private Integer mNetErrorView = 0; + + private RecyclerView.Adapter mInnerAdapter; + + private Context mContext; + + public WrapperAdapter(Context context, RecyclerView.Adapter adapter, List
headerViews) { + this.mInnerAdapter = adapter; + this.mHeaderViews = headerViews; + this.mContext = context; + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + int layout = 0; + if (viewType == VIEW_TYPE_HEADER) { + View view = LayoutInflater.from(mContext).inflate(mHeaderViews.get(mCurrentHeader).layoutId, parent, false); + return new BaseViewHolder(view); + } + if (viewType == VIEW_TYPE_EMPTY) { + layout = mEmptyView; + } + if (viewType == VIEW_TYPE_NET_ERROR) { + layout = mNetErrorView; + } + if (viewType == VIEW_TYPE_START_LOADING) { + layout = mStartLoadingView; + View view = LayoutInflater.from(mContext).inflate(layout, parent, false); + return new LoadingViewHolder(view); + } + if (viewType == VIEW_TYPE_LOAD_MORE) { + layout = mLoadMoreView; + } + if (layout != 0) { + View view = LayoutInflater.from(mContext).inflate(layout, parent, false); + return new BaseViewHolder(view); + } + return mInnerAdapter.onCreateViewHolder(parent, viewType); + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + if (position >= mHeaderViews.size() && position < mInnerAdapter.getItemCount() + mHeaderViews.size()) { + mInnerAdapter.onBindViewHolder(holder, position - mHeaderViews.size()); + } else if (getItemViewType(position) == VIEW_TYPE_HEADER) { + IHeaderHolderListener listener = mHeaderViews.get(position).listener; + if (listener != null) { + listener.onViewHolder((BaseViewHolder) holder); + } + } else if (getItemViewType(position) == VIEW_TYPE_EMPTY) { + holder.itemView.setOnClickListener(v -> { + if (mReloadListener != null) { + mReloadListener.onEmptyClick(); + } + }); + if (holder instanceof BaseViewHolder) { + BaseViewHolder helper = (BaseViewHolder) holder; + View textView = helper.getView(R.id.no_data_text); + if (textView != null && textView instanceof TextView) { + helper.setText(R.id.no_data_text, emptyTips); + } + View imageView = helper.getView(R.id.no_data_icon); + if (imageView != null && imageView instanceof ImageView && emptyResId != 0) { + helper.setImageResource(R.id.no_data_icon, emptyResId); + } + } + } else if (getItemViewType(position) == VIEW_TYPE_NET_ERROR) { + holder.itemView.setOnClickListener(v -> { + if (mReloadListener != null) { + mReloadListener.onNetErrorClick(); + } + }); + } else if (getItemViewType(position) == VIEW_TYPE_START_LOADING) { + if (holder instanceof LoadingViewHolder) { + ((LoadingViewHolder) holder).startAnim(); + } + } else { + holder.itemView.setOnClickListener(null); + } + } + + private ReloadListener mReloadListener; + + public void setReloadListener(ReloadListener reloadListener) { + this.mReloadListener = reloadListener; + } + + public interface ReloadListener { + void onEmptyClick(); + + void onNetErrorClick(); + } + + @Override + public void onViewDetachedFromWindow(RecyclerView.ViewHolder holder) { + super.onViewDetachedFromWindow(holder); + if (holder instanceof LoadingViewHolder) { + ((LoadingViewHolder) holder).stopAnim(); + } + } + + @Override + public int getItemViewType(int position) { + if (mHeaderViews.size() > 0 && position < mHeaderViews.size()) { + mCurrentHeader = position; + return VIEW_TYPE_HEADER; + } + if (mInnerAdapter.getItemCount() == 0) { + if (mIsEmpty) { + return VIEW_TYPE_EMPTY; + } else if (mIsNetError) { + return VIEW_TYPE_NET_ERROR; + } else { + return VIEW_TYPE_START_LOADING; + } + } + if (position >= mInnerAdapter.getItemCount() + mHeaderViews.size()) { + return VIEW_TYPE_LOAD_MORE; + } + return mInnerAdapter.getItemViewType(position - mHeaderViews.size()); + } + + @Override + public int getItemCount() { + return mHeaderViews.size() + mInnerAdapter.getItemCount() + mStatusViews.size(); + } + + public void setLoadMoreView(int layoutId) { + if (layoutId == 0) { + return; + } + mLoadMoreView = layoutId; + if (!mStatusViews.contains(mLoadMoreView)) { + int insertPos = getItemCount(); + mStatusViews.add(mLoadMoreView); + notifyItemInserted(insertPos); + } + } + + public void loadMoreComplete() { + if (mLoadMoreView <= 0) { + return; + } + if (mStatusViews.contains(mLoadMoreView)) { + int removePos = getItemCount() - 1; + mStatusViews.remove(mLoadMoreView); + notifyItemRemoved(removePos); + } + } + + public void setEmpty(int layoutId, String emptyTips, int emptyResId) { + reset(); + this.mIsEmpty = true; + if (layoutId <= 0) { + return; + } + mEmptyView = layoutId; + this.emptyTips = emptyTips; + this.emptyResId = emptyResId; + if (!mStatusViews.contains(mEmptyView)) { + mStatusViews.add(mEmptyView); + notifyDataSetChanged(); + } + } + + public void setNetError(int layoutId) { + reset(); + this.mIsNetError = true; + if (layoutId <= 0) { + return; + } + mNetErrorView = layoutId; + if (!mStatusViews.contains(mNetErrorView)) { + mStatusViews.add(mNetErrorView); + notifyDataSetChanged(); + } + } + + public void startLoading(int layoutId) { + reset(); + this.mIsStartLoading = true; + if (layoutId <= 0) { + return; + } + mStartLoadingView = layoutId; + if (!mStatusViews.contains(mStartLoadingView)) { + mStatusViews.add(mStartLoadingView); + notifyDataSetChanged(); + } + } + + public void startLoadingComplete() { + reset(); + this.mIsStartLoading = false; + if (mStartLoadingView <= 0) { + return; + } + if (mStatusViews.contains(mStartLoadingView)) { + mStatusViews.remove(mStartLoadingView); + notifyDataSetChanged(); + } + } + + private void reset() { + this.mIsEmpty = false; + this.mIsNetError = false; + this.mIsStartLoading = false; + } + + public void clearStatusView() { + reset(); + if (mStatusViews.size() > 0) { + mStatusViews.clear(); + notifyDataSetChanged(); + } + } + + public boolean isEmptyOrNetError() { + return mIsEmpty || mIsNetError; + } + + @Override + public void onAttachedToRecyclerView(RecyclerView recyclerView) { + super.onAttachedToRecyclerView(recyclerView); + RecyclerView.LayoutManager manager = recyclerView.getLayoutManager(); + if (manager instanceof GridLayoutManager) { + final GridLayoutManager gridLayoutManager = (GridLayoutManager) manager; + gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { + @Override + public int getSpanSize(int position) { + if (isHeader(position) || isFullSpanView(position)) { + return gridLayoutManager.getSpanCount(); + } + if (mSpanSizeLookup != null) { + return mSpanSizeLookup.getSpanSize(gridLayoutManager, position - mHeaderViews.size()); + } else { + return 1; + } + } + }); + } + } + + private boolean isHeader(int position) { + return mHeaderViews.size() > 0 && position < mHeaderViews.size(); + } + + private boolean isFullSpanView(int position) { + int viewType = getItemViewType(position); + return viewType == VIEW_TYPE_LOAD_MORE || + viewType == VIEW_TYPE_EMPTY || + viewType == VIEW_TYPE_START_LOADING || + viewType == VIEW_TYPE_NET_ERROR; + } + + + private SpanSizeLookup mSpanSizeLookup; + + public void setSpanSizeLookup(SpanSizeLookup spanSizeLookup) { + this.mSpanSizeLookup = spanSizeLookup; + } + + public interface SpanSizeLookup { + int getSpanSize(GridLayoutManager gridLayoutManager, int position); + } +} diff --git a/app/src/main/java/com/chwl/app/bills/activities/BillBaseActivity.java b/app/src/main/java/com/chwl/app/bills/activities/BillBaseActivity.java new file mode 100644 index 0000000..46f7d88 --- /dev/null +++ b/app/src/main/java/com/chwl/app/bills/activities/BillBaseActivity.java @@ -0,0 +1,185 @@ +package com.chwl.app.bills.activities; + +import android.annotation.SuppressLint; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.databinding.ViewDataBinding; +import androidx.recyclerview.widget.RecyclerView; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import com.jzxiang.pickerview.TimePickerDialog; +import com.jzxiang.pickerview.data.Type; +import com.jzxiang.pickerview.listener.OnDateSetListener; +import com.chwl.app.R; +import com.chwl.app.base.BaseBindingActivity; +import com.chwl.app.bills.adapter.BillBaseAdapter; +import com.chwl.app.common.NoDataFragment; +import com.chwl.core.Constants; +import com.chwl.core.bills.bean.BillItemEntity; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.TimeUtils; + +import java.util.ArrayList; +import java.util.List; + +/** + *

账单base activity

+ * + * @author Administrator + * @date 2017/11/6 + */ +public abstract class BillBaseActivity extends BaseBindingActivity + implements OnDateSetListener, View.OnClickListener { + protected BillBaseActivity mActivity; + private TextView mTvDate; + private ImageView mIvSelectorDate; + protected RecyclerView mRecyclerView; + private ImageView mIvTodaySelect; + protected SwipeRefreshLayout mRefreshLayout; + protected BillBaseAdapter adapter; + + protected int mCurrentCounter = Constants.PAGE_START; + protected static final int PAGE_SIZE = Constants.BILL_PAGE_SIZE; + protected TimePickerDialog.Builder mDialogYearMonthDayBuild; + protected long time = System.currentTimeMillis(); + protected List mBillItemEntityList = new ArrayList<>(); + + protected int getLayout() { + return R.layout.activity_bills; + } + + @Override + protected void init() { + mActivity = this; + initView(); + initData(); + setListener(); + } + + protected void initView() { + mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView); + mRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh); + mTvDate = (TextView) findViewById(R.id.tv_date); + mIvTodaySelect = (ImageView) findViewById(R.id.iv_today_select); + mIvSelectorDate = (ImageView) findViewById(R.id.tv_selector_date); + +// mRecyclerView = mBinding.recyclerView; +// mRefreshLayout = mBinding.swipeRefresh; +// mTvDate = mBinding.tvDate; +// mIvTodaySelect = mBinding.ivTodaySelect; +// mIvSelectorDate = mBinding.tvSelectorDate; + } + + protected void initData() { + setDate(System.currentTimeMillis()); + mDialogYearMonthDayBuild = new TimePickerDialog.Builder() + .setType(Type.YEAR_MONTH_DAY) + .setTitleStringId(ResUtil.getString(R.string.bills_activities_billbaseactivity_01)) + .setThemeColor(getResources().getColor(R.color.line_background)) + .setWheelItemTextNormalColor(getResources().getColor(R.color + .timetimepicker_default_text_color)) + .setWheelItemTextSelectorColor(getResources().getColor(R.color.black)) + .setCallBack(mActivity); + } + + protected void setDate(long time) { + mTvDate.setText(TimeUtils.getDateTimeString(time, "yyyy-MM-dd")); + } + + protected abstract void loadData(); + + protected void setListener() { + mIvTodaySelect.setOnClickListener(this); + mIvSelectorDate.setOnClickListener(this); + mRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { + @Override + public void onRefresh() { + mCurrentCounter = Constants.PAGE_START; +// time = System.currentTimeMillis(); + loadData(); + } + }); + } + + @Override + public void showNetworkErr() { + mRefreshLayout.setRefreshing(false); + super.showNetworkErr(); + } + + public void onGetDataError(String error) { + if (mCurrentCounter == Constants.PAGE_START) { + showNetworkErr(); + } else { + adapter.loadMoreFail(); + } + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.iv_today_select: + mCurrentCounter = Constants.PAGE_START; + time = System.currentTimeMillis(); + setDate(time); + showLoading(); + loadData(); + break; + case R.id.tv_selector_date: + mDialogYearMonthDayBuild.build().show(getSupportFragmentManager(), "year_month_day"); + break; + default: + } + } + + @Override + public void onDateSet(TimePickerDialog timePickerView, long millseconds) { + this.time = millseconds; + setDate(millseconds); + mCurrentCounter = Constants.PAGE_START; + showLoading(); + loadData(); + } + + @Override + public void showNoData(CharSequence charSequence) { + this.showNoData(R.drawable.icon_common_failure, charSequence); + } + + @SuppressLint("ResourceType") + @Override + public void showNoData(int drawable, CharSequence charSequence) { + if (!checkActivityValid()) { + return; + } + + View status = findViewById(R.id.status_layout); + if (status == null || status.getId() <= 0) { + return; + } + NoDataFragment fragment = NoDataFragment.newInstance(R.layout.fragment_no_data_large_iv, drawable, charSequence); + fragment.setListener(getLoadListener()); + getSupportFragmentManager().beginTransaction().replace(status.getId(), fragment, STATUS_TAG).commitAllowingStateLoss(); + } + + @Override + public View.OnClickListener getLoadListener() { + return v -> { + mCurrentCounter = Constants.PAGE_START; + showLoading(); + loadData(); + }; + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (mDialogYearMonthDayBuild != null) { + mDialogYearMonthDayBuild.setCallBack(null); + mDialogYearMonthDayBuild = null; + } + } + +} diff --git a/app/src/main/java/com/chwl/app/bills/activities/BillGiftExpendActivity.java b/app/src/main/java/com/chwl/app/bills/activities/BillGiftExpendActivity.java new file mode 100644 index 0000000..b595ef0 --- /dev/null +++ b/app/src/main/java/com/chwl/app/bills/activities/BillGiftExpendActivity.java @@ -0,0 +1,187 @@ +package com.chwl.app.bills.activities; + +import android.annotation.SuppressLint; +import android.text.TextUtils; +import android.view.View; +import android.widget.TextView; + +import com.chwl.app.R; +import com.chwl.app.base.TitleBar; +import com.chwl.app.bills.adapter.GiftExpendAdapter; +import com.chwl.app.databinding.ActivityBillsGiftBinding; +import com.chwl.app.ui.pay.ChargeActivity; +import com.chwl.app.ui.widget.RecyclerViewNoBugLinearLayoutManager; +import com.chwl.core.Constants; +import com.chwl.core.bills.BillModel; +import com.chwl.core.bills.bean.BillItemEntity; +import com.chwl.core.bills.bean.ExpendInfo; +import com.chwl.core.bills.bean.ExpendListInfo; +import com.chwl.core.pay.PayModel; +import com.chwl.core.pay.bean.WalletInfo; +import com.chwl.library.annatation.ActLayoutRes; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + *

账单礼物支出界面

+ * + * @author Administrator + * @date 2017/11/6 + */ +@ActLayoutRes(R.layout.activity_bills_gift) +public class BillGiftExpendActivity extends BillBaseActivity { +// private GiftExpendAdapter adapter; + private TextView mGoldNum; + + @Override + protected void initView() { + super.initView(); + mGoldNum = (TextView) findViewById(R.id.tv_gold_num); + } + + @Override + protected void initData() { + super.initData(); + initTitleBar(getString(R.string.bill_gift_expend)); + + adapter = new GiftExpendAdapter(mBillItemEntityList); + adapter.setOnLoadMoreListener(() -> { + mCurrentCounter++; + loadData(); + }, mRecyclerView); + RecyclerViewNoBugLinearLayoutManager manager = new RecyclerViewNoBugLinearLayoutManager(mActivity); + mRecyclerView.setLayoutManager(manager); + mRecyclerView.setAdapter(adapter); + showLoading(); + onLoadGoldNum(); + loadData(); + } + + private void onLoadGoldNum() { + WalletInfo walletInfo = PayModel.get().getCurrentWalletInfo(); + if (null != walletInfo) { + mGoldNum.setText(getString(R.string.bill_gift_gold_num, walletInfo.getDiamondNum())); + } + } + + @SuppressLint("CheckResult") + @Override + protected void loadData() { + BillModel.get() + .getGiftExpendBills(mCurrentCounter, PAGE_SIZE, time) + .compose(bindToLifecycle()) + .subscribe((expendResult, throwable) -> { + if (throwable != null) { + BillGiftExpendActivity.this.onGetDataError(throwable.getMessage()); + } else if (expendResult != null && expendResult.isSuccess()) { + BillGiftExpendActivity.this.onGetExpendBills(expendResult.getData()); + } else if (expendResult != null) { + BillGiftExpendActivity.this.onGetDataError(expendResult.getError()); + } + }); + } + + public void onGetExpendBills(ExpendListInfo data) { + mRefreshLayout.setRefreshing(false); + if (null != data) { + if (mCurrentCounter == Constants.PAGE_START) { + hideStatus(); + mBillItemEntityList.clear(); + adapter.setNewData(mBillItemEntityList); + } else { + adapter.loadMoreComplete(); + } + List>> billList = data.getBillList(); + if (!billList.isEmpty()) { + List billItemEntities = new ArrayList<>(); + int size = mBillItemEntityList.size(); + BillItemEntity billItemEntity; + for (int i = 0; i < billList.size(); i++) { + Map> map = billList.get(i); + for (String key : map.keySet()) { + // key ---日期 value:list集合记录 + List expendInfos = map.get(key); + if (ListUtils.isListEmpty(expendInfos)) continue; + //标题 + if (size > 0) { + BillItemEntity lastBillItem = mBillItemEntityList.get(size - 1); + //时间不一致才会添加标题 + if (!TextUtils.equals(lastBillItem.time, key)) { + billItemEntity = new BillItemEntity(BillItemEntity.ITEM_DATE, key); + billItemEntities.add(billItemEntity); + } + } else { + billItemEntity = new BillItemEntity(BillItemEntity.ITEM_DATE, key); + billItemEntities.add(billItemEntity); + } + + //正常item + for (ExpendInfo temp : expendInfos) { + billItemEntity = new BillItemEntity(BillItemEntity.ITEM_NORMAL); + //目的是为了比较 + billItemEntity.time = key; + billItemEntity.mGiftExpendInfo = temp; + billItemEntities.add(billItemEntity); + } + } + } + if (billItemEntities.size() < Constants.BILL_PAGE_SIZE && mCurrentCounter == Constants.PAGE_START) { + adapter.setEnableLoadMore(false); + } + + adapter.addData(billItemEntities); + } else { + if (mCurrentCounter == Constants.PAGE_START) { + showNoData(R.drawable.icon_common_failure, ResUtil.getString(R.string.bills_activities_billgiftexpendactivity_01)); + } else { + adapter.loadMoreEnd(true); + } + } + } + } + +// public void onGetExpendBillsError(String error) { +// if (mCurrentCounter == Constants.PAGE_START) { +// showNetworkErr(); +// } else { +// adapter.loadMoreFail(); +// } +// } + + @Override + public void initTitleBar(String title) { + mTitleBar = (TitleBar) findViewById(R.id.title_bar); + if (mTitleBar != null) { + mTitleBar.setTitle(title); + mTitleBar.setImmersive(false); + mTitleBar.setTitleColor(getResources().getColor(R.color.back_font)); + mTitleBar.setLeftImageResource(R.drawable.arrow_left); + mTitleBar.setLeftClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); + } + mTitleBar.setActionTextColor(getResources().getColor(R.color.text_tertiary)); + mTitleBar.addAction(new TitleBar.TextAction(ResUtil.getString(R.string.bills_activities_billgiftexpendactivity_02)) { + @Override + public void performAction(View view) { +// if(AppMetaDataUtil.getChannelID().equals(Constants.GOOGLE)) { + ChargeActivity.start(mActivity); +// }else { +// CommonWebViewActivity.start( +// mActivity, UriProvider.getOfficialPay( +// 4, +// DeviceUtil.getDeviceId(mActivity) +// ) +// ); +// } + } + }); + } +} diff --git a/app/src/main/java/com/chwl/app/bills/activities/BillGiftInComeActivity.java b/app/src/main/java/com/chwl/app/bills/activities/BillGiftInComeActivity.java new file mode 100644 index 0000000..747ce3d --- /dev/null +++ b/app/src/main/java/com/chwl/app/bills/activities/BillGiftInComeActivity.java @@ -0,0 +1,213 @@ +package com.chwl.app.bills.activities; + +import android.annotation.SuppressLint; +import android.text.TextUtils; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chwl.app.R; +import com.chwl.app.base.TitleBar; +import com.chwl.app.bills.adapter.GiftIncomeAdapter; +import com.chwl.app.databinding.ActivityBillsGiftBinding; +import com.chwl.app.ui.pay.ChargeActivity; +import com.chwl.app.ui.widget.RecyclerViewNoBugLinearLayoutManager; +import com.chwl.core.Constants; +import com.chwl.core.bills.BillModel; +import com.chwl.core.bills.bean.BillItemEntity; +import com.chwl.core.bills.bean.IncomeInfo; +import com.chwl.core.bills.bean.IncomeListInfo; +import com.chwl.core.pay.PayModel; +import com.chwl.core.pay.bean.WalletInfo; +import com.chwl.library.annatation.ActLayoutRes; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + *

账单礼物收入界面

+ * + * @author Administrator + * @date 2017/11/7 + */ +@ActLayoutRes(R.layout.activity_bills_gift) +public class BillGiftInComeActivity extends BillBaseActivity { +// private GiftIncomeAdapter adapter; + private TextView mGoldNum; + private ImageView iv_goto_top; + + @Override + protected void init() { + super.init(); + initTitleBar(getString(R.string.bill_gift_income)); + } + + @Override + protected void initView() { + super.initView(); + mGoldNum = (TextView) findViewById(R.id.tv_gold_num); + iv_goto_top = findViewById(R.id.iv_goto_top); + iv_goto_top.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + try { + mRecyclerView.smoothScrollToPosition(0); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + + @Override + protected void initData() { + super.initData(); + adapter = new GiftIncomeAdapter(mBillItemEntityList); + adapter.setOnLoadMoreListener(new BaseQuickAdapter.RequestLoadMoreListener() { + @Override + public void onLoadMoreRequested() { + mCurrentCounter++; + loadData(); + } + }, mRecyclerView); + + RecyclerViewNoBugLinearLayoutManager manager = new RecyclerViewNoBugLinearLayoutManager(mActivity); + mRecyclerView.setLayoutManager(manager); + mRecyclerView.setAdapter(adapter); + + firstLoadDate(); + } + + private void firstLoadDate() { + mCurrentCounter = Constants.PAGE_START; + showLoading(); + onLoadGoldNum(); + loadData(); + } + + @SuppressLint("CheckResult") + @Override + protected void loadData() { + BillModel.get() + .getGiftIncomeBills(mCurrentCounter, PAGE_SIZE, time) + .compose(bindToLifecycle()) + .subscribe((incomedResult, throwable) -> { + if (throwable != null) { + onGetDataError(throwable.getMessage()); + } else if (incomedResult != null && incomedResult.isSuccess()) { + onGetIncomeBills(incomedResult.getData()); + } else if (incomedResult != null) { + onGetDataError(incomedResult.getError()); + } + }); + } + + private void onLoadGoldNum() { + WalletInfo walletInfo = PayModel.get().getCurrentWalletInfo(); + if (null != walletInfo) { + mGoldNum.setText(getString(R.string.bill_gift_gold_num, walletInfo.getDiamondNum())); + } + } + + public void onGetIncomeBills(IncomeListInfo data) { + mRefreshLayout.setRefreshing(false); + if (null != data) { + if (mCurrentCounter == Constants.PAGE_START) { + hideStatus(); + mBillItemEntityList.clear(); + adapter.setNewData(mBillItemEntityList); + } else { + adapter.loadMoreComplete(); + } + List>> billList = data.getBillList(); + if (!billList.isEmpty()) { + int size = mBillItemEntityList.size(); + List billItemEntities = new ArrayList<>(); + BillItemEntity billItemEntity; + for (int i = 0; i < billList.size(); i++) { + Map> map = billList.get(i); + for (String key : map.keySet()) { + // key ---日期 value:list集合记录 + List incomeInfos = map.get(key); + if (ListUtils.isListEmpty(incomeInfos)) continue; + + //标题 + if (size > 0) { + BillItemEntity lastBillItem = mBillItemEntityList.get(size - 1); + //时间不一致才会添加标题 + if (!TextUtils.equals(lastBillItem.time, key)) { + billItemEntity = new BillItemEntity(BillItemEntity.ITEM_DATE, key); + billItemEntities.add(billItemEntity); + } + } else { + billItemEntity = new BillItemEntity(BillItemEntity.ITEM_DATE, key); + billItemEntities.add(billItemEntity); + } + + //正常item + for (IncomeInfo temp : incomeInfos) { + billItemEntity = new BillItemEntity(BillItemEntity.ITEM_NORMAL); + billItemEntity.mGiftInComeInfo = temp; + //目的是为了比较 + billItemEntity.time = key; + billItemEntities.add(billItemEntity); + } + } + } + if (billItemEntities.size() < Constants.BILL_PAGE_SIZE && mCurrentCounter == Constants.PAGE_START) { + adapter.setEnableLoadMore(false); + } + adapter.addData(billItemEntities); + } else { + if (mCurrentCounter == Constants.PAGE_START) { + showNoData(R.drawable.icon_common_failure, ResUtil.getString(R.string.bills_activities_billgiftincomeactivity_01)); + } else { + adapter.loadMoreEnd(true); + } + } + } + } + + @Override + public void initTitleBar(String title) { + TitleBar mTitleBar = (TitleBar) findViewById(R.id.title_bar); + if (mTitleBar != null) { + mTitleBar.setTitle(title); + mTitleBar.setImmersive(false); + mTitleBar.setTitleColor(getResources().getColor(R.color.back_font)); + mTitleBar.setLeftImageResource(R.drawable.arrow_left); + mTitleBar.setLeftClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); + } + mTitleBar.setActionTextColor(getResources().getColor(R.color.text_tertiary)); + mTitleBar.addAction(new TitleBar.TextAction(ResUtil.getString(R.string.bills_activities_billgiftincomeactivity_02)) { + @Override + public void performAction(View view) { +// if(AppMetaDataUtil.getChannelID().equals(Constants.GOOGLE)) { + ChargeActivity.start(mActivity); +// }else { +// CommonWebViewActivity.start( +// mActivity, UriProvider.getOfficialPay( +// 4, +// DeviceUtil.getDeviceId(mActivity) +// ) +// ); +// } + } + }); + } + + @Override + public void onReloadDate() { + super.onReloadDate(); + firstLoadDate(); + } +} diff --git a/app/src/main/java/com/chwl/app/bills/activities/BillGiftIncomeGroupActivity.java b/app/src/main/java/com/chwl/app/bills/activities/BillGiftIncomeGroupActivity.java new file mode 100644 index 0000000..fc3b411 --- /dev/null +++ b/app/src/main/java/com/chwl/app/bills/activities/BillGiftIncomeGroupActivity.java @@ -0,0 +1,148 @@ +package com.chwl.app.bills.activities; + +import static com.chwl.app.bills.fragmemt.RadishGiftFragment.TYPE_RADISH_EXPAND; +import static com.chwl.app.bills.fragmemt.RadishGiftFragment.TYPE_RADISH_INCOME; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.fragment.app.Fragment; +import androidx.viewpager.widget.ViewPager; + +import com.chwl.app.R; +import com.chwl.app.avroom.adapter.RoomContributeListAdapter; +import com.chwl.app.base.BaseMvpActivity; +import com.chwl.app.base.TitleBar; +import com.chwl.app.bills.fragmemt.GiftIncomeFragment; +import com.chwl.app.bills.fragmemt.GiftOutputFragment; +import com.chwl.app.bills.fragmemt.RadishGiftFragment; +import com.chwl.app.bills.presenter.BillGiftIncomeGroupPresenter; +import com.chwl.app.bills.view.IBillGiftIncomeGroupView; +import com.chwl.app.bills.view.ISmoothToTopView; +import com.chwl.app.bills.widget.BillGiftIncomeGroupNavigatorAdapter; +import com.chwl.app.ui.pay.ChargeActivity; +import com.chwl.app.ui.webview.CommonWebViewActivity; +import com.chwl.app.ui.widget.magicindicator.MagicIndicator; +import com.chwl.app.ui.widget.magicindicator.ViewPagerHelper; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.CommonNavigator; +import com.chwl.core.Constants; +import com.chwl.core.UriProvider; +import com.chwl.library.base.factory.CreatePresenter; +import com.chwl.library.common.util.DeviceUtil; +import com.chwl.library.utils.AppMetaDataUtil; +import com.chwl.library.utils.ResUtil; + +import java.util.ArrayList; + +@CreatePresenter(BillGiftIncomeGroupPresenter.class) +public class BillGiftIncomeGroupActivity extends BaseMvpActivity + implements IBillGiftIncomeGroupView, CommonNavigator.NavigatorSelectedListener { + + public static final byte TYPE_BILL_INCOME = 1; + public static final byte TYPE_BILL_OUTPUT = 2; + private static final String FLAG_TYPE_BILL = "type_bill"; + private byte mType = TYPE_BILL_INCOME; + + private TextView mGoldNum; + private ImageView iv_goto_top; + private ViewPager mViewPager; + + public static void startActivity(Context context, byte type) { + Intent intent = new Intent(context, BillGiftIncomeGroupActivity.class); + intent.putExtra(FLAG_TYPE_BILL, type); + context.startActivity(intent); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + StatusBarLightModes(true); + setContentView(R.layout.activity_bill_gift_income_group); + + mType = getIntent().getByteExtra(FLAG_TYPE_BILL, TYPE_BILL_INCOME); + + initTitleBar(mType == TYPE_BILL_INCOME ? ResUtil.getString(R.string.bills_activities_billgiftincomegroupactivity_01) : ResUtil.getString(R.string.bills_activities_billgiftincomegroupactivity_02)); + + mGoldNum = findViewById(R.id.tv_gold_num); + iv_goto_top = findViewById(R.id.iv_goto_top); + iv_goto_top.setOnClickListener(v -> smoothToTop()); + + mViewPager = findViewById(R.id.vp_bill_gift_income_group); + MagicIndicator viewIndicator = findViewById(R.id.mi_bill); + + ArrayList fragments = new ArrayList<>(2); + + if (mType == TYPE_BILL_INCOME) { + fragments.add(GiftIncomeFragment.newInstance()); + fragments.add(RadishGiftFragment.newInstance(TYPE_RADISH_INCOME)); + } else { + fragments.add(GiftOutputFragment.newInstance()); + fragments.add(RadishGiftFragment.newInstance(TYPE_RADISH_EXPAND)); + } + mViewPager.setAdapter(new RoomContributeListAdapter(getSupportFragmentManager(), fragments)); + + CommonNavigator commonNavigator = new CommonNavigator(this); + commonNavigator.setAdjustMode(true); + commonNavigator.setmNavigatorSelectedListener(this); + + BillGiftIncomeGroupNavigatorAdapter indicator = new BillGiftIncomeGroupNavigatorAdapter(); + indicator.setOnItemSelectListener(position -> mViewPager.setCurrentItem(position)); + commonNavigator.setAdapter(indicator); + viewIndicator.setNavigator(commonNavigator); + ViewPagerHelper.bind(viewIndicator, mViewPager); + } + + private void smoothToTop() { + try { + + if (mViewPager != null) { + int position = mViewPager.getCurrentItem(); + RoomContributeListAdapter roomConsumeListAdapter = (RoomContributeListAdapter) mViewPager.getAdapter(); + + if (roomConsumeListAdapter != null) { + ISmoothToTopView iSmoothToTopView = (ISmoothToTopView) roomConsumeListAdapter.getItem(position); + + if (iSmoothToTopView != null) + iSmoothToTopView.smoothScrollToTop(); + } + } + + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void showRightOption(boolean show) { + if (mTitleBar.getActionCount() > 0) + mTitleBar.removeActionAt(0); + + if (show) { + mTitleBar.addAction(new TitleBar.TextAction(ResUtil.getString(R.string.bills_activities_billgiftincomegroupactivity_03)) { + @Override + public void performAction(View view) { +// if(AppMetaDataUtil.getChannelID().equals(Constants.GOOGLE)) { + startActivity(new Intent(BillGiftIncomeGroupActivity.this, ChargeActivity.class)); +// }else { +// CommonWebViewActivity.start( +// context, UriProvider.getOfficialPay( +// 4, +// DeviceUtil.getDeviceId(context) +// ) +// ); +// } + } + }); + } + + } + + @Override + public void navigatorSelected(int position) { + showRightOption(position == 0); // 钻石礼物显示充值按钮 + } +} diff --git a/app/src/main/java/com/chwl/app/bills/activities/BillNobleActivity.java b/app/src/main/java/com/chwl/app/bills/activities/BillNobleActivity.java new file mode 100644 index 0000000..fff8494 --- /dev/null +++ b/app/src/main/java/com/chwl/app/bills/activities/BillNobleActivity.java @@ -0,0 +1,155 @@ +package com.chwl.app.bills.activities; + +import android.annotation.SuppressLint; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; +import android.widget.ImageView; + +import com.chwl.app.R; +import com.chwl.app.bills.adapter.NobleBillAdapter; +import com.chwl.app.databinding.ActivityBillsBinding; +import com.chwl.app.ui.widget.RecyclerViewNoBugLinearLayoutManager; +import com.chwl.core.Constants; +import com.chwl.core.bills.BillModel; +import com.chwl.core.bills.bean.BillItemEntity; +import com.chwl.core.bills.bean.NobleBillListInfo; +import com.chwl.library.annatation.ActLayoutRes; +import com.chwl.library.utils.ListUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + *

贵族开通记录

+ * + * @author jiahui + * @date 2018/1/10 + */ +@ActLayoutRes(R.layout.activity_bills) +public class BillNobleActivity extends BillBaseActivity { + private NobleBillAdapter mNobleBillAdapter; + + private ImageView iv_goto_top; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + initTitleBar(getString(R.string.bill_noble_open)); + } + + @Override + protected void initView() { + super.initView(); + iv_goto_top = findViewById(R.id.iv_goto_top); + iv_goto_top.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + try { + mRecyclerView.smoothScrollToPosition(0); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + + @Override + protected void initData() { + super.initData(); + mNobleBillAdapter = new NobleBillAdapter(mBillItemEntityList); + mNobleBillAdapter.setOnLoadMoreListener(() -> { + mCurrentCounter++; + loadData(); + }, mRecyclerView); + RecyclerViewNoBugLinearLayoutManager manager = new RecyclerViewNoBugLinearLayoutManager(mActivity); + mRecyclerView.setLayoutManager(manager); + mRecyclerView.setAdapter(mNobleBillAdapter); + showLoading(); + loadData(); + } + + @SuppressLint("CheckResult") + @Override + protected void loadData() { + BillModel.get() + .loadNobleBillRecords(time, mCurrentCounter) + .compose(bindToLifecycle()) + .subscribe((nobleBillListInfo, throwable) -> { + if (throwable != null) { + onGetDataError(throwable.getMessage()); + } else { + onLoadNobleRecordSuccess(nobleBillListInfo); + } + }); + + } + +// public void onLoadNobleRecordFail() { +// if (mCurrentCounter == Constants.PAGE_START) { +// showNetworkErr(); +// } else { +// mNobleBillAdapter.loadMoreFail(); +// } +// } + + public void onLoadNobleRecordSuccess(NobleBillListInfo nobleBillListInfo) { + mRefreshLayout.setRefreshing(false); + if (null != nobleBillListInfo) { + if (mCurrentCounter == Constants.PAGE_START) { + hideStatus(); + mBillItemEntityList.clear(); + mNobleBillAdapter.setNewData(mBillItemEntityList); + } else { + mNobleBillAdapter.loadMoreComplete(); + } + + List>> billList = nobleBillListInfo.billList; + if (!billList.isEmpty()) { + int size = mBillItemEntityList.size(); + List billItemEntities = new ArrayList<>(); + BillItemEntity billItemEntity; + for (int i = 0; i < billList.size(); i++) { + Map> map = billList.get(i); + for (String key : map.keySet()) { + // key ---日期 value:list集合记录 + List nobleBillInfoList = map.get(key); + if (ListUtils.isListEmpty(nobleBillInfoList)) continue; + //标题 + if (size > 0) { + BillItemEntity lastBillItem = (BillItemEntity) mBillItemEntityList.get(size - 1); + //时间不一致才会添加标题 + if (!TextUtils.equals(lastBillItem.time, key)) { + billItemEntity = new BillItemEntity(BillItemEntity.ITEM_DATE, key); + billItemEntities.add(billItemEntity); + } + } else { + billItemEntity = new BillItemEntity(BillItemEntity.ITEM_DATE, key); + billItemEntities.add(billItemEntity); + } + + //正常item + for (NobleBillListInfo.NobleBillInfo temp : nobleBillInfoList) { + billItemEntity = new BillItemEntity(BillItemEntity.ITEM_NORMAL); + billItemEntity.nobleBillInfo = temp; + //目的是为了比较 + billItemEntity.time = key; + billItemEntities.add(billItemEntity); + } + } + } + if (billItemEntities.size() < Constants.BILL_PAGE_SIZE && mCurrentCounter == Constants.PAGE_START) { + mNobleBillAdapter.setEnableLoadMore(false); + } + mNobleBillAdapter.addData(billItemEntities); + } else { + if (mCurrentCounter == 1) { + showNoData(R.drawable.icon_common_failure, getResources().getString(R.string.bill_no_data_text)); + } else { + mNobleBillAdapter.loadMoreEnd(true); + } + } + } + } +} diff --git a/app/src/main/java/com/chwl/app/bills/activities/ChargeBillsActivity.java b/app/src/main/java/com/chwl/app/bills/activities/ChargeBillsActivity.java new file mode 100644 index 0000000..d11007b --- /dev/null +++ b/app/src/main/java/com/chwl/app/bills/activities/ChargeBillsActivity.java @@ -0,0 +1,198 @@ +package com.chwl.app.bills.activities; + +import android.annotation.SuppressLint; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; +import android.widget.ImageView; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chwl.app.R; +import com.chwl.app.base.TitleBar; +import com.chwl.app.bills.adapter.ChargeBillsAdapter; +import com.chwl.app.databinding.ActivityBillsBinding; +import com.chwl.app.ui.pay.ChargeActivity; +import com.chwl.app.ui.widget.RecyclerViewNoBugLinearLayoutManager; +import com.chwl.core.XConstants; +import com.chwl.core.Constants; +import com.chwl.core.bills.BillModel; +import com.chwl.core.bills.bean.BillItemEntity; +import com.chwl.core.bills.bean.ExpendInfo; +import com.chwl.core.bills.bean.ExpendListInfo; +import com.chwl.library.annatation.ActLayoutRes; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * 充值记录 + */ +@ActLayoutRes(R.layout.activity_bills) +public class ChargeBillsActivity extends BillBaseActivity { + private TitleBar mTitleBar; +// private ChargeBillsAdapter adapter; + + private ImageView iv_goto_top; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + initTitleBar(ResUtil.getString(R.string.bills_activities_chargebillsactivity_01)); + } + + @Override + protected void initView() { + super.initView(); + iv_goto_top = findViewById(R.id.iv_goto_top); + iv_goto_top.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + try { + mRecyclerView.smoothScrollToPosition(0); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + + @Override + protected void initData() { + super.initData(); + adapter = new ChargeBillsAdapter(mBillItemEntityList); + adapter.setOnLoadMoreListener(new BaseQuickAdapter.RequestLoadMoreListener() { + @Override + public void onLoadMoreRequested() { + mCurrentCounter++; + loadData(); + } + }, mRecyclerView); + adapter.addFooterView(View.inflate(context, R.layout.layout_bills_bottom, null)); + RecyclerViewNoBugLinearLayoutManager manager = new RecyclerViewNoBugLinearLayoutManager(mActivity); + mRecyclerView.setLayoutManager(manager); + mRecyclerView.setAdapter(adapter); + showLoading(); + loadData(); + } + + @SuppressLint("CheckResult") + @Override + protected void loadData() { + BillModel.get() + .getChargeBills(mCurrentCounter, PAGE_SIZE, time) + .compose(bindToLifecycle()) + .subscribe((chargeResult, throwable) -> { + if (throwable != null) { + onGetDataError(throwable.getMessage()); + } else if (chargeResult != null && chargeResult.isSuccess()) { + onGetChargeBills(chargeResult.getData()); + } else if (chargeResult != null) { + onGetDataError(chargeResult.getError()); + } + }); + } + + public void onGetChargeBills(ExpendListInfo data) { + mRefreshLayout.setRefreshing(false); + if (null != data) { + if (mCurrentCounter == Constants.PAGE_START) { + hideStatus(); + mBillItemEntityList.clear(); + adapter.setNewData(mBillItemEntityList); + } else { + adapter.loadMoreComplete(); + } + + BillItemEntity billItemEntity; + List>> billList = data.getBillList(); + if (!billList.isEmpty()) { + int size = mBillItemEntityList.size(); + List billItemEntities = new ArrayList<>(); + for (int i = 0; i < billList.size(); i++) { + Map> map = billList.get(i); + for (String key : map.keySet()) { + // key ---日期 value:list集合记录 + List expendInfos = map.get(key); + if (ListUtils.isListEmpty(expendInfos)) { + continue; + } + //标题 + if (size > 0) { + BillItemEntity lastBillItem = (BillItemEntity) mBillItemEntityList.get(size - 1); + if (!TextUtils.equals(lastBillItem.time, key)) { //时间不一致才会添加标题 + billItemEntity = new BillItemEntity(BillItemEntity.ITEM_DATE, key); + billItemEntities.add(billItemEntity); + } + } else { + billItemEntity = new BillItemEntity(BillItemEntity.ITEM_DATE, key); + billItemEntities.add(billItemEntity); + } + + //正常item + for (ExpendInfo temp : expendInfos) { + billItemEntity = new BillItemEntity(BillItemEntity.ITEM_NORMAL); + billItemEntity.mChargeExpendInfo = temp; + billItemEntity.time = key; //目的是为了比较 + billItemEntities.add(billItemEntity); + } + } + } + if (billItemEntities.size() < Constants.BILL_PAGE_SIZE && mCurrentCounter == Constants.PAGE_START) { + adapter.setEnableLoadMore(false); + } + adapter.addData(billItemEntities); + } else { + if (mCurrentCounter == Constants.PAGE_START) { + showNoData(R.drawable.icon_common_failure, ResUtil.getString(R.string.yizhuan_xchat_android_constants_xchatconstants_017)); + } else { + adapter.loadMoreEnd(true); + } + } + } + } + + + @Override + public void initTitleBar(String title) { + mTitleBar = (TitleBar) findViewById(R.id.title_bar); + if (mTitleBar != null) { + mTitleBar.setTitle(title); + mTitleBar.setImmersive(false); + mTitleBar.setTitleColor(getResources().getColor(R.color.back_font)); + mTitleBar.setLeftImageResource(R.drawable.arrow_left); + mTitleBar.setLeftClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); + } + mTitleBar.setActionTextColor(getResources().getColor(R.color.text_tertiary)); + mTitleBar.addAction(new TitleBar.TextAction(ResUtil.getString(R.string.bills_activities_chargebillsactivity_02)) { + @Override + public void performAction(View view) { +// if(AppMetaDataUtil.getChannelID().equals(Constants.GOOGLE)) { + ChargeActivity.start(mActivity); +// }else { +// CommonWebViewActivity.start( +// mActivity, UriProvider.getOfficialPay( +// 4, +// DeviceUtil.getDeviceId(mActivity) +// ) +// ); +// } + } + }); + } + +// public void onGetChargeBillsError(String error) { +// if (mCurrentCounter == Constants.PAGE_START) { +// showNetworkErr(); +// } else { +// adapter.loadMoreFail(); +// } +// } +} diff --git a/app/src/main/java/com/chwl/app/bills/activities/ChatBillsActivity.java b/app/src/main/java/com/chwl/app/bills/activities/ChatBillsActivity.java new file mode 100644 index 0000000..2293b02 --- /dev/null +++ b/app/src/main/java/com/chwl/app/bills/activities/ChatBillsActivity.java @@ -0,0 +1,161 @@ +package com.chwl.app.bills.activities; + +import android.annotation.SuppressLint; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; +import android.widget.ImageView; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chwl.app.R; +import com.chwl.app.bills.adapter.ChatBillsAdapter; +import com.chwl.app.databinding.ActivityBillsBinding; +import com.chwl.app.ui.widget.RecyclerViewNoBugLinearLayoutManager; +import com.chwl.core.Constants; +import com.chwl.core.bills.BillModel; +import com.chwl.core.bills.bean.BillItemEntity; +import com.chwl.core.bills.bean.IncomeInfo; +import com.chwl.core.bills.bean.IncomeListInfo; +import com.chwl.library.annatation.ActLayoutRes; +import com.chwl.library.utils.ListUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * 竞拍记录 + * + * @author Administrator + */ +@ActLayoutRes(R.layout.activity_bills) +public class ChatBillsActivity extends BillBaseActivity { +// private ChatBillsAdapter adapter; + + private ImageView iv_goto_top; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + initTitleBar(getString(R.string.menu_my_auction)); + } + + @Override + protected void initView() { + super.initView(); + iv_goto_top = findViewById(R.id.iv_goto_top); + iv_goto_top.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + try { + mRecyclerView.smoothScrollToPosition(0); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + + @Override + protected void initData() { + super.initData(); + adapter = new ChatBillsAdapter(mBillItemEntityList); + adapter.setOnLoadMoreListener(new BaseQuickAdapter.RequestLoadMoreListener() { + @Override + public void onLoadMoreRequested() { + mCurrentCounter++; + loadData(); + } + }, mRecyclerView); + RecyclerViewNoBugLinearLayoutManager manager = new RecyclerViewNoBugLinearLayoutManager(mActivity); + mRecyclerView.setLayoutManager(manager); + mRecyclerView.setAdapter(adapter); + showLoading(); + loadData(); + } + + + @SuppressLint("CheckResult") + @Override + protected void loadData() { + BillModel.get() + .getChatBills(mCurrentCounter, PAGE_SIZE, time) + .compose(bindToLifecycle()) + .subscribe((incomedResult, throwable) -> { + if (throwable != null) { + onGetDataError(throwable.getMessage()); + } else if (incomedResult != null && incomedResult.isSuccess()) { + onGetOrderIncomeBills(incomedResult.getData()); + } else if (incomedResult != null) { + onGetDataError(incomedResult.getError()); + } + }); + } + + public void onGetOrderIncomeBills(IncomeListInfo data) { + mRefreshLayout.setRefreshing(false); + if (null != data) { + if (mCurrentCounter == Constants.PAGE_START) { + hideStatus(); + mBillItemEntityList.clear(); + adapter.setNewData(mBillItemEntityList); + } else { + adapter.loadMoreComplete(); + } + + List>> billList = data.getBillList(); + if (!billList.isEmpty()) { + int size = mBillItemEntityList.size(); + List billItemEntities = new ArrayList<>(); + BillItemEntity billItemEntity; + for (int i = 0; i < billList.size(); i++) { + Map> map = billList.get(i); + for (String key : map.keySet()) { + // key ---日期 value:list集合记录 + List incomeInfos = map.get(key); + if (ListUtils.isListEmpty(incomeInfos)) continue; + //标题 + if (size > 0) { + BillItemEntity lastBillItem = mBillItemEntityList.get(size - 1); + //时间不一致才会添加标题 + if (!TextUtils.equals(lastBillItem.time, key)) { + billItemEntity = new BillItemEntity(BillItemEntity.ITEM_DATE, key); + billItemEntities.add(billItemEntity); + } + } else { + billItemEntity = new BillItemEntity(BillItemEntity.ITEM_DATE, key); + billItemEntities.add(billItemEntity); + } + + //正常item + for (IncomeInfo temp : incomeInfos) { + billItemEntity = new BillItemEntity(BillItemEntity.ITEM_NORMAL); + billItemEntity.mChatInComeInfo = temp; + //目的是为了比较 + billItemEntity.time = key; + billItemEntities.add(billItemEntity); + } + } + } + if (billItemEntities.size() < Constants.BILL_PAGE_SIZE && mCurrentCounter == Constants.PAGE_START) { + adapter.setEnableLoadMore(false); + } + adapter.addData(billItemEntities); + } else { + if (mCurrentCounter == 1) { + showNoData(getResources().getString(R.string.bill_no_data_text)); + } else { + adapter.loadMoreEnd(true); + } + } + } + } + +// public void onGetOrderIncomeBillsError(String error) { +// if (mCurrentCounter == Constants.PAGE_START) { +// showNetworkErr(); +// } else { +// adapter.loadMoreFail(); +// } +// } +} diff --git a/app/src/main/java/com/chwl/app/bills/activities/RedBagBillsActivity.java b/app/src/main/java/com/chwl/app/bills/activities/RedBagBillsActivity.java new file mode 100644 index 0000000..8ad5a63 --- /dev/null +++ b/app/src/main/java/com/chwl/app/bills/activities/RedBagBillsActivity.java @@ -0,0 +1,190 @@ +package com.chwl.app.bills.activities; + +import android.annotation.SuppressLint; +import android.content.Intent; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; +import android.widget.ImageView; + +import com.chwl.app.R; +import com.chwl.app.base.TitleBar; +import com.chwl.app.bills.adapter.RedBagBillsAdapter; +import com.chwl.app.databinding.ActivityBillsBinding; +import com.chwl.app.ui.pay.ChargeActivity; +import com.chwl.app.ui.webview.CommonWebViewActivity; +import com.chwl.app.ui.widget.RecyclerViewNoBugLinearLayoutManager; +import com.chwl.core.Constants; +import com.chwl.core.UriProvider; +import com.chwl.core.bills.BillModel; +import com.chwl.core.bills.bean.BillItemEntity; +import com.chwl.core.bills.bean.RedBagInfo; +import com.chwl.core.bills.bean.RedBagListInfo; +import com.chwl.library.annatation.ActLayoutRes; +import com.chwl.library.common.util.DeviceUtil; +import com.chwl.library.utils.AppMetaDataUtil; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * 红包记录 + * + * @author Administrator + */ +@ActLayoutRes(R.layout.activity_bills) +public class RedBagBillsActivity extends BillBaseActivity { + +// private RedBagBillsAdapter adapter; + + private ImageView iv_goto_top; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + initTitleBar(getString(R.string.bill_red)); + } + + @Override + public void initTitleBar(String title) { + mTitleBar = mBinding.titleBar; + if (mTitleBar != null) { + mTitleBar.setTitle(title); + mTitleBar.setImmersive(false); + mTitleBar.setTitleColor(getResources().getColor(R.color.back_font)); + mTitleBar.setLeftImageResource(R.drawable.icon_user_back_black); + mTitleBar.setLeftClickListener(v -> finish()); + } + mTitleBar.setActionTextColor(getResources().getColor(R.color.text_tertiary)); + mTitleBar.addAction(new TitleBar.TextAction(ResUtil.getString(R.string.bills_activities_redbagbillsactivity_01)) { + @Override + public void performAction(View view) { +// if(AppMetaDataUtil.getChannelID().equals(Constants.GOOGLE)) { + startActivity(new Intent(RedBagBillsActivity.this, ChargeActivity.class)); +// }else { +// CommonWebViewActivity.start( +// context, UriProvider.getOfficialPay( +// 4, +// DeviceUtil.getDeviceId(context) +// ) +// ); +// } + } + }); + } + + @Override + protected void initView() { + super.initView(); + iv_goto_top = findViewById(R.id.iv_goto_top); + iv_goto_top.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + try { + mRecyclerView.smoothScrollToPosition(0); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + + @Override + protected void initData() { + super.initData(); + adapter = new RedBagBillsAdapter(mBillItemEntityList); + adapter.setOnLoadMoreListener(() -> { + mCurrentCounter++; + loadData(); + }, mRecyclerView); + RecyclerViewNoBugLinearLayoutManager manager = new RecyclerViewNoBugLinearLayoutManager(mActivity); + mRecyclerView.setLayoutManager(manager); + mRecyclerView.setAdapter(adapter); + showLoading(); + loadData(); + } + + @SuppressLint("CheckResult") + @Override + protected void loadData() { + BillModel.get() + .getRedBagBills(mCurrentCounter, PAGE_SIZE, time) + .compose(bindToLifecycle()) + .subscribe((redBagResult, throwable) -> { + if (throwable != null) { + onGetDataError(throwable.getMessage()); + } else if (redBagResult != null && redBagResult.isSuccess()) { + onGetRedBagBills(redBagResult.getData()); + } else if (redBagResult != null) { + onGetDataError(redBagResult.getError()); + } + }); + } + + public void onGetRedBagBills(RedBagListInfo data) { + mRefreshLayout.setRefreshing(false); + if (null != data) { + if (mCurrentCounter == Constants.PAGE_START) { + hideStatus(); + mBillItemEntityList.clear(); + adapter.setNewData(mBillItemEntityList); + } else { + adapter.loadMoreComplete(); + } + BillItemEntity billItemEntity; + List>> billList = data.getBillList(); + if (!billList.isEmpty()) { + int size = mBillItemEntityList.size(); + List billItemEntities = new ArrayList<>(); + for (int i = 0; i < billList.size(); i++) { + Map> map = billList.get(i); + for (String key : map.keySet()) { + // key ---日期 value:list集合记录 + List redBagInfos = map.get(key); + if (ListUtils.isListEmpty(redBagInfos)) continue; + //标题 + if (size > 0) { + BillItemEntity lastBillItem = mBillItemEntityList.get(size - 1); + if (!TextUtils.equals(lastBillItem.time, key)) { //时间不一致才会添加标题 + billItemEntity = new BillItemEntity(BillItemEntity.ITEM_DATE, key); + billItemEntities.add(billItemEntity); + } + } else { + billItemEntity = new BillItemEntity(BillItemEntity.ITEM_DATE, key); + billItemEntities.add(billItemEntity); + } + + //正常item + for (RedBagInfo temp : redBagInfos) { + billItemEntity = new BillItemEntity(BillItemEntity.ITEM_NORMAL); + billItemEntity.mRedBagInfo = temp; + billItemEntity.time = key; //目的是为了比较 + billItemEntities.add(billItemEntity); + } + } + } + if (billItemEntities.size() < Constants.BILL_PAGE_SIZE && mCurrentCounter == Constants.PAGE_START) { + adapter.setEnableLoadMore(false); + } + adapter.addData(billItemEntities); + } else { + if (mCurrentCounter == 1) { + showNoData(ResUtil.getString(R.string.bills_activities_redbagbillsactivity_02)); + } else { + adapter.loadMoreEnd(true); + } + } + } + } + +// public void onGetRedBagBillsError(String error) { +// if (mCurrentCounter == Constants.PAGE_START) { +// showNetworkErr(); +// } else { +// adapter.loadMoreFail(); +// } +// } +} diff --git a/app/src/main/java/com/chwl/app/bills/activities/TotalBillsActivity.java b/app/src/main/java/com/chwl/app/bills/activities/TotalBillsActivity.java new file mode 100644 index 0000000..0dd8ede --- /dev/null +++ b/app/src/main/java/com/chwl/app/bills/activities/TotalBillsActivity.java @@ -0,0 +1,80 @@ +package com.chwl.app.bills.activities; + +import android.content.Intent; +import android.os.Bundle; +import android.view.View; + +import com.chwl.app.R; +import com.chwl.app.base.BaseActivity; +import com.chwl.app.bills.widget.BillItemView; + +/** + * @author Administrator + */ +public class TotalBillsActivity extends BaseActivity implements View.OnClickListener { + private BillItemView mBillGiftInCome, mBillGiftExpend; + private BillItemView mBillChat; + private BillItemView mBillCharge; + private BillItemView mBillRed; + private BillItemView mBillNoble; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_total_bills); + initTitleBar(getString(R.string.bill_title)); + initView(); + initData(); + setListener(); + } + + private void initView() { + mBillGiftInCome = (BillItemView) findViewById(R.id.bill_item_income); + mBillGiftExpend = (BillItemView) findViewById(R.id.bill_item_expend); + mBillChat = (BillItemView) findViewById(R.id.bill_item_chat); + mBillCharge = (BillItemView) findViewById(R.id.bill_item_charge); + mBillRed = (BillItemView) findViewById(R.id.bill_item_red); + mBillNoble = (BillItemView) findViewById(R.id.bill_item_noble); + } + + private void initData() { + + } + + + private void setListener() { + mBillGiftInCome.setOnClickListener(this); + mBillGiftExpend.setOnClickListener(this); + mBillChat.setOnClickListener(this); + mBillCharge.setOnClickListener(this); + mBillRed.setOnClickListener(this); + mBillNoble.setOnClickListener(this); + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.bill_item_income: +// startActivity(new Intent(this, BillGiftInComeActivity.class)); + BillGiftIncomeGroupActivity.startActivity(this, BillGiftIncomeGroupActivity.TYPE_BILL_INCOME); + break; + case R.id.bill_item_expend: +// startActivity(new Intent(this, BillGiftExpendActivity.class)); + BillGiftIncomeGroupActivity.startActivity(this, BillGiftIncomeGroupActivity.TYPE_BILL_OUTPUT); + break; + case R.id.bill_item_chat: + startActivity(new Intent(this, ChatBillsActivity.class)); + break; + case R.id.bill_item_charge: + startActivity(new Intent(this, ChargeBillsActivity.class)); + break; + case R.id.bill_item_red: + startActivity(new Intent(this, RedBagBillsActivity.class)); + break; + case R.id.bill_item_noble: + startActivity(new Intent(this, BillNobleActivity.class)); + break; + default: + } + } +} diff --git a/app/src/main/java/com/chwl/app/bills/adapter/BillBaseAdapter.java b/app/src/main/java/com/chwl/app/bills/adapter/BillBaseAdapter.java new file mode 100644 index 0000000..1b4e735 --- /dev/null +++ b/app/src/main/java/com/chwl/app/bills/adapter/BillBaseAdapter.java @@ -0,0 +1,40 @@ +package com.chwl.app.bills.adapter; + +import com.chad.library.adapter.base.BaseMultiItemQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.core.bills.bean.BillItemEntity; +import com.chwl.library.utils.TimeUtils; + +import java.util.List; + +/** + *

账单adapter base

+ * Created by Administrator on 2017/11/6. + */ +public abstract class BillBaseAdapter extends BaseMultiItemQuickAdapter { + + public BillBaseAdapter(List billItemEntityList) { + super(billItemEntityList); + addItemType(BillItemEntity.ITEM_DATE, R.layout.list_income_gift_title); + } + + @Override + protected void convert(BaseViewHolder baseViewHolder, BillItemEntity billItemEntity) { + if (billItemEntity == null) { + return; + } + switch (billItemEntity.getItemType()) { + case BillItemEntity.ITEM_DATE: + baseViewHolder.setText(R.id.tv_date, + TimeUtils.getDateTimeString(Long.parseLong(billItemEntity.time), "yyyy-MM-dd")); + break; + case BillItemEntity.ITEM_NORMAL: + convertNormal(baseViewHolder, billItemEntity); + break; + default: + } + } + + public abstract void convertNormal(BaseViewHolder baseViewHolder, BillItemEntity billItemEntity); +} diff --git a/app/src/main/java/com/chwl/app/bills/adapter/ChargeBillsAdapter.java b/app/src/main/java/com/chwl/app/bills/adapter/ChargeBillsAdapter.java new file mode 100644 index 0000000..aa46914 --- /dev/null +++ b/app/src/main/java/com/chwl/app/bills/adapter/ChargeBillsAdapter.java @@ -0,0 +1,33 @@ +package com.chwl.app.bills.adapter; + +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.core.bills.bean.BillItemEntity; +import com.chwl.core.bills.bean.ExpendInfo; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.TimeUtils; + +import java.util.List; + +/** + * 充值记录 ExpendInfo + * Created by ${Seven} on 2017/9/15. + */ +public class ChargeBillsAdapter extends BillBaseAdapter { + + public ChargeBillsAdapter(List billItemEntityList) { + super(billItemEntityList); + addItemType(BillItemEntity.ITEM_NORMAL, R.layout.list_charge_bills_item); + } + + @Override + public void convertNormal(BaseViewHolder baseViewHolder, BillItemEntity billItemEntity) { + ExpendInfo expendInfo = billItemEntity.mChargeExpendInfo; + if (expendInfo == null) { + return; + } + baseViewHolder.setText(R.id.tv_gold, ResUtil.getString(R.string.bills_adapter_chargebillsadapter_01) + expendInfo.getGoldNum() + ResUtil.getString(R.string.diamond)) + .setText(R.id.tv_money, expendInfo.getShowStr()) + .setText(R.id.tv_charge_time, TimeUtils.getYearMonthDayHourMinuteSecond(expendInfo.getRecordTime())); + } +} diff --git a/app/src/main/java/com/chwl/app/bills/adapter/ChatBillsAdapter.java b/app/src/main/java/com/chwl/app/bills/adapter/ChatBillsAdapter.java new file mode 100644 index 0000000..05241d0 --- /dev/null +++ b/app/src/main/java/com/chwl/app/bills/adapter/ChatBillsAdapter.java @@ -0,0 +1,41 @@ +package com.chwl.app.bills.adapter; + +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.app.common.widget.CircleImageView; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.bills.bean.BillItemEntity; +import com.chwl.core.bills.bean.IncomeInfo; +import com.chwl.library.utils.TimeUtils; + +import java.util.List; + +/** + * IncomeInfo + * Created by Seven on 2017/9/18. + */ +public class ChatBillsAdapter extends BillBaseAdapter { + + public ChatBillsAdapter(List billItemEntityList) { + super(billItemEntityList); + addItemType(BillItemEntity.ITEM_NORMAL, R.layout.list_order_bills_item); + } + + @Override + public void convertNormal(BaseViewHolder baseViewHolder, BillItemEntity billItemEntity) { + IncomeInfo incomeInfo = billItemEntity.mChatInComeInfo; + if (incomeInfo == null) return; + baseViewHolder.setVisible(R.id.rly_gold, true) + .setText(R.id.tv_user_pro, incomeInfo.getTargetNick() + "&" + incomeInfo.getUserNick()) + .setText(R.id.tv_date, TimeUtils.getYearMonthDayHourMinuteSecond(incomeInfo.getRecordTime())) + .setText(R.id.tv_gold, incomeInfo.getGoldNum() != 0 + ? String.valueOf(incomeInfo.getGoldNum()) : "+" + incomeInfo.getDiamondNum()) + .setText(R.id.tv_bill_type, incomeInfo.getGoldNum() != 0 + ? mContext.getString(R.string.gift_expend_gold) : mContext.getString(R.string.gift_income_gold)); + + CircleImageView userAvatar = baseViewHolder.getView(R.id.user_avatar); + CircleImageView proAvatar = baseViewHolder.getView(R.id.pro_avatar); + ImageLoadUtils.loadAvatar(mContext, incomeInfo.getUserAvatar(), userAvatar); + ImageLoadUtils.loadAvatar(mContext, incomeInfo.getTargetAvatar(), proAvatar); + } +} diff --git a/app/src/main/java/com/chwl/app/bills/adapter/GiftExpendAdapter.java b/app/src/main/java/com/chwl/app/bills/adapter/GiftExpendAdapter.java new file mode 100644 index 0000000..2f23451 --- /dev/null +++ b/app/src/main/java/com/chwl/app/bills/adapter/GiftExpendAdapter.java @@ -0,0 +1,40 @@ +package com.chwl.app.bills.adapter; + +import android.widget.ImageView; + +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.bills.bean.BillItemEntity; +import com.chwl.core.bills.bean.ExpendInfo; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.TimeUtils; + +import java.util.List; + +/** + * ExpendInfo + * Created by Seven on 2017/9/10. + */ +public class GiftExpendAdapter extends BillBaseAdapter { + + public GiftExpendAdapter(List billItemEntityList) { + super(billItemEntityList); + addItemType(BillItemEntity.ITEM_NORMAL, R.layout.list_expend_gift_item); + } + + @Override + public void convertNormal(BaseViewHolder baseViewHolder, BillItemEntity billItemEntity) { + ExpendInfo expendInfo = billItemEntity.mGiftExpendInfo; + if (expendInfo == null) return; + baseViewHolder.setText(R.id.tv_gift_income, + mContext.getString(R.string.gift_out_gold_number_format, expendInfo.getGoldNum())) + .setText(R.id.tv_send_name, ResUtil.getString(R.string.bills_adapter_giftexpendadapter_01) + expendInfo.getTargetNick()) + .setText(R.id.tv_user_name, expendInfo.getGiftName()) + .setText(R.id.gift_date, TimeUtils.getDateTimeString(expendInfo.getRecordTime(), "HH:mm:ss")) + .setText(R.id.gold, R.string.gift_expend_gold); + + ImageView img_avatar = baseViewHolder.getView(R.id.img_avatar); + ImageLoadUtils.loadImage(mContext, expendInfo.getGiftPic(), img_avatar); + } +} diff --git a/app/src/main/java/com/chwl/app/bills/adapter/GiftIncomeAdapter.java b/app/src/main/java/com/chwl/app/bills/adapter/GiftIncomeAdapter.java new file mode 100644 index 0000000..a298095 --- /dev/null +++ b/app/src/main/java/com/chwl/app/bills/adapter/GiftIncomeAdapter.java @@ -0,0 +1,39 @@ +package com.chwl.app.bills.adapter; + +import android.widget.ImageView; + +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.bills.bean.BillItemEntity; +import com.chwl.core.bills.bean.IncomeInfo; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.TimeUtils; + +import java.util.List; + +/** + * Created by Seven on 2017/9/11. + */ + +public class GiftIncomeAdapter extends BillBaseAdapter { + + public GiftIncomeAdapter(List billItemEntityList) { + super(billItemEntityList); + addItemType(BillItemEntity.ITEM_NORMAL, R.layout.list_expend_gift_item); + } + + @Override + public void convertNormal(BaseViewHolder baseViewHolder, BillItemEntity billItemEntity) { + IncomeInfo incomeInfo = billItemEntity.mGiftInComeInfo; + if (incomeInfo == null) return; + baseViewHolder.setText(R.id.tv_gift_income, + mContext.getString(R.string.gift_in_gold_number_format, incomeInfo.getDiamondNum())) + .setText(R.id.tv_send_name, ResUtil.getString(R.string.bills_adapter_giftincomeadapter_01) + incomeInfo.getTargetNick()) + .setText(R.id.tv_user_name, incomeInfo.getGiftName()) + .setText(R.id.gift_date, TimeUtils.getDateTimeString(incomeInfo.getRecordTime(), "HH:mm:ss")) + .setText(R.id.gold, R.string.gift_income_gold); + ImageView avatar = baseViewHolder.getView(R.id.img_avatar); + ImageLoadUtils.loadImage(mContext, incomeInfo.getGiftPic(), avatar); + } +} diff --git a/app/src/main/java/com/chwl/app/bills/adapter/NobleBillAdapter.java b/app/src/main/java/com/chwl/app/bills/adapter/NobleBillAdapter.java new file mode 100644 index 0000000..f5bd071 --- /dev/null +++ b/app/src/main/java/com/chwl/app/bills/adapter/NobleBillAdapter.java @@ -0,0 +1,31 @@ +package com.chwl.app.bills.adapter; + +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.core.bills.bean.BillItemEntity; +import com.chwl.core.bills.bean.NobleBillListInfo; +import com.chwl.library.utils.TimeUtils; + +import java.util.List; + +/** + *

+ * + * @author jiahui + * @date 2018/1/18 + */ +public class NobleBillAdapter extends BillBaseAdapter { + public NobleBillAdapter(List billItemEntityList) { + super(billItemEntityList); + addItemType(BillItemEntity.ITEM_NORMAL, R.layout.list_charge_bills_item); + } + + @Override + public void convertNormal(BaseViewHolder baseViewHolder, BillItemEntity billItemEntity) { + NobleBillListInfo.NobleBillInfo nobleBillInfo = billItemEntity.nobleBillInfo; + if (nobleBillInfo == null) return; + baseViewHolder.setText(R.id.tv_gold, nobleBillInfo.getOptStr()) + .setText(R.id.tv_money, nobleBillInfo.getPayStr()) + .setText(R.id.tv_charge_time, TimeUtils.getYearMonthDayHourMinuteSecond(nobleBillInfo.getRecordTime())); + } +} diff --git a/app/src/main/java/com/chwl/app/bills/adapter/RadishGiftAdapter.java b/app/src/main/java/com/chwl/app/bills/adapter/RadishGiftAdapter.java new file mode 100644 index 0000000..51456a0 --- /dev/null +++ b/app/src/main/java/com/chwl/app/bills/adapter/RadishGiftAdapter.java @@ -0,0 +1,47 @@ +package com.chwl.app.bills.adapter; + +import android.widget.ImageView; + +import androidx.core.content.ContextCompat; + +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.app.bills.fragmemt.RadishGiftFragment; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.bills.bean.BillItemEntity; +import com.chwl.core.bills.bean.RadishGiftInfo; +import com.chwl.library.utils.TimeUtils; + +import java.util.List; + +public class RadishGiftAdapter extends BillBaseAdapter{ + private byte mType; + + public RadishGiftAdapter(List billItemEntityList, byte type) { + super(billItemEntityList); + mType = type; + addItemType(BillItemEntity.ITEM_NORMAL, R.layout.list_expend_gift_item); + } + + @Override + public void convertNormal(BaseViewHolder baseViewHolder, BillItemEntity billItemEntity) { + + RadishGiftInfo radishGiftInfo = billItemEntity.mRadishGiftInfo; + if (radishGiftInfo == null) return; + + baseViewHolder.setText(R.id.tv_send_name, radishGiftInfo.getDescribeStr()) + .setText(R.id.tv_user_name, radishGiftInfo.getGiftName()) + .setText(R.id.gift_date, TimeUtils.getDateTimeString(radishGiftInfo.getCreateTime(), "HH:mm:ss")); + + // 价格/数量 + int incomeColor = ContextCompat.getColor(mContext, R.color.appColor); + int outputColor = ContextCompat.getColor(mContext, R.color.color_333333); + baseViewHolder.setTextColor(R.id.tv_gift_income, mType == RadishGiftFragment.TYPE_RADISH_INCOME ? incomeColor : outputColor) + .setText(R.id.tv_gift_income, mType == RadishGiftFragment.TYPE_RADISH_INCOME ? "x" + radishGiftInfo.getGiftNum() : radishGiftInfo.getAmountStr()) + .setText(R.id.gold, mType == RadishGiftFragment.TYPE_RADISH_INCOME ? "" : radishGiftInfo.getCurrencyStr()); + + ImageView avatar = baseViewHolder.getView(R.id.img_avatar); + ImageLoadUtils.loadImage(mContext, radishGiftInfo.getGiftPicUrl(), avatar); + } +} + diff --git a/app/src/main/java/com/chwl/app/bills/adapter/RedBagBillsAdapter.java b/app/src/main/java/com/chwl/app/bills/adapter/RedBagBillsAdapter.java new file mode 100644 index 0000000..8073132 --- /dev/null +++ b/app/src/main/java/com/chwl/app/bills/adapter/RedBagBillsAdapter.java @@ -0,0 +1,30 @@ +package com.chwl.app.bills.adapter; + +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.core.bills.bean.BillItemEntity; +import com.chwl.core.bills.bean.RedBagInfo; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.TimeUtils; + +import java.util.List; + +/** + * 红包记录 RedBagInfo + * Created by ${Seven} on 2017/9/25. + */ +public class RedBagBillsAdapter extends BillBaseAdapter { + public RedBagBillsAdapter(List billItemEntityList) { + super(billItemEntityList); + addItemType(BillItemEntity.ITEM_NORMAL, R.layout.list_charge_bills_item); + } + + @Override + public void convertNormal(BaseViewHolder baseViewHolder, BillItemEntity billItemEntity) { + RedBagInfo redBagInfo = billItemEntity.mRedBagInfo; + if (redBagInfo == null) return; + baseViewHolder.setText(R.id.tv_gold, redBagInfo.getTypeStr()) + .setText(R.id.tv_money, "+" + redBagInfo.getPacketNum() + ResUtil.getString(R.string.bills_adapter_redbagbillsadapter_01)) + .setText(R.id.tv_charge_time, TimeUtils.getYearMonthDayHourMinuteSecond(redBagInfo.getCreateTime())); + } +} diff --git a/app/src/main/java/com/chwl/app/bills/event/DateInfoEvent.java b/app/src/main/java/com/chwl/app/bills/event/DateInfoEvent.java new file mode 100644 index 0000000..bb666d8 --- /dev/null +++ b/app/src/main/java/com/chwl/app/bills/event/DateInfoEvent.java @@ -0,0 +1,15 @@ +package com.chwl.app.bills.event; + +/** + *

事件日期

+ * Created by Administrator on 2017/11/8. + */ +public class DateInfoEvent { + public long millSeconds; + public int position; + + public DateInfoEvent(long millSeconds, int position) { + this.millSeconds = millSeconds; + this.position = position; + } +} diff --git a/app/src/main/java/com/chwl/app/bills/event/TopEvent.java b/app/src/main/java/com/chwl/app/bills/event/TopEvent.java new file mode 100644 index 0000000..fa604b4 --- /dev/null +++ b/app/src/main/java/com/chwl/app/bills/event/TopEvent.java @@ -0,0 +1,10 @@ +package com.chwl.app.bills.event; + +public class TopEvent { + + public int position; + + public TopEvent(int position) { + this.position = position; + } +} diff --git a/app/src/main/java/com/chwl/app/bills/fragmemt/BaseBillsFragment.java b/app/src/main/java/com/chwl/app/bills/fragmemt/BaseBillsFragment.java new file mode 100644 index 0000000..16dd10a --- /dev/null +++ b/app/src/main/java/com/chwl/app/bills/fragmemt/BaseBillsFragment.java @@ -0,0 +1,134 @@ +package com.chwl.app.bills.fragmemt; + +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.recyclerview.widget.RecyclerView; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import com.jzxiang.pickerview.TimePickerDialog; +import com.jzxiang.pickerview.data.Type; +import com.jzxiang.pickerview.listener.OnDateSetListener; +import com.chwl.app.R; +import com.chwl.app.base.BaseMvpFragment; +import com.chwl.core.Constants; +import com.chwl.core.bills.bean.BillItemEntity; +import com.chwl.core.radish.RadishModel; +import com.chwl.library.base.IMvpBaseView; +import com.chwl.library.base.factory.AbstractMvpPresenter; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.TimeUtils; + +import java.util.ArrayList; +import java.util.List; + +public abstract class BaseBillsFragment> extends BaseMvpFragment + implements View.OnClickListener, OnDateSetListener { + protected RecyclerView mRecyclerView; + protected SwipeRefreshLayout mRefreshLayout; + protected int mCurrentCounter = Constants.PAGE_START; + protected static final int PAGE_SIZE = Constants.BILL_PAGE_SIZE; + protected long time = System.currentTimeMillis(); + protected List mBillItemEntityList = new ArrayList<>(); + private TextView mTvDate; + private ImageView mIvTodaySelect; + private ImageView mIvSelectorDate; + protected TimePickerDialog.Builder mDialogYearMonthDayBuild; + private View mRlyDate; + + @Override + public int getRootLayoutId() { + return R.layout.fragment_gift_income ; + } + + @Override + public void onFindViews() { + mTvDate = mView.findViewById(R.id.tv_date); + mRecyclerView = mView.findViewById(R.id.recyclerView); + mRefreshLayout = mView.findViewById(R.id.swipe_refresh); + mIvTodaySelect = mView.findViewById(R.id.iv_today_select); + mIvSelectorDate = mView.findViewById(R.id.tv_selector_date); + mRlyDate = mView.findViewById(R.id.rly_date); + } + + @Override + public void onSetListener() { + mIvTodaySelect.setOnClickListener(this); + mIvSelectorDate.setOnClickListener(this); + mRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { + @Override + public void onRefresh() { + mCurrentCounter = Constants.PAGE_START; + RadishModel.get().updateRadishWallet().subscribe(); + loadData(); + } + }); + + } + + @Override + public void initiate() { + initData(); + } + + @Override + public void onDateSet(TimePickerDialog timePickerView, long millseconds) { + this.time = millseconds; + setDate(millseconds); + mCurrentCounter = Constants.PAGE_START; + showLoading(); + loadData(); + } + + protected void initData() { + setDate(System.currentTimeMillis()); + mDialogYearMonthDayBuild = new TimePickerDialog.Builder() + .setType(Type.YEAR_MONTH_DAY) + .setTitleStringId(ResUtil.getString(R.string.bills_fragmemt_basebillsfragment_01)) + .setThemeColor(getResources().getColor(R.color.line_background)) + .setWheelItemTextNormalColor(getResources().getColor(R.color + .timetimepicker_default_text_color)) + .setWheelItemTextSelectorColor(getResources().getColor(R.color.black)) + .setCallBack(this); + } + + protected long mTime; + protected void setDate(long time) { + mTime = time; + mTvDate.setText(TimeUtils.getDateTimeString(time, "yyyy-MM-dd")); + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.iv_today_select: + mCurrentCounter = Constants.PAGE_START; + time = System.currentTimeMillis(); + setDate(time); + showLoading(); + loadData(); + break; + case R.id.tv_selector_date: + mDialogYearMonthDayBuild.build().show(getChildFragmentManager(), "year_month_day"); + break; + default: + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (mDialogYearMonthDayBuild != null) { + mDialogYearMonthDayBuild.setCallBack(null); + mDialogYearMonthDayBuild = null; + } + } + + protected void setRlyDateBackground(int color) { + if (mRlyDate != null) + mRlyDate.setBackgroundColor(color); + } + + public abstract void loadData(); +} diff --git a/app/src/main/java/com/chwl/app/bills/fragmemt/GiftIncomeFragment.java b/app/src/main/java/com/chwl/app/bills/fragmemt/GiftIncomeFragment.java new file mode 100644 index 0000000..3011f29 --- /dev/null +++ b/app/src/main/java/com/chwl/app/bills/fragmemt/GiftIncomeFragment.java @@ -0,0 +1,148 @@ +package com.chwl.app.bills.fragmemt; + +import android.annotation.SuppressLint; +import android.text.TextUtils; +import android.view.View; + +import androidx.fragment.app.Fragment; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chwl.app.R; +import com.chwl.app.bills.adapter.BillBaseAdapter; +import com.chwl.app.bills.adapter.GiftIncomeAdapter; +import com.chwl.app.bills.presenter.GiftIncomePresenter; +import com.chwl.app.bills.view.IGiftIncomeView; +import com.chwl.app.ui.widget.RecyclerViewNoBugLinearLayoutManager; +import com.chwl.core.XConstants; +import com.chwl.core.Constants; +import com.chwl.core.bills.bean.BillItemEntity; +import com.chwl.core.bills.bean.IncomeInfo; +import com.chwl.core.bills.bean.IncomeListInfo; +import com.chwl.library.base.factory.CreatePresenter; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@CreatePresenter(GiftIncomePresenter.class) +public class GiftIncomeFragment extends BaseBillsFragment implements IGiftIncomeView { + private BillBaseAdapter adapter; + + public static Fragment newInstance() { + Fragment fragment = new GiftIncomeFragment(); + return fragment; + } + + @Override + public int getRootLayoutId() { + return R.layout.fragment_gift_income; + } + + @Override + public void initiate () { + super.initiate(); + adapter = new GiftIncomeAdapter(mBillItemEntityList); + adapter.setOnLoadMoreListener(new BaseQuickAdapter.RequestLoadMoreListener() { + @Override + public void onLoadMoreRequested() { + mCurrentCounter++; + loadData(); + } + }, mRecyclerView); + adapter.addFooterView(View.inflate(getActivity(), R.layout.layout_bills_bottom, null)); + RecyclerViewNoBugLinearLayoutManager manager = new RecyclerViewNoBugLinearLayoutManager(mContext); + mRecyclerView.setLayoutManager(manager); + mRecyclerView.setAdapter(adapter); + + firstLoadDate(); + } + + @SuppressLint("CheckResult") + public void loadData () { + getMvpPresenter().getGiftIncomeBills(mCurrentCounter, PAGE_SIZE, time); + } + + @Override + public void onGetDataError (String error){ + if (mCurrentCounter == Constants.PAGE_START) { + showNetworkErr(); + } else { + adapter.loadMoreFail(); + } + } + + @Override + public void onGetIncomeBills (IncomeListInfo data){ + mRefreshLayout.setRefreshing(false); + if (null != data) { + if (mCurrentCounter == Constants.PAGE_START) { + hideStatus(); + mBillItemEntityList.clear(); + adapter.setNewData(mBillItemEntityList); + } else { + adapter.loadMoreComplete(); + } + List>> billList = data.getBillList(); + if (!billList.isEmpty()) { + int size = mBillItemEntityList.size(); + List billItemEntities = new ArrayList<>(); + BillItemEntity billItemEntity; + for (int i = 0; i < billList.size(); i++) { + Map> map = billList.get(i); + for (String key : map.keySet()) { + // key ---日期 value:list集合记录 + List incomeInfos = map.get(key); + if (ListUtils.isListEmpty(incomeInfos)) continue; + + //标题 + if (size > 0) { + BillItemEntity lastBillItem = mBillItemEntityList.get(size - 1); + //时间不一致才会添加标题 + if (!TextUtils.equals(lastBillItem.time, key)) { + billItemEntity = new BillItemEntity(BillItemEntity.ITEM_DATE, key); + billItemEntities.add(billItemEntity); + } + } else { + billItemEntity = new BillItemEntity(BillItemEntity.ITEM_DATE, key); + billItemEntities.add(billItemEntity); + } + + //正常item + for (IncomeInfo temp : incomeInfos) { + billItemEntity = new BillItemEntity(BillItemEntity.ITEM_NORMAL); + billItemEntity.mGiftInComeInfo = temp; + //目的是为了比较 + billItemEntity.time = key; + billItemEntities.add(billItemEntity); + } + } + } + if (billItemEntities.size() < Constants.BILL_PAGE_SIZE && mCurrentCounter == Constants.PAGE_START) { + adapter.setEnableLoadMore(false); + } + adapter.addData(billItemEntities); + } else { + if (mCurrentCounter == Constants.PAGE_START) { + showNoData(R.drawable.icon_common_failure, ResUtil.getString(R.string.yizhuan_xchat_android_constants_xchatconstants_017)); + } else { + adapter.loadMoreEnd(true); + } + } + } + } + + @Override + public void smoothScrollToTop () { + if (mRecyclerView != null) + mRecyclerView.smoothScrollToPosition(0); + } + + private void firstLoadDate () { + mCurrentCounter = Constants.PAGE_START; + showLoading(); + loadData(); + } + +} diff --git a/app/src/main/java/com/chwl/app/bills/fragmemt/GiftOutputFragment.java b/app/src/main/java/com/chwl/app/bills/fragmemt/GiftOutputFragment.java new file mode 100644 index 0000000..c15285b --- /dev/null +++ b/app/src/main/java/com/chwl/app/bills/fragmemt/GiftOutputFragment.java @@ -0,0 +1,142 @@ +package com.chwl.app.bills.fragmemt; + +import android.annotation.SuppressLint; +import android.text.TextUtils; +import android.view.View; + +import androidx.fragment.app.Fragment; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chwl.app.R; +import com.chwl.app.bills.adapter.BillBaseAdapter; +import com.chwl.app.bills.adapter.GiftExpendAdapter; +import com.chwl.app.bills.presenter.GiftOutputPresenter; +import com.chwl.app.bills.view.IGiftOutputView; +import com.chwl.app.ui.widget.RecyclerViewNoBugLinearLayoutManager; +import com.chwl.core.XConstants; +import com.chwl.core.Constants; +import com.chwl.core.bills.bean.BillItemEntity; +import com.chwl.core.bills.bean.ExpendInfo; +import com.chwl.core.bills.bean.ExpendListInfo; +import com.chwl.library.base.factory.CreatePresenter; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@CreatePresenter(GiftOutputPresenter.class) +public class GiftOutputFragment extends BaseBillsFragment implements IGiftOutputView { + private BillBaseAdapter adapter; + + public static Fragment newInstance() { + Fragment fragment = new GiftOutputFragment(); + return fragment; + } + + @Override + public void initiate() { + super.initiate(); + adapter = new GiftExpendAdapter(mBillItemEntityList); + adapter.setOnLoadMoreListener(new BaseQuickAdapter.RequestLoadMoreListener() { + @Override + public void onLoadMoreRequested() { + mCurrentCounter++; + loadData(); + } + }, mRecyclerView); + adapter.addFooterView(View.inflate(getActivity(), R.layout.layout_bills_bottom, null)); + RecyclerViewNoBugLinearLayoutManager manager = new RecyclerViewNoBugLinearLayoutManager(mContext); + mRecyclerView.setLayoutManager(manager); + mRecyclerView.setAdapter(adapter); + + firstLoadDate(); + } + + private void firstLoadDate() { + mCurrentCounter = Constants.PAGE_START; + showLoading(); + loadData(); + } + + @SuppressLint("CheckResult") + public void loadData() { + getMvpPresenter().getetExpendBills(mCurrentCounter, PAGE_SIZE, time); + } + + @Override + public void onGetDataError(String error) { + if (mCurrentCounter == Constants.PAGE_START) { + showNetworkErr(); + } else { + adapter.loadMoreFail(); + } + } + + @Override + public void onGetExpendBills(ExpendListInfo data) { + mRefreshLayout.setRefreshing(false); + if (null != data) { + if (mCurrentCounter == Constants.PAGE_START) { + hideStatus(); + mBillItemEntityList.clear(); + adapter.setNewData(mBillItemEntityList); + } else { + adapter.loadMoreComplete(); + } + List>> billList = data.getBillList(); + if (!billList.isEmpty()) { + List billItemEntities = new ArrayList<>(); + int size = mBillItemEntityList.size(); + BillItemEntity billItemEntity; + for (int i = 0; i < billList.size(); i++) { + Map> map = billList.get(i); + for (String key : map.keySet()) { + // key ---日期 value:list集合记录 + List expendInfos = map.get(key); + if (ListUtils.isListEmpty(expendInfos)) continue; + //标题 + if (size > 0) { + BillItemEntity lastBillItem = mBillItemEntityList.get(size - 1); + //时间不一致才会添加标题 + if (!TextUtils.equals(lastBillItem.time, key)) { + billItemEntity = new BillItemEntity(BillItemEntity.ITEM_DATE, key); + billItemEntities.add(billItemEntity); + } + } else { + billItemEntity = new BillItemEntity(BillItemEntity.ITEM_DATE, key); + billItemEntities.add(billItemEntity); + } + + //正常item + for (ExpendInfo temp : expendInfos) { + billItemEntity = new BillItemEntity(BillItemEntity.ITEM_NORMAL); + //目的是为了比较 + billItemEntity.time = key; + billItemEntity.mGiftExpendInfo = temp; + billItemEntities.add(billItemEntity); + } + } + } + if (billItemEntities.size() < Constants.BILL_PAGE_SIZE && mCurrentCounter == Constants.PAGE_START) { + adapter.setEnableLoadMore(false); + } + + adapter.addData(billItemEntities); + } else { + if (mCurrentCounter == Constants.PAGE_START) { + showNoData(R.drawable.icon_common_failure, ResUtil.getString(R.string.yizhuan_xchat_android_constants_xchatconstants_017)); + } else { + adapter.loadMoreEnd(true); + } + } + } + } + + @Override + public void smoothScrollToTop() { + if (mRecyclerView != null) + mRecyclerView.smoothScrollToPosition(0); + } +} diff --git a/app/src/main/java/com/chwl/app/bills/fragmemt/RadishGiftFragment.java b/app/src/main/java/com/chwl/app/bills/fragmemt/RadishGiftFragment.java new file mode 100644 index 0000000..dbec84e --- /dev/null +++ b/app/src/main/java/com/chwl/app/bills/fragmemt/RadishGiftFragment.java @@ -0,0 +1,155 @@ +package com.chwl.app.bills.fragmemt; + +import android.os.Bundle; +import android.text.TextUtils; + +import androidx.fragment.app.Fragment; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chwl.app.R; +import com.chwl.app.bills.adapter.BillBaseAdapter; +import com.chwl.app.bills.adapter.RadishGiftAdapter; +import com.chwl.app.bills.presenter.RadishGiftPresenter; +import com.chwl.app.bills.view.IRadishGiftView; +import com.chwl.app.ui.widget.RecyclerViewNoBugLinearLayoutManager; +import com.chwl.core.Constants; +import com.chwl.core.bills.bean.BillItemEntity; +import com.chwl.core.bills.bean.RadishGiftInfo; +import com.chwl.core.bills.bean.RadishGiftListInfo; +import com.chwl.library.base.factory.CreatePresenter; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@CreatePresenter(RadishGiftPresenter.class) +public class RadishGiftFragment extends BaseBillsFragment implements IRadishGiftView { + + public static final byte TYPE_RADISH_EXPAND = 1; + public static final byte TYPE_RADISH_INCOME= 2; + private static final String TYPE = "type_radish"; + private BillBaseAdapter mAdapter; + + private byte mType = TYPE_RADISH_INCOME; + + public static Fragment newInstance(byte type) { + Fragment fragment = new RadishGiftFragment(); + Bundle bundle = new Bundle(); + bundle.putByte(TYPE, type); + fragment.setArguments(bundle); + return fragment; + } + @Override + public void loadData() { + getMvpPresenter().getRadishRecord(mCurrentCounter, PAGE_SIZE, mTime, mType); + } + + private void firstLoadDate() { + mCurrentCounter = Constants.PAGE_START; + showLoading(); + loadData(); + } + + @Override + public void initiate() { + super.initiate(); + + Bundle bundle = getArguments(); + if (bundle != null) { + mType = bundle.getByte(TYPE, TYPE_RADISH_INCOME); + } + + mAdapter = new RadishGiftAdapter(mBillItemEntityList, mType); + mAdapter.setOnLoadMoreListener(new BaseQuickAdapter.RequestLoadMoreListener() { + @Override + public void onLoadMoreRequested() { + mCurrentCounter++; + loadData(); + } + }, mRecyclerView); + RecyclerViewNoBugLinearLayoutManager manager = new RecyclerViewNoBugLinearLayoutManager(mContext); + mRecyclerView.setLayoutManager(manager); + mRecyclerView.setAdapter(mAdapter); + + firstLoadDate(); + + } + + @Override + public void getRadishRecordSuccess(RadishGiftListInfo list) { + mRefreshLayout.setRefreshing(false); + if (null != list) { + if (mCurrentCounter == Constants.PAGE_START) { + hideStatus(); + mBillItemEntityList.clear(); + mAdapter.setNewData(mBillItemEntityList); + } else { + mAdapter.loadMoreComplete(); + } + List>> billList = list.getBillList(); + if (!billList.isEmpty()) { + int size = mBillItemEntityList.size(); + List billItemEntities = new ArrayList<>(); + BillItemEntity billItemEntity; + for (int i = 0; i < billList.size(); i++) { + Map> map = billList.get(i); + for (String key : map.keySet()) { + // key ---日期 value:list集合记录 + List incomeInfos = map.get(key); + if (ListUtils.isListEmpty(incomeInfos)) continue; + + //标题 + if (size > 0) { + BillItemEntity lastBillItem = mBillItemEntityList.get(size - 1); + //时间不一致才会添加标题 + if (!TextUtils.equals(lastBillItem.time, key)) { + billItemEntity = new BillItemEntity(BillItemEntity.ITEM_DATE, key); + billItemEntities.add(billItemEntity); + } + } else { + billItemEntity = new BillItemEntity(BillItemEntity.ITEM_DATE, key); + billItemEntities.add(billItemEntity); + } + + //正常item + for (RadishGiftInfo temp : incomeInfos) { + billItemEntity = new BillItemEntity(BillItemEntity.ITEM_NORMAL); + billItemEntity.mRadishGiftInfo = temp; + //目的是为了比较 + billItemEntity.time = key; + billItemEntities.add(billItemEntity); + } + } + } + if (billItemEntities.size() < Constants.BILL_PAGE_SIZE && mCurrentCounter == Constants.PAGE_START) { + mAdapter.setEnableLoadMore(false); + } + mAdapter.addData(billItemEntities); + } else { + if (mCurrentCounter == Constants.PAGE_START) { + showNoData(R.drawable.icon_common_failure, ResUtil.getString(R.string.bills_fragmemt_radishgiftfragment_01)); + } else { + mAdapter.loadMoreEnd(true); + } + } + } + } + + @Override + public void getRadishRecordFail(String message) { + if (mCurrentCounter == Constants.PAGE_START) { + showNetworkErr(); + } else { + mAdapter.loadMoreFail(); + } + + } + + @Override + public void smoothScrollToTop () { + if (mRecyclerView != null) + mRecyclerView.smoothScrollToPosition(0); + } +} diff --git a/app/src/main/java/com/chwl/app/bills/presenter/BillGiftIncomeGroupPresenter.java b/app/src/main/java/com/chwl/app/bills/presenter/BillGiftIncomeGroupPresenter.java new file mode 100644 index 0000000..931834b --- /dev/null +++ b/app/src/main/java/com/chwl/app/bills/presenter/BillGiftIncomeGroupPresenter.java @@ -0,0 +1,7 @@ +package com.chwl.app.bills.presenter; + +import com.chwl.app.base.BaseMvpPresenter; +import com.chwl.app.bills.view.IBillGiftIncomeGroupView; + +public class BillGiftIncomeGroupPresenter extends BaseMvpPresenter { +} diff --git a/app/src/main/java/com/chwl/app/bills/presenter/GiftIncomePresenter.java b/app/src/main/java/com/chwl/app/bills/presenter/GiftIncomePresenter.java new file mode 100644 index 0000000..5371674 --- /dev/null +++ b/app/src/main/java/com/chwl/app/bills/presenter/GiftIncomePresenter.java @@ -0,0 +1,29 @@ +package com.chwl.app.bills.presenter; + +import android.annotation.SuppressLint; + +import com.chwl.app.base.BaseMvpPresenter; +import com.chwl.app.bills.view.IGiftIncomeView; +import com.chwl.core.bills.BillModel; + +public class GiftIncomePresenter extends BaseMvpPresenter { + + @SuppressLint("CheckResult") + public void getGiftIncomeBills(int pageNo, int pageSize, long time) { + BillModel.get() + .getGiftIncomeBills(pageNo, pageSize, time) + .compose(bindToLifecycle()) + .subscribe((incomedResult, throwable) -> { + if (throwable != null) { + if (mMvpView != null) + mMvpView.onGetDataError(throwable.getMessage()); + } else if (incomedResult != null && incomedResult.isSuccess()) { + if (mMvpView != null) + mMvpView.onGetIncomeBills(incomedResult.getData()); + } else if (incomedResult != null) { + if (mMvpView != null) + mMvpView.onGetDataError(incomedResult.getError()); + } + }); + } +} diff --git a/app/src/main/java/com/chwl/app/bills/presenter/GiftOutputPresenter.java b/app/src/main/java/com/chwl/app/bills/presenter/GiftOutputPresenter.java new file mode 100644 index 0000000..5f59d8f --- /dev/null +++ b/app/src/main/java/com/chwl/app/bills/presenter/GiftOutputPresenter.java @@ -0,0 +1,26 @@ +package com.chwl.app.bills.presenter; + +import android.annotation.SuppressLint; + +import com.chwl.app.base.BaseMvpPresenter; +import com.chwl.app.bills.view.IGiftOutputView; +import com.chwl.core.bills.BillModel; + +public class GiftOutputPresenter extends BaseMvpPresenter { + + @SuppressLint("CheckResult") + public void getetExpendBills(int pageNo, int pageSize, long time) { + BillModel.get() + .getGiftExpendBills(pageNo, pageSize, time) + .compose(bindToLifecycle()) + .subscribe((expendResult, throwable) -> { + if (throwable != null) { + mMvpView.onGetDataError(throwable.getMessage()); + } else if (expendResult != null && expendResult.isSuccess()) { + mMvpView.onGetExpendBills(expendResult.getData()); + } else if (expendResult != null) { + mMvpView.onGetDataError(expendResult.getError()); + } + }); + } +} diff --git a/app/src/main/java/com/chwl/app/bills/presenter/RadishGiftPresenter.java b/app/src/main/java/com/chwl/app/bills/presenter/RadishGiftPresenter.java new file mode 100644 index 0000000..fbff468 --- /dev/null +++ b/app/src/main/java/com/chwl/app/bills/presenter/RadishGiftPresenter.java @@ -0,0 +1,41 @@ +package com.chwl.app.bills.presenter; + +import com.chwl.app.base.BaseMvpPresenter; +import com.chwl.app.bills.view.IRadishGiftView; +import com.chwl.core.bills.RadishGiftModel; +import com.chwl.core.bills.result.RadishGiftResult; + +import io.reactivex.SingleObserver; +import io.reactivex.disposables.Disposable; + +public class RadishGiftPresenter extends BaseMvpPresenter { + + public void getRadishRecord(int page, int pageSize, long date, byte type) { + RadishGiftModel.get().getRadishRecord(page, pageSize, date, type) + .subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onSuccess(RadishGiftResult radishGiftResult) { + if (radishGiftResult != null && radishGiftResult.isSuccess()) { + if (mMvpView != null) + mMvpView.getRadishRecordSuccess(radishGiftResult.getData()); + } else if (radishGiftResult != null){ + if (mMvpView != null) + mMvpView.getRadishRecordFail(radishGiftResult.getError()); + } + } + + @Override + public void onError(Throwable e) { + if (mMvpView != null) + mMvpView.getRadishRecordFail(e.getMessage()); + + } + }); + + } +} diff --git a/app/src/main/java/com/chwl/app/bills/view/IBillGiftIncomeGroupView.java b/app/src/main/java/com/chwl/app/bills/view/IBillGiftIncomeGroupView.java new file mode 100644 index 0000000..f22e91f --- /dev/null +++ b/app/src/main/java/com/chwl/app/bills/view/IBillGiftIncomeGroupView.java @@ -0,0 +1,6 @@ +package com.chwl.app.bills.view; + +import com.chwl.library.base.IMvpBaseView; + +public interface IBillGiftIncomeGroupView extends IMvpBaseView { +} diff --git a/app/src/main/java/com/chwl/app/bills/view/IGiftIncomeView.java b/app/src/main/java/com/chwl/app/bills/view/IGiftIncomeView.java new file mode 100644 index 0000000..d4da736 --- /dev/null +++ b/app/src/main/java/com/chwl/app/bills/view/IGiftIncomeView.java @@ -0,0 +1,8 @@ +package com.chwl.app.bills.view; + +import com.chwl.core.bills.bean.IncomeListInfo; + +public interface IGiftIncomeView extends ISmoothToTopView { + void onGetDataError(String message); + void onGetIncomeBills(IncomeListInfo data); +} diff --git a/app/src/main/java/com/chwl/app/bills/view/IGiftOutputView.java b/app/src/main/java/com/chwl/app/bills/view/IGiftOutputView.java new file mode 100644 index 0000000..1d8b845 --- /dev/null +++ b/app/src/main/java/com/chwl/app/bills/view/IGiftOutputView.java @@ -0,0 +1,10 @@ +package com.chwl.app.bills.view; + +import com.chwl.core.bills.bean.ExpendListInfo; +import com.chwl.library.base.IMvpBaseView; + +public interface IGiftOutputView extends IMvpBaseView { + void smoothScrollToTop(); + void onGetDataError(String message); + void onGetExpendBills(ExpendListInfo data); +} diff --git a/app/src/main/java/com/chwl/app/bills/view/IRadishGiftView.java b/app/src/main/java/com/chwl/app/bills/view/IRadishGiftView.java new file mode 100644 index 0000000..4608b18 --- /dev/null +++ b/app/src/main/java/com/chwl/app/bills/view/IRadishGiftView.java @@ -0,0 +1,8 @@ +package com.chwl.app.bills.view; + +import com.chwl.core.bills.bean.RadishGiftListInfo; + +public interface IRadishGiftView extends ISmoothToTopView { + void getRadishRecordSuccess(RadishGiftListInfo list); + void getRadishRecordFail(String message); +} diff --git a/app/src/main/java/com/chwl/app/bills/view/ISmoothToTopView.java b/app/src/main/java/com/chwl/app/bills/view/ISmoothToTopView.java new file mode 100644 index 0000000..a8d64b7 --- /dev/null +++ b/app/src/main/java/com/chwl/app/bills/view/ISmoothToTopView.java @@ -0,0 +1,7 @@ +package com.chwl.app.bills.view; + +import com.chwl.library.base.IMvpBaseView; + +public interface ISmoothToTopView extends IMvpBaseView { + void smoothScrollToTop(); +} diff --git a/app/src/main/java/com/chwl/app/bills/widget/BillGiftIncomeGroupNavigatorAdapter.java b/app/src/main/java/com/chwl/app/bills/widget/BillGiftIncomeGroupNavigatorAdapter.java new file mode 100644 index 0000000..1423d5c --- /dev/null +++ b/app/src/main/java/com/chwl/app/bills/widget/BillGiftIncomeGroupNavigatorAdapter.java @@ -0,0 +1,71 @@ +package com.chwl.app.bills.widget; + +import android.content.Context; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import androidx.core.content.ContextCompat; + +import com.chwl.app.R; +import com.chwl.app.avroom.widget.RankNavigatorAdapter; +import com.chwl.app.decoration.view.widgets.BadgeScaleTransitionPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.CommonNavigatorAdapter; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.indicators.LinePagerIndicator; +import com.chwl.library.utils.ResUtil; + +import java.util.ArrayList; +import java.util.List; + +public class BillGiftIncomeGroupNavigatorAdapter extends CommonNavigatorAdapter { + + private List mTitleList = new ArrayList<>(); + + public BillGiftIncomeGroupNavigatorAdapter() { + mTitleList.add(ResUtil.getString(R.string.bills_widget_billgiftincomegroupnavigatoradapter_01)); + mTitleList.add(ResUtil.getString(R.string.bills_widget_billgiftincomegroupnavigatoradapter_02)); + } + @Override + public int getCount() { + return mTitleList.size(); + } + + @Override + public IPagerTitleView getTitleView(Context context, int index) { + BadgeScaleTransitionPagerTitleView scaleTransitionPagerTitleView = new BadgeScaleTransitionPagerTitleView(context); + scaleTransitionPagerTitleView.setNormalColor(ContextCompat.getColor(context, R.color.color_999999)); + scaleTransitionPagerTitleView.setSelectedColor(ContextCompat.getColor(context, R.color.color_333333)); + scaleTransitionPagerTitleView.setMinScale(1.0f); + scaleTransitionPagerTitleView.setTextSize(15); + scaleTransitionPagerTitleView.setText(mTitleList.get(index)); + + scaleTransitionPagerTitleView.setOnClickListener(view -> { + if (mOnItemSelectListener != null) { + mOnItemSelectListener.onItemSelect(index); + } + }); + return scaleTransitionPagerTitleView; + } + + @Override + public IPagerIndicator getIndicator(Context context) { + LinePagerIndicator indicator = new LinePagerIndicator(context); + indicator.setMode(LinePagerIndicator.MODE_EXACTLY); + indicator.setLineHeight(UIUtil.dip2px(context, 4)); + indicator.setRoundRadius(UIUtil.dip2px(context, 2.0)); + indicator.setLineWidth(UIUtil.dip2px(context, 17)); + indicator.setColors(ContextCompat.getColor(context, R.color.appColor)); + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + //lp.bottomMargin = 0; + indicator.setLayoutParams(lp); + return indicator; + } + + private RankNavigatorAdapter.OnItemSelectListener mOnItemSelectListener; + + public void setOnItemSelectListener(RankNavigatorAdapter.OnItemSelectListener mOnItemSelectListener) { + this.mOnItemSelectListener = mOnItemSelectListener; + } +} diff --git a/app/src/main/java/com/chwl/app/bills/widget/BillItemView.java b/app/src/main/java/com/chwl/app/bills/widget/BillItemView.java new file mode 100644 index 0000000..aa87804 --- /dev/null +++ b/app/src/main/java/com/chwl/app/bills/widget/BillItemView.java @@ -0,0 +1,67 @@ +package com.chwl.app.bills.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.view.View; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import androidx.annotation.Nullable; + +import com.chwl.app.R; + +/** + *

账单item

+ * Created by Administrator on 2017/11/6. + */ +public class BillItemView extends RelativeLayout { + private ImageView mIvLeftIcon; + private TextView mTvItemText; + private View mViewLine; + private Context mContext; + + public BillItemView(Context context) { + this(context, null); + } + + public BillItemView(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public BillItemView(Context context, @Nullable AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(context, attrs, defStyle); + } + + private void init(Context context, @Nullable AttributeSet attrs, int defStyle) { + mContext = context; + inflate(context, R.layout.layout_bill_item_view, this); + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.BillItemView, defStyle, 0); + int leftIcon = a.getResourceId(R.styleable.BillItemView_left_icon, -1); + String itemText = a.getString(R.styleable.BillItemView_item_text); + boolean isHide = a.getBoolean(R.styleable.BillItemView_hide_line, false); + a.recycle(); + mIvLeftIcon = (ImageView) findViewById(R.id.iv_left_icon); + mTvItemText = (TextView) findViewById(R.id.tv_item_text); + mViewLine = findViewById(R.id.view_line); + + setBackgroundResource(R.drawable.bg_common_touch_while); + setData(leftIcon, itemText); + setViewLine(isHide); + } + + public void setData(int leftIconResId, int itemTextResId) { + setData(leftIconResId, mContext.getResources().getString(itemTextResId)); + } + + public void setData(int leftIconResId, String itemText) { + mIvLeftIcon.setImageResource(leftIconResId); + mTvItemText.setText(itemText); + } + + public void setViewLine(boolean isHide) { + mViewLine.setVisibility(!isHide ? VISIBLE : GONE); + } +} diff --git a/app/src/main/java/com/chwl/app/bindadapter/BaseAdapter.java b/app/src/main/java/com/chwl/app/bindadapter/BaseAdapter.java new file mode 100644 index 0000000..9a12af8 --- /dev/null +++ b/app/src/main/java/com/chwl/app/bindadapter/BaseAdapter.java @@ -0,0 +1,52 @@ +package com.chwl.app.bindadapter; + +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.LayoutRes; +import androidx.annotation.Nullable; +import androidx.databinding.DataBindingUtil; +import androidx.databinding.ViewDataBinding; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chwl.app.R; + + +/** + * Created by fwhm on 2017/7/5. + */ + +public class BaseAdapter extends BaseQuickAdapter { + + private int brid; + + @Nullable + private int[] clickIds; + + public BaseAdapter(@LayoutRes int layoutResId, int brid) { + this(layoutResId, brid, null); + } + + public BaseAdapter(@LayoutRes int layoutResId, int brid, @Nullable int[] clickIds) { + super(layoutResId); + this.clickIds = clickIds; + this.brid = brid; + } + + @Override + protected void convert(BindingViewHolder helper, T item) { + ViewDataBinding binding = helper.getBinding(); + binding.setVariable(brid, item); + binding.executePendingBindings(); + } + @Override + protected View getItemView(int layoutResId, ViewGroup parent) { + ViewDataBinding binding = DataBindingUtil.inflate(mLayoutInflater, layoutResId, parent, false); + if (binding == null) { + return super.getItemView(layoutResId, parent); + } + View view = binding.getRoot(); + view.setTag(R.id.BaseQuickAdapter_databinding_support, binding); + return view; + } +} diff --git a/app/src/main/java/com/chwl/app/bindadapter/BaseBindingAdapter.kt b/app/src/main/java/com/chwl/app/bindadapter/BaseBindingAdapter.kt new file mode 100644 index 0000000..44bd61c --- /dev/null +++ b/app/src/main/java/com/chwl/app/bindadapter/BaseBindingAdapter.kt @@ -0,0 +1,65 @@ +package com.chwl.app.bindadapter + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.viewbinding.ViewBinding +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chwl.app.R +import com.chwl.library.common.util.isVerify +import java.lang.reflect.ParameterizedType + +open class BaseBindingAdapter() : BaseQuickAdapter>(R.layout.item_empty_list) { + + + override fun getItemView(layoutResId: Int, parent: ViewGroup): View { + //反射没有想象中的那么耗时 + val type = javaClass.genericSuperclass as ParameterizedType + val aClass = type.actualTypeArguments[0] as Class<*> + +// val method = aClass.getDeclaredMethod("inflate", LayoutInflater::class.java) +// val binding = method.invoke(null, mLayoutInflater) as VB + + val method = aClass.getDeclaredMethod("inflate", LayoutInflater::class.java, ViewGroup::class.java, Boolean::class.java) + val binding = method.invoke(null, mLayoutInflater,parent,false) as VB + + val view = binding?.root?:return View(mContext) + view.setTag(R.id.BaseQuickAdapter_databinding_support, binding) + onCreateView(view) + return view + } + + protected open fun onCreateView(view : View) { + + } + + override fun convert(helper: BaseBindingViewHolder, item: T) { + helper.binding?.let { + val pos = helper.bindingAdapterPosition + onBindView(helper.binding,item,pos) + } + } + + + + override fun convertPayloads( + helper: BaseBindingViewHolder, + item: T, + payloads: MutableList + ) { + if (payloads.isVerify()) { + helper.binding?.let { + val pos = helper.bindingAdapterPosition + onBindViewByPayloads(helper.binding,item,pos,payloads) + } + } else { + super.convertPayloads(helper, item, payloads) + } + } + + open fun onBindView(viewBinding: VB,data : T,pos:Int) {} + open fun onBindViewByPayloads(viewBinding: VB,data : T,pos:Int,payloads: MutableList) {} + + + +} diff --git a/app/src/main/java/com/chwl/app/bindadapter/BaseBindingViewHolder.java b/app/src/main/java/com/chwl/app/bindadapter/BaseBindingViewHolder.java new file mode 100644 index 0000000..1fca777 --- /dev/null +++ b/app/src/main/java/com/chwl/app/bindadapter/BaseBindingViewHolder.java @@ -0,0 +1,23 @@ +package com.chwl.app.bindadapter; + +import android.view.View; + +import androidx.viewbinding.ViewBinding; + +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; + +/** + * Created by fwhm on 2017/3/28. + */ + +public class BaseBindingViewHolder extends BaseViewHolder { + + public BaseBindingViewHolder(View view) { + super(view); + } + + public VB getBinding() { + return (VB) itemView.getTag(R.id.BaseQuickAdapter_databinding_support); + } +} diff --git a/app/src/main/java/com/chwl/app/bindadapter/BindingViewHolder.java b/app/src/main/java/com/chwl/app/bindadapter/BindingViewHolder.java new file mode 100644 index 0000000..1b5ed14 --- /dev/null +++ b/app/src/main/java/com/chwl/app/bindadapter/BindingViewHolder.java @@ -0,0 +1,23 @@ +package com.chwl.app.bindadapter; + +import android.view.View; + +import androidx.databinding.ViewDataBinding; + +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; + +/** + * Created by fwhm on 2017/3/28. + */ + +public class BindingViewHolder extends BaseViewHolder { + + public BindingViewHolder(View view) { + super(view); + } + + public ViewDataBinding getBinding() { + return (ViewDataBinding) itemView.getTag(R.id.BaseQuickAdapter_databinding_support); + } +} diff --git a/app/src/main/java/com/chwl/app/bindadapter/RvAdapter.java b/app/src/main/java/com/chwl/app/bindadapter/RvAdapter.java new file mode 100644 index 0000000..4ad068f --- /dev/null +++ b/app/src/main/java/com/chwl/app/bindadapter/RvAdapter.java @@ -0,0 +1,41 @@ +package com.chwl.app.bindadapter; + +import androidx.databinding.BindingAdapter; +import androidx.recyclerview.widget.RecyclerView; + +import java.util.List; + +/** + * Created by huangmeng1 on 2018/5/9. + */ + +public class RvAdapter { + /** + * 实现adapter加载更多的一些处理与rv的映射 + * + * @param recyclerView + * @param date rv的数据 + * @param newData 每次加载回的数控 + * @param isLode + * @param throwable + * @param pageSize + * @param + */ + @BindingAdapter(value = {"date", "newData", "isLode", "error", "pageSize"}, requireAll = false) + public static void bindRvData(RecyclerView recyclerView, List date, List newData, boolean isLode, Throwable throwable, int pageSize) { + BaseAdapter adapter = (BaseAdapter) recyclerView.getAdapter(); + adapter.setNewData(date); + if (throwable != null) { + adapter.loadMoreFail(); + return; + } + if (newData == null || newData.size() < pageSize) { + adapter.loadMoreEnd(true); + return; + } + if (isLode) { + adapter.loadMoreComplete(); + } + } +} + diff --git a/app/src/main/java/com/chwl/app/bindadapter/ViewAdapter.java b/app/src/main/java/com/chwl/app/bindadapter/ViewAdapter.java new file mode 100644 index 0000000..efc312c --- /dev/null +++ b/app/src/main/java/com/chwl/app/bindadapter/ViewAdapter.java @@ -0,0 +1,179 @@ +package com.chwl.app.bindadapter; + +import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; +import android.text.TextUtils; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import androidx.annotation.Nullable; +import androidx.databinding.BindingAdapter; + +import com.bumptech.glide.load.DataSource; +import com.bumptech.glide.load.engine.GlideException; +import com.bumptech.glide.request.RequestListener; +import com.bumptech.glide.request.target.Target; +import com.chwl.app.R; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.view.GenderAgeTextView; +import com.chwl.library.common.util.OtherExtKt; +import com.chwl.library.utils.TimeUtils; +import com.chwl.library.utils.config.BasicConfig; +import com.chwl.library.widget.IOSSwitchView; +import com.netease.nim.uikit.support.glide.GlideApp; + + +/** + * Created by huangmeng1 on 2018/1/4. + */ + +public class ViewAdapter { + + @BindingAdapter(value = {"imgUrl", "defaultImage", "isRound"}, requireAll = false) + public static void setImgUrl(ImageView imageView, String url, Drawable drawable, boolean isRound) { + if (isRound) { + ImageLoadUtils.loadBannerRoundBackground(imageView.getContext(), url, imageView); + } else { + GlideApp.with(imageView.getContext()) + .load(TextUtils.isEmpty(url) ? R.mipmap.ic_tag_default : url) + .placeholder(drawable) + .error(drawable) + .listener(new RequestListener() { + @Override + public boolean onLoadFailed(@Nullable GlideException e, Object o, Target target, boolean b) { + return false; + } + + @Override + public boolean onResourceReady(Drawable drawable, Object o, Target target, DataSource dataSource, boolean b) { + float ratio = (drawable.getIntrinsicHeight() + 0.F) / drawable.getIntrinsicWidth(); + int width = Math.round(imageView.getContext().getResources().getDimensionPixelOffset(R.dimen.tag_height) / ratio); + int height = imageView.getContext().getResources().getDimensionPixelOffset(R.dimen.tag_height); + RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) imageView.getLayoutParams(); + params.width = width; + params.height = height; + imageView.setLayoutParams(params); + imageView.setImageDrawable(drawable); + return true; + } + }) + .into(imageView); + } + } + + @BindingAdapter(value = {"avatarUrl"}, requireAll = false) + public static void setAvatarUrl(ImageView imageView, String url) { + ImageLoadUtils.loadAvatar(url,imageView,R.drawable.default_avatar); + } + + @BindingAdapter(value = {"roundUrl"}, requireAll = false) + public static void setRoundUrl(ImageView imageView, String url) { + if (TextUtils.isEmpty(url)) return; + ImageLoadUtils.loadSmallRoundBackground(imageView.getContext(), url, imageView); + } + + @BindingAdapter(value = {"nomalUrl"}, requireAll = false) + public static void setNomalUrl(ImageView imageView, String url) { + if (TextUtils.isEmpty(url)) return; + ImageLoadUtils.loadImage(imageView.getContext(), url, imageView); + OtherExtKt.setVis(imageView,true,false); + } + + @BindingAdapter(value = {"isOn"}, requireAll = false) + public static void setIsOn(IOSSwitchView iosSwitchView, boolean isOn) { + iosSwitchView.setOn(isOn); + } + + @BindingAdapter(value = {"drawTime"}, requireAll = false) + public static void setTime(TextView tvContent, String time) { + long longTime = 0; + try { + longTime = Long.parseLong(time); + } catch (Exception e) { + e.printStackTrace(); + } + if (longTime == 0) { + tvContent.setVisibility(View.GONE); + return; + } + tvContent.setText(TimeUtils.getPostTimeString(BasicConfig.INSTANCE.getAppContext(), longTime, true, false)); + } + + @BindingAdapter(value = {"circleUrl"}, requireAll = false) + public static void setCircleUrl(ImageView imageView, String url) { + // if (TextUtils.isEmpty(url)) return; + ImageLoadUtils.loadCircleImage(imageView.getContext(), url, imageView, R.drawable.default_avatar); + } + + @BindingAdapter(value = {"shape_color", "shape_radius", "shape_stroke_width", "shape_stroke_color"}, requireAll = false) + public static void setViewBackground(View view, int color, int radius_dp, + float shape_stroke_width, int shape_stroke_color) { + GradientDrawable drawable = new GradientDrawable(); + drawable.setColor(color); + drawable.setCornerRadius(UIUtil.dip2px(view.getContext(), radius_dp)); + if (shape_stroke_width > 0) { + try { + drawable.setStroke(UIUtil.dip2px(view.getContext(), shape_stroke_width), + shape_stroke_color); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + view.setBackground(drawable); + } + + @BindingAdapter(value = {"selected"}) + public static void setViewSelected(View view, boolean selected) { + view.setSelected(selected); + } + + @BindingAdapter(value = {"ktvRoundCover"}, requireAll = false) + public static void setKtvRoundCover(ImageView imageView, String url) { + if (TextUtils.isEmpty(url)) { + imageView.setImageResource(R.drawable.default_cover); + } else { + ImageLoadUtils.loadKtvRoundBackground(imageView.getContext(), url, imageView); + } + } + + @BindingAdapter(value = {"visible"}, requireAll = false) + public static void setAvatarUrl(View view, boolean show) { + view.setVisibility(show ? View.VISIBLE : View.GONE); + } + + @BindingAdapter(value = {"shape_color", "shape_radius",}, requireAll = false) + public static void setViewBackgroundII(View v, int color, int radius) { + GradientDrawable drawable = new GradientDrawable(); + drawable.setColor(color); + drawable.setCornerRadius(UIUtil.dip2px(v.getContext(), radius)); + v.setBackground(drawable); + } + + @BindingAdapter(value = {"android:layout_width"}, requireAll = false) + public static void setLayoutWidth(View v, float width) { + ViewGroup.LayoutParams params = v.getLayoutParams(); + params.width = (int) width; + v.setLayoutParams(params); + } + + @BindingAdapter(value = {"android:layout_height"}, requireAll = false) + public static void setLayoutHeight(View v, float height) { + ViewGroup.LayoutParams params = v.getLayoutParams(); + params.height = (int) height; + v.setLayoutParams(params); + } + + @BindingAdapter(value = {"birthday"}, requireAll = false) + public static void setBirthday(GenderAgeTextView v, long birthday) { + v.setBirthDay(birthday); + } + + @BindingAdapter(value = {"gender"}, requireAll = false) + public static void setGender(GenderAgeTextView v, int gender) { + v.setGender(gender); + } +} diff --git a/app/src/main/java/com/chwl/app/common/AbsStatusFragment.java b/app/src/main/java/com/chwl/app/common/AbsStatusFragment.java new file mode 100644 index 0000000..12ce338 --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/AbsStatusFragment.java @@ -0,0 +1,36 @@ +package com.chwl.app.common; + +import android.os.Bundle; +import android.view.View; + +import androidx.fragment.app.Fragment; + +import com.chwl.app.R; +import com.chwl.library.utils.SingleToastUtil; + +/** + * Created by xujiexing on 14-7-21. + */ +public abstract class AbsStatusFragment extends Fragment implements IStatusFragment { + protected View.OnClickListener mLoadListener; + + @Override + public void setListener(View.OnClickListener listener) { + this.mLoadListener = listener; + } + + public void checkNetToast(){ + SingleToastUtil.showToast(R.string.str_network_not_capable); + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + view.setOnClickListener(mLoadListener); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + mLoadListener = null; + } +} diff --git a/app/src/main/java/com/chwl/app/common/CommonPagerAdapter.kt b/app/src/main/java/com/chwl/app/common/CommonPagerAdapter.kt new file mode 100644 index 0000000..51273b0 --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/CommonPagerAdapter.kt @@ -0,0 +1,14 @@ +package com.chwl.app.common + +import android.annotation.SuppressLint +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentPagerAdapter + +@SuppressLint("WrongConstant") +class CommonPagerAdapter(fm:FragmentManager, private val list:List) :FragmentPagerAdapter(fm, + BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT){ + override fun getCount()=list.size + + override fun getItem(position: Int)=list[position] +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/common/EmptyViewHelper.java b/app/src/main/java/com/chwl/app/common/EmptyViewHelper.java new file mode 100644 index 0000000..477a4aa --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/EmptyViewHelper.java @@ -0,0 +1,68 @@ +package com.chwl.app.common; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.chwl.app.R; +import com.chwl.library.utils.NetworkUtils; +import com.chwl.library.utils.ResUtil; + + +public class EmptyViewHelper { + + public static View createEmptyTextView(Context context, String text) { + if (!NetworkUtils.isNetworkAvailable(context)) text = ResUtil.getString(R.string.erban_common_emptyviewhelper_01); + View view = LayoutInflater.from(context).inflate(R.layout.layout_ktv_empty, null); + view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + ((TextView) view.findViewById(R.id.tv_hint)).setText(text); + return view; + } + + public static View createEmptyView(Context context,int imgId, String text) { + if (!NetworkUtils.isNetworkAvailable(context)) text = ResUtil.getString(R.string.erban_common_emptyviewhelper_01); + View view = LayoutInflater.from(context).inflate(R.layout.layout_ktv_empty, null); + view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + ((TextView) view.findViewById(R.id.tv_hint)).setText(text); + ((ImageView) view.findViewById(R.id.iv_status)).setImageResource(imgId); + return view; + } + + public static View createEmptyView(Context context,int imgId, String text,ViewGroup.LayoutParams layoutParams) { + if (!NetworkUtils.isNetworkAvailable(context)) text = ResUtil.getString(R.string.erban_common_emptyviewhelper_01); + View view = LayoutInflater.from(context).inflate(R.layout.layout_ktv_empty, null); + view.setLayoutParams(layoutParams); + ((TextView) view.findViewById(R.id.tv_hint)).setText(text); + ((ImageView) view.findViewById(R.id.iv_status)).setImageResource(imgId); + return view; + } + + public static View createEmptyTextViewHeight(Context context, String text) { + if (!NetworkUtils.isNetworkAvailable(context)) text = ResUtil.getString(R.string.erban_common_emptyviewhelper_01); + View view = LayoutInflater.from(context).inflate(R.layout.layout_wrap_empty, null); + view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + ((TextView) view.findViewById(R.id.tv_hint)).setText(text); + return view; + } + + public static View createEmptyTextViewNoImage(Context context, String text) { + if (!NetworkUtils.isNetworkAvailable(context)) text = ResUtil.getString(R.string.erban_common_emptyviewhelper_01); + View view = LayoutInflater.from(context).inflate(R.layout.layout_text_empty, null); + view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + ((TextView) view.findViewById(R.id.tv_hint)).setText(text); + return view; + } + + public static View createDarkEmptyView(Context context, String text) { + if (!NetworkUtils.isNetworkAvailable(context)) text = ResUtil.getString(R.string.erban_common_emptyviewhelper_02); + View view = LayoutInflater.from(context).inflate(R.layout.layout_ktv_empty, null); + view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + ((TextView) view.findViewById(R.id.tv_hint)).setText(text); + ((ImageView) view.findViewById(R.id.iv_status)).setImageResource(R.drawable.empty_content_dark); + return view; + } + +} diff --git a/app/src/main/java/com/chwl/app/common/IStatusFragment.java b/app/src/main/java/com/chwl/app/common/IStatusFragment.java new file mode 100644 index 0000000..a6aa65f --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/IStatusFragment.java @@ -0,0 +1,10 @@ +package com.chwl.app.common; + +import android.view.View; + +/** + * Created by xujiexing on 14-7-21. + */ +public interface IStatusFragment { + public void setListener(View.OnClickListener listener); +} diff --git a/app/src/main/java/com/chwl/app/common/LoadingFragment.java b/app/src/main/java/com/chwl/app/common/LoadingFragment.java new file mode 100644 index 0000000..2271aae --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/LoadingFragment.java @@ -0,0 +1,87 @@ +package com.chwl.app.common; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.chwl.app.R; + + +/** + * Created by xujiexing on 14-4-9. + */ +public class LoadingFragment extends AbsStatusFragment { + private static final String TIP_PARAM = "TIP_PARAM"; + private static final String DRAWABLE_PARAM = "DRAWABLE_PARAM"; + private static final String BACKGROUND_COLOR_PARAM = "BACKGROUND_COLOR_PARAM"; + private int mTip; + private int mDrawable; + private int mBackgroundColor; + + public static LoadingFragment newInstance() { + return new LoadingFragment(); + } + + public static LoadingFragment newInstance(int drawable, int tips) { + Bundle bundle = new Bundle(); + bundle.putInt(TIP_PARAM, tips); + bundle.putInt(DRAWABLE_PARAM, drawable); + LoadingFragment fragment = new LoadingFragment(); + fragment.setArguments(bundle); + return fragment; + } + + public static LoadingFragment newInstance(int drawable, int tips, int backgroundColor) { + Bundle bundle = new Bundle(); + bundle.putInt(TIP_PARAM, tips); + bundle.putInt(DRAWABLE_PARAM, drawable); + bundle.putInt(BACKGROUND_COLOR_PARAM, backgroundColor); + LoadingFragment fragment = new LoadingFragment(); + fragment.setArguments(bundle); + return fragment; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_loading, container, false); + if (savedInstanceState != null) { + mTip = savedInstanceState.getInt(TIP_PARAM, R.string.loading); + mDrawable = savedInstanceState.getInt(DRAWABLE_PARAM, R.drawable.loading_icon); + } else { + Bundle bundle = getArguments(); + if (bundle != null) { + mTip = bundle.getInt(TIP_PARAM, R.string.loading); + mDrawable = bundle.getInt(DRAWABLE_PARAM, R.drawable.loading_icon); + } else { + mTip = R.string.loading; + } + } + + if (mTip > 0) { + TextView textView = (TextView) view.findViewById(R.id.loading_text); + textView.setText(getString(mTip)); + textView.setVisibility(View.VISIBLE); + } + if (mDrawable > 0) { + ImageView imageView = (ImageView) view.findViewById(R.id.loadingIv); + imageView.setImageResource(mDrawable); + imageView.setVisibility(View.VISIBLE); + } + if (mBackgroundColor > 0) { + view.setBackgroundColor(mBackgroundColor); + } + + return view; + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putInt(TIP_PARAM, mTip); + outState.putInt(DRAWABLE_PARAM, mDrawable); + outState.putInt(BACKGROUND_COLOR_PARAM, mBackgroundColor); + } +} diff --git a/app/src/main/java/com/chwl/app/common/NetworkErrorFragment.java b/app/src/main/java/com/chwl/app/common/NetworkErrorFragment.java new file mode 100644 index 0000000..d69bbe8 --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/NetworkErrorFragment.java @@ -0,0 +1,70 @@ +package com.chwl.app.common; + +import static com.chwl.app.common.NoDataFragment.LAYOUTID_PARAM; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.chwl.app.R; +import com.chwl.library.utils.NetworkUtils; + +/** + * Created by xujiexing on 14-4-9. + */ +public class NetworkErrorFragment extends AbsStatusFragment { + private int mLayout; + + public static NetworkErrorFragment newInstance() { + return new NetworkErrorFragment(); + } + + public static NetworkErrorFragment newInstance(int layoutId) { + Bundle bundle = new Bundle(); + bundle.putInt(LAYOUTID_PARAM, layoutId); + NetworkErrorFragment fragment = new NetworkErrorFragment(); + fragment.setArguments(bundle); + return fragment; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + + Bundle bundle = getArguments(); + if (bundle != null) { + mLayout = bundle.getInt(LAYOUTID_PARAM); + } else { + mLayout = R.layout.fragment_network_error; + } + + if(mLayout <= 0){ + mLayout = R.layout.fragment_network_error; + } + + View view = LayoutInflater.from(getActivity()).inflate(mLayout, container, false); + view.setOnClickListener(mSelfListener); + + return view; + } + + private View.OnClickListener mSelfListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + + if(!NetworkUtils.isNetworkStrictlyAvailable(getActivity())){ + checkNetToast(); + return; + } + + if(mLoadListener != null){ + mLoadListener.onClick(v); + } + } + }; + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + } +} diff --git a/app/src/main/java/com/chwl/app/common/NoDataFragment.java b/app/src/main/java/com/chwl/app/common/NoDataFragment.java new file mode 100644 index 0000000..b3de2aa --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/NoDataFragment.java @@ -0,0 +1,130 @@ +package com.chwl.app.common; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.chwl.app.R; + + +/** + * Created by xujiexing on 14-4-9. + */ +public class NoDataFragment extends AbsStatusFragment { + public static final String LAYOUTID_PARAM = "LAYOUTID"; + private static final String TIP_PARAM = "TIP_PARAM"; + private static final String DRAWABLE_PARAM = "DRAWABLE_PARAM"; + private int mLayout; + private CharSequence mTip; + private int mDrawable; + + private OnNoDataFragmentButtonClickListener onNoDataFragmentButtonClickListener; + + public static NoDataFragment newInstance() { + return new NoDataFragment(); + } + + public static NoDataFragment newInstance(int drawable, CharSequence tips) { + Bundle bundle = new Bundle(); + bundle.putCharSequence(TIP_PARAM, tips); + bundle.putInt(DRAWABLE_PARAM, drawable); + NoDataFragment fragment = new NoDataFragment(); + fragment.setArguments(bundle); + return fragment; + } + + public static NoDataFragment newInstance(int layoutId, int drawable, CharSequence tips) { + Bundle bundle = new Bundle(); + bundle.putInt(LAYOUTID_PARAM, layoutId); + bundle.putCharSequence(TIP_PARAM, tips); + bundle.putInt(DRAWABLE_PARAM, drawable); + NoDataFragment fragment = new NoDataFragment(); + fragment.setArguments(bundle); + return fragment; + } + + public static NoDataFragment newInstance(int layoutId, int drawable, CharSequence tips, OnNoDataFragmentButtonClickListener onNoDataFragmentButtonClickListener) { + Bundle bundle = new Bundle(); + bundle.putInt(LAYOUTID_PARAM, layoutId); + bundle.putCharSequence(TIP_PARAM, tips); + bundle.putInt(DRAWABLE_PARAM, drawable); + NoDataFragment fragment = new NoDataFragment(); + fragment.setArguments(bundle); + fragment.setOnNoDataFragmentButtonClickListener(onNoDataFragmentButtonClickListener); + return fragment; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + + if (savedInstanceState != null) { + mLayout = savedInstanceState.getInt(LAYOUTID_PARAM); + mTip = savedInstanceState.getCharSequence(TIP_PARAM); + mDrawable = savedInstanceState.getInt(DRAWABLE_PARAM, R.drawable.icon_common_failure); + } else { + Bundle bundle = getArguments(); + if (bundle != null) { + mLayout = bundle.getInt(LAYOUTID_PARAM, 0); + mTip = bundle.getCharSequence(TIP_PARAM); + mDrawable = bundle.getInt(DRAWABLE_PARAM, R.drawable.icon_common_failure); + } else { + mLayout = R.layout.fragment_no_data_large_iv; + mTip = getString( + R.string.no_list_data); + mDrawable = R.drawable.icon_common_failure; + } + } + if (mTip == null || mTip.length() <= 0) { + mTip = getString(R.string.no_list_data); + } + + if (mDrawable <= 0) { + mDrawable = R.drawable.icon_common_failure; + } + + if (mLayout <= 0) { + mLayout = R.layout.fragment_no_data_large_iv; + } + + View view = LayoutInflater.from(getActivity()).inflate(mLayout, container, false); + view.setOnClickListener(this.mSelfListener); + ImageView imageView = view.findViewById(R.id.no_data_icon); + imageView.setImageDrawable(getResources().getDrawable(mDrawable)); + TextView textView = view.findViewById(R.id.no_data_text); + textView.setText(mTip); + if (view.findViewById(R.id.no_data_button) != null) { + View button = view.findViewById(R.id.no_data_button); + button.setOnClickListener(view1 -> { + if (onNoDataFragmentButtonClickListener != null) { + onNoDataFragmentButtonClickListener.onButtonClick(); + } + }); + } + + return view; + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putInt(LAYOUTID_PARAM, mLayout); + outState.putCharSequence(TIP_PARAM, mTip); + outState.putInt(DRAWABLE_PARAM, mDrawable); + } + + private View.OnClickListener mSelfListener = v -> { + if (mLoadListener != null) + mLoadListener.onClick(v); + }; + + public interface OnNoDataFragmentButtonClickListener { + void onButtonClick(); + } + + public void setOnNoDataFragmentButtonClickListener(OnNoDataFragmentButtonClickListener onNoDataFragmentButtonClickListener) { + this.onNoDataFragmentButtonClickListener = onNoDataFragmentButtonClickListener; + } +} diff --git a/app/src/main/java/com/chwl/app/common/ReloadFragment.java b/app/src/main/java/com/chwl/app/common/ReloadFragment.java new file mode 100644 index 0000000..e665245 --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/ReloadFragment.java @@ -0,0 +1,125 @@ +package com.chwl.app.common; + +import android.annotation.TargetApi; +import android.os.Build; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.ColorInt; + +import com.chwl.app.R; +import com.chwl.library.utils.NetworkUtils; +import com.chwl.library.utils.log.MLog; + +/** + * Created by xujiexing on 14-4-9. + */ +public class ReloadFragment extends AbsStatusFragment { + private static final String TIP_PARAM = "TIP_PARAM"; + private static final String DRAWABLE_PARAM = "DRAWABLE_PARAM"; + private static final String BG_PARAM = "BG_PARAM"; + private int mTip; + private int mDrawable; + private int mBgColor = 1; + + public static ReloadFragment newInstance() { + return new ReloadFragment(); + } + + public static ReloadFragment newInstance(int drawable, int tips) { + return newInstance(drawable, tips, -1); + } + + public static ReloadFragment newInstance(int drawable, int tips, @ColorInt int bgColor) { + Bundle bundle = new Bundle(); + bundle.putInt(TIP_PARAM, tips); + bundle.putInt(DRAWABLE_PARAM, drawable); + bundle.putInt(BG_PARAM, bgColor); + ReloadFragment fragment = new ReloadFragment(); + fragment.setArguments(bundle); + return fragment; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_reload, container, false); + + if (savedInstanceState != null) { + mTip = savedInstanceState.getInt(TIP_PARAM, R.string.click_screen_reload); + mDrawable = savedInstanceState.getInt(DRAWABLE_PARAM, R.drawable.icon_common_failure); + mBgColor = savedInstanceState.getInt(BG_PARAM, mBgColor); + } else { + Bundle bundle = getArguments(); + if (bundle != null) { + mTip = bundle.getInt(TIP_PARAM, R.string.click_screen_reload); + mDrawable = bundle.getInt(DRAWABLE_PARAM, R.drawable.icon_common_failure); + mBgColor = bundle.getInt(BG_PARAM, mBgColor); + } else { + mTip = R.string.click_screen_reload; + mDrawable = R.drawable.icon_common_failure; + } + } + if (mTip <= 0) { + mTip = R.string.click_screen_reload; + } + + if (mDrawable <= 0) { + mDrawable = R.drawable.icon_common_failure; + } + if(mBgColor != 1){ + view.setBackgroundColor(mBgColor); + } + ImageView imageView = (ImageView) view.findViewById(R.id.reload_icon); + imageView.setImageDrawable(getResources().getDrawable(mDrawable)); + TextView textView = (TextView) view.findViewById(R.id.error_text); + textView.setText(getString(mTip)); + view.setOnClickListener(mSelfListener); + return view; + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putInt(TIP_PARAM, mTip); + outState.putInt(DRAWABLE_PARAM, mDrawable); + } + + private View.OnClickListener mSelfListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + if (!checkActivityValid()) + return; + if (!NetworkUtils.isNetworkStrictlyAvailable(getActivity())) { + checkNetToast(); + return; + } + + if (mLoadListener != null) { + mLoadListener.onClick(v); + } + } + }; + + @TargetApi(17) + protected boolean checkActivityValid() { + if (getActivity() == null) { + MLog.warn(this, "Fragment " + this + " not attached to Activity"); + return false; + } + + if (getActivity().isFinishing()) { + MLog.warn(this, "activity is finishing"); + return false; + } + + if (Build.VERSION.SDK_INT >= 17 && getActivity().isDestroyed()) { + MLog.warn(this, "activity is isDestroyed"); + return false; + } + return true; + } +} diff --git a/app/src/main/java/com/chwl/app/common/ViewPagerAdapter.java b/app/src/main/java/com/chwl/app/common/ViewPagerAdapter.java new file mode 100644 index 0000000..7716ec6 --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/ViewPagerAdapter.java @@ -0,0 +1,38 @@ +package com.chwl.app.common; + +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentPagerAdapter; + +import java.util.List; + +/** + * Created by huangmeng1 on 2018/5/7. + */ + +public class ViewPagerAdapter extends FragmentPagerAdapter { + private List mFragmentList; + private String[] mTitleList; + public ViewPagerAdapter(FragmentManager fm, List mFragmentList, String[] mTitleList) { + super(fm); + this.mFragmentList = mFragmentList; + this.mTitleList = mTitleList; + } + + @Override + public Fragment getItem(int position) { + return mFragmentList.get(position); + } + + @Override + public int getCount() { + return mFragmentList.size(); + } + + @Nullable + @Override + public CharSequence getPageTitle(int position) { + return mTitleList[position]; + } +} diff --git a/app/src/main/java/com/chwl/app/common/app/ActivityStack.java b/app/src/main/java/com/chwl/app/common/app/ActivityStack.java new file mode 100644 index 0000000..b1d50ae --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/app/ActivityStack.java @@ -0,0 +1,167 @@ +package com.chwl.app.common.app; + +import android.app.Activity; +import android.content.Context; + +import com.chwl.app.application.App; +import com.chwl.app.avroom.activity.AVRoomActivity; +import com.chwl.app.utils.ActWhiteListMrg; +import com.chwl.core.utils.CoreLogger; + +import java.lang.ref.WeakReference; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * Activity栈管理类 + */ +public class ActivityStack { + private static final String TAG = "ActivityStack"; + private final CopyOnWriteArrayList> mActivity = new CopyOnWriteArrayList<>(); + private WeakReference mTopActivity; + private WeakReference mAvRoomActivity; + + public int getActivityNum() { + return mActivity.size(); + } + + public void finishAllActivity() { + for (WeakReference activity : mActivity) { + if (!isActivityValid(activity)) { + continue; + } + activity.get().finish(); + } + mActivity.clear(); + } + + public boolean isActivityExist(Class clazz) { + return getActivity(clazz) != null; + } + + public Activity getActivity(Class clazz) { + for (WeakReference activity : mActivity) { + if (!isActivityValid(activity) || !activity.get().getClass().equals(clazz)) { + continue; + } + return activity.get(); + } + return null; + } + + public Context getTopContext() { + Context context = null; + if (isActivityValid(mTopActivity)) { + context = mTopActivity.get(); + } else { + if (mActivity.size() > 0) { + context = mActivity.get(mActivity.size() - 1).get(); + } + if (context == null) { + context = App.gContext; + } + } + return context; + } + + public Activity getTopActivity() { + return mTopActivity == null ? null : mTopActivity.get(); + } + + public Activity getAvRoomActivity() { + return mAvRoomActivity == null ? null : mAvRoomActivity.get(); + } + + public Activity getActivityUnderTop() { + if (getActivityNum() < 2) { + return null; + } + return mActivity.get(mActivity.size() - 2).get(); + } + + public void onActivityCreated(Activity activity) { + if (activity == null) { + return; + } + Activity existActivity = getActivity(activity.getClass()); + if (existActivity != null) { + CoreLogger.error(TAG, "已存在多个相同的实例:" + existActivity.getClass()); + existActivity.finish();//如果onActivityCreated回调时返回栈里面已存在当前Activity的实例,则先关掉之前的Activity,避免创建过多实例消耗太多内存 + } + for (WeakReference ac : mActivity) { + Activity realActivity = ac.get(); + if (realActivity == null || realActivity != activity) { + continue; + } + mActivity.remove(ac); + break; + } + mActivity.add(new WeakReference<>(activity)); + if (!ActWhiteListMrg.isTempActivity(activity)) { + if (mTopActivity == null) { + mTopActivity = new WeakReference<>(activity); + } else if (mTopActivity.get() != activity) { + mTopActivity.clear(); + mTopActivity = new WeakReference<>(activity); + } + } + if (activity instanceof AVRoomActivity) { + if (mAvRoomActivity == null) { + mAvRoomActivity = new WeakReference<>(activity); + } else if (mAvRoomActivity.get() != activity) { + if(mAvRoomActivity != null) { + mAvRoomActivity.clear(); + mAvRoomActivity = new WeakReference<>(activity); + } + } + } + } + + public void onActivityResumed(Activity activity) { + if (activity == null) { + return; + } + if (!ActWhiteListMrg.isTempActivity(activity)) { + if (mTopActivity == null) { + mTopActivity = new WeakReference<>(activity); + } else if (mTopActivity.get() != activity) { + mTopActivity.clear(); + mTopActivity = new WeakReference<>(activity); + } + } + if (activity instanceof AVRoomActivity) { + if (mAvRoomActivity == null) { + mAvRoomActivity = new WeakReference<>(activity); + } else if (mAvRoomActivity.get() != activity) { + if(mAvRoomActivity != null) { + mAvRoomActivity.clear(); + mAvRoomActivity = new WeakReference<>(activity); + } + } + } + } + + public void onActivityDestroyed(Activity activity) { + if (activity == null) { + return; + } + for (WeakReference ac : mActivity) { + Activity realActivity = ac.get(); + if (realActivity == null || realActivity != activity) { + continue; + } + mActivity.remove(ac); + break; + } + if (activity instanceof AVRoomActivity) { + if(mAvRoomActivity != null) { + mAvRoomActivity.clear(); + mAvRoomActivity = null; + } + } + } + + private boolean isActivityValid(WeakReference activityWeakReference) { + return activityWeakReference != null && activityWeakReference.get() != null && !activityWeakReference.get().isFinishing() && !activityWeakReference.get().isDestroyed(); + } + +} diff --git a/app/src/main/java/com/chwl/app/common/dialog/DialogCommon.kt b/app/src/main/java/com/chwl/app/common/dialog/DialogCommon.kt new file mode 100644 index 0000000..609a962 --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/dialog/DialogCommon.kt @@ -0,0 +1,45 @@ +package com.chwl.app.common.dialog + +import android.view.Gravity +import android.view.View +import android.view.WindowManager +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.databinding.DialogCommonBinding +import com.chwl.library.common.util.ClickUtils.click +import com.example.lib_utils.ktx.dp + +class DialogCommon : BaseDialogFragment() { + + + override var width = 290.dp + override var height = WindowManager.LayoutParams.WRAP_CONTENT + override var dimAmount = 0.3f + override var gravity = Gravity.CENTER + + + var mTitle = "" + var mContentLayout : View? = null + + + override fun init() { + + if (mContentLayout == null) { + mContentLayout = View(context) + } + + binding.btnOk.click { + dismiss() + } + + + binding.title.text = mTitle + binding.contentLayout.addView(mContentLayout) + } + + + + + + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/common/permission/EasyPermissions.java b/app/src/main/java/com/chwl/app/common/permission/EasyPermissions.java new file mode 100644 index 0000000..882a386 --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/permission/EasyPermissions.java @@ -0,0 +1,300 @@ +/* + * Copyright Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.chwl.app.common.permission; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.graphics.Color; +import android.net.Uri; +import android.os.Build; +import android.provider.Settings; + +import androidx.annotation.Nullable; +import androidx.annotation.StringRes; +import androidx.appcompat.app.AlertDialog; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; +import androidx.fragment.app.Fragment; + +import com.chwl.app.common.widget.dialog.BaseAlertDialogBuilder; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + + +/** + * Android M (API >= 23). + */ +public class EasyPermissions { + + public static final int SETTINGS_REQ_CODE = 16061; + + private static final String TAG = "EasyPermissions"; + + public interface PermissionCallbacks extends + ActivityCompat.OnRequestPermissionsResultCallback { + + void onPermissionsGranted(int requestCode, List perms); + + void onPermissionsDenied(int requestCode, List perms); + + void onPermissionsAllGranted(); + + } + + /** + + */ + public static boolean hasPermissions(Context context, String... perms) { + // Always return true for SDK < M, let the system deal with the permissions + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + return true; + } + + for (String perm : perms) { + boolean hasPerm = (ContextCompat.checkSelfPermission(context, perm) == + PackageManager.PERMISSION_GRANTED); + if (!hasPerm) { + return false; + } + } + + return true; + } + + /** + + */ + public static void requestPermissions(final Object object, String rationale, + final int requestCode, final String... perms) { + requestPermissions(object, rationale, + android.R.string.ok, + android.R.string.cancel, + requestCode, perms); + } + + /** + + */ + public static void requestPermissions(final Object object, String rationale, + @StringRes int positiveButton, + @StringRes int negativeButton, + final int requestCode, final String... perms) { + + checkCallingObjectSuitability(object); + + boolean shouldShowRationale = false; + for (String perm : perms) { + shouldShowRationale = + shouldShowRationale || shouldShowRequestPermissionRationale(object, perm); + } + + if (shouldShowRationale) { + Activity activity = getActivity(object); + if (null == activity) { + return; + } + + AlertDialog dialog = new BaseAlertDialogBuilder(activity) + .setMessage(rationale) + .setPositiveButton(positiveButton, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + executePermissionsRequest(object, perms, requestCode); + } + }) + .setNegativeButton(negativeButton, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + // act as if the permissions were denied + if (object instanceof PermissionCallbacks) { + ((PermissionCallbacks) object).onPermissionsDenied(requestCode, Arrays.asList(perms)); + } + } + }).create(); + dialog.show(); + dialog.getButton(dialog.BUTTON_POSITIVE).setTextColor(Color.BLACK); + dialog.getButton(dialog.BUTTON_NEGATIVE).setTextColor(Color.BLACK); + } else { + executePermissionsRequest(object, perms, requestCode); + } + } + + /** + * + */ + public static void onRequestPermissionsResult(int requestCode, String[] permissions, + int[] grantResults, Object object) { + + checkCallingObjectSuitability(object); + + // Make a collection of granted and denied permissions from the request. + ArrayList granted = new ArrayList<>(); + ArrayList denied = new ArrayList<>(); + for (int i = 0; i < permissions.length; i++) { + String perm = permissions[i]; + if (grantResults[i] == PackageManager.PERMISSION_GRANTED) { + granted.add(perm); + } else { + denied.add(perm); + } + } + + // Report granted permissions, if any. + if (!granted.isEmpty()) { + // Notify callbacks + if (object instanceof PermissionCallbacks) { + ((PermissionCallbacks) object).onPermissionsGranted(requestCode, granted); + } + } + + // Report denied permissions, if any. + if (!denied.isEmpty()) { + if (object instanceof PermissionCallbacks) { + ((PermissionCallbacks) object).onPermissionsDenied(requestCode, denied); + } + } + + // If 100% successful, call annotated methods + if (!granted.isEmpty() && denied.isEmpty()) { + if (object instanceof PermissionCallbacks) + ((PermissionCallbacks) object).onPermissionsAllGranted(); + } + } + + + public static boolean checkDeniedPermissionsNeverAskAgain(final Object object, + String rationale, + @StringRes int positiveButton, + @StringRes int negativeButton, + List deniedPerms) { + return checkDeniedPermissionsNeverAskAgain(object, rationale, + positiveButton, negativeButton, null, deniedPerms); + } + + + public static boolean checkDeniedPermissionsNeverAskAgain(final Object object, + String rationale, + @StringRes int positiveButton, + @StringRes int negativeButton, + @Nullable DialogInterface.OnClickListener negativeButtonOnClickListener, + List deniedPerms) { + boolean shouldShowRationale; + for (String perm : deniedPerms) { + shouldShowRationale = shouldShowRequestPermissionRationale(object, perm); + if (!shouldShowRationale) { + final Activity activity = getActivity(object); + if (null == activity) { + return true; + } + + AlertDialog dialog = new BaseAlertDialogBuilder(activity) + .setMessage(rationale) + .setPositiveButton(positiveButton, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + Uri uri = Uri.fromParts("package", activity.getPackageName(), null); + intent.setData(uri); + startAppSettingsScreen(object, intent); + } + }) + .setNegativeButton(negativeButton, negativeButtonOnClickListener) + .create(); + dialog.show(); + + return true; + } + } + + return false; + } + + @TargetApi(23) + private static boolean shouldShowRequestPermissionRationale(Object object, String perm) { + if (object instanceof Activity) { + return ActivityCompat.shouldShowRequestPermissionRationale((Activity) object, perm); + } else if (object instanceof Fragment) { + return ((Fragment) object).shouldShowRequestPermissionRationale(perm); + } else if (object instanceof android.app.Fragment) { + return ((android.app.Fragment) object).shouldShowRequestPermissionRationale(perm); + } else { + return false; + } + } + + @TargetApi(23) + private static void executePermissionsRequest(Object object, String[] perms, int requestCode) { + checkCallingObjectSuitability(object); + + if (object instanceof Activity) { + ActivityCompat.requestPermissions((Activity) object, perms, requestCode); + } else if (object instanceof Fragment) { + ((Fragment) object).requestPermissions(perms, requestCode); + } else if (object instanceof android.app.Fragment) { + ((android.app.Fragment) object).requestPermissions(perms, requestCode); + } + } + + @TargetApi(11) + private static Activity getActivity(Object object) { + if (object instanceof Activity) { + return ((Activity) object); + } else if (object instanceof Fragment) { + return ((Fragment) object).getActivity(); + } else if (object instanceof android.app.Fragment) { + return ((android.app.Fragment) object).getActivity(); + } else { + return null; + } + } + + @TargetApi(11) + private static void startAppSettingsScreen(Object object, + Intent intent) { + if (object instanceof Activity) { + ((Activity) object).startActivityForResult(intent, SETTINGS_REQ_CODE); + } else if (object instanceof Fragment) { + ((Fragment) object).startActivityForResult(intent, SETTINGS_REQ_CODE); + } else if (object instanceof android.app.Fragment) { + ((android.app.Fragment) object).startActivityForResult(intent, SETTINGS_REQ_CODE); + } + } + + + private static void checkCallingObjectSuitability(Object object) { + // Make sure Object is an Activity or Fragment + boolean isActivity = object instanceof Activity; + boolean isSupportFragment = object instanceof Fragment; + boolean isAppFragment = object instanceof android.app.Fragment; + boolean isMinSdkM = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; + + if (!(isSupportFragment || isActivity || (isAppFragment && isMinSdkM))) { + if (isAppFragment) { + throw new IllegalArgumentException( + "Target SDK needs to be greater than 23 if caller is android.app.Fragment"); + } else { + throw new IllegalArgumentException("Caller must be an Activity or a Fragment."); + } + } + } + +} diff --git a/app/src/main/java/com/chwl/app/common/permission/PermissionActivity.java b/app/src/main/java/com/chwl/app/common/permission/PermissionActivity.java new file mode 100644 index 0000000..a81afe1 --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/permission/PermissionActivity.java @@ -0,0 +1,133 @@ +package com.chwl.app.common.permission; + + +import android.content.Intent; +import android.graphics.Color; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; + +import com.chwl.app.R; + +import java.util.List; + + +/* + * @创建者 Jrking + * @创建时间 2016/4/15 16:18 + * @描述 ${Activity基类 } + * @更新描述 ${适配6.0权限问题} + */ +public class PermissionActivity extends AppCompatActivity implements + EasyPermissions.PermissionCallbacks { + + protected static final int RC_PERM = 123; + + protected static int reSting = R.string.ask_again;//默认提示语句 + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); +// initStatusBar("#303F9F");//透明状态栏 + } + + public void initStatusBar(String strColor) { + StatusBarCompat.setStatusBarColor(this, Color.parseColor(strColor)); + StatusBarCompat.translucentStatusBar(this); + } + + @Override + protected void onStart() { + super.onStart(); + } + + @Override + protected void onResume() { + super.onResume(); + } + + @Override + protected void onPause() { + super.onPause(); + } + + @Override + protected void onStop() { + super.onStop(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + } + + + /** + * 权限回调接口 + */ + private CheckPermListener mListener; + + public interface CheckPermListener { + //权限通过后的回调方法 + void superPermission(); + } + + public void checkPermission(CheckPermListener listener, int resString, String... mPerms) { + mListener = listener; + if (EasyPermissions.hasPermissions(this, mPerms)) { + if (mListener != null) + mListener.superPermission(); + } else { + EasyPermissions.requestPermissions(this, getString(resString), RC_PERM, mPerms); + } + } + + /** + * 用户权限处理, + * 如果全部获取, 则直接过. + * 如果权限缺失, 则提示Dialog. + * + * @param requestCode 请求码 + * @param permissions 权限 + * @param grantResults 结果 + */ + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + + EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == EasyPermissions.SETTINGS_REQ_CODE) { + //设置返回 + } + } + + + @Override + public void onPermissionsGranted(int requestCode, List perms) { + //同意了某些权限可能不是全部 + } + + @Override + public void onPermissionsAllGranted() { + if (mListener != null) + mListener.superPermission();//同意了全部权限的回调 + } + + @Override + public void onPermissionsDenied(int requestCode, List perms) { + + EasyPermissions.checkDeniedPermissionsNeverAskAgain(this, + getString(R.string.perm_tip), + R.string.setting, R.string.cancel, null, perms); + } + + + +} diff --git a/app/src/main/java/com/chwl/app/common/permission/StatusBarCompat.java b/app/src/main/java/com/chwl/app/common/permission/StatusBarCompat.java new file mode 100644 index 0000000..9c549db --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/permission/StatusBarCompat.java @@ -0,0 +1,162 @@ +package com.chwl.app.common.permission; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Color; +import android.os.Build; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.widget.FrameLayout; + +import androidx.core.view.ViewCompat; + +/** + * Utils for status bar + * Created by qiu on 3/29/16. + */ +public class StatusBarCompat { + + private static final int COLOR_TRANSLUCENT = Color.parseColor("#00000000"); + + public static final int DEFAULT_COLOR_ALPHA = 112; + + /** + * set statusBarColor + * @param statusColor color + * @param alpha 0 - 255 + */ + public static void setStatusBarColor(Activity activity, int statusColor, int alpha) { + setStatusBarColor(activity, calculateStatusBarColor(statusColor, alpha)); + } + + public static void setStatusBarColor(Activity activity, int statusColor) { + Window window = activity.getWindow(); + ViewGroup mContentView = (ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + //First translucent status bar. + window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + //After LOLLIPOP not translucent status bar + window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + //Then call setStatusBarColor. + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + window.setStatusBarColor(statusColor); + //set child View not fill the system window + View mChildView = mContentView.getChildAt(0); + if (mChildView != null) { + ViewCompat.setFitsSystemWindows(mChildView, true); + } + } else { + ViewGroup mDecorView = (ViewGroup) window.getDecorView(); + if (mDecorView.getTag() != null && mDecorView.getTag() instanceof Boolean && (Boolean)mDecorView.getTag()) { + //if has add fake status bar view + View mStatusBarView = mDecorView.getChildAt(0); + if (mStatusBarView != null) { + mStatusBarView.setBackgroundColor(statusColor); + } + } else { + int statusBarHeight = getStatusBarHeight(activity); + //add margin + View mContentChild = mContentView.getChildAt(0); + if (mContentChild != null) { + ViewCompat.setFitsSystemWindows(mContentChild, false); + FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mContentChild.getLayoutParams(); + lp.topMargin += statusBarHeight; + mContentChild.setLayoutParams(lp); + } + //add fake status bar view + View mStatusBarView = new View(activity); + FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, statusBarHeight); + layoutParams.gravity = Gravity.TOP; + mStatusBarView.setLayoutParams(layoutParams); + mStatusBarView.setBackgroundColor(statusColor); + mDecorView.addView(mStatusBarView, 0); + mDecorView.setTag(true); + } + } + } + } + + public static void translucentStatusBar(Activity activity) { + translucentStatusBar(activity, false); + } + + /** + * change to full screen mode + * @param hideStatusBarBackground hide status bar alpha Background when SDK > 21, true if hide it + */ + public static void translucentStatusBar(Activity activity, boolean hideStatusBarBackground) { + Window window = activity.getWindow(); + ViewGroup mContentView = (ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT); + + //set child View not fill the system window + View mChildView = mContentView.getChildAt(0); + if (mChildView != null) { + ViewCompat.setFitsSystemWindows(mChildView, false); + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + int statusBarHeight = getStatusBarHeight(activity); + + //First translucent status bar. + window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + //After LOLLIPOP just set LayoutParams. + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + if (hideStatusBarBackground) { + window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + window.setStatusBarColor(COLOR_TRANSLUCENT); + } else { + window.setStatusBarColor(calculateStatusBarColor(COLOR_TRANSLUCENT, DEFAULT_COLOR_ALPHA)); + } + //must call requestApplyInsets, otherwise it will have space in screen bottom + if (mChildView != null) { + ViewCompat.requestApplyInsets(mChildView); + } + } else { + ViewGroup mDecorView = (ViewGroup) window.getDecorView(); + if (mDecorView.getTag() != null && mDecorView.getTag() instanceof Boolean && (Boolean)mDecorView.getTag()) { + mChildView = mDecorView.getChildAt(0); + //remove fake status bar view. + mContentView.removeView(mChildView); + mChildView = mContentView.getChildAt(0); + if (mChildView != null) { + FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mChildView.getLayoutParams(); + //cancel the margin top + if (lp != null && lp.topMargin >= statusBarHeight) { + lp.topMargin -= statusBarHeight; + mChildView.setLayoutParams(lp); + } + } + mDecorView.setTag(false); + } + } + } + } + + //Get status bar height + public static int getStatusBarHeight(Context context) { + int result = 0; + int resId = context.getResources().getIdentifier("status_bar_height", "dimen", "android"); + if (resId > 0) { + result = context.getResources().getDimensionPixelOffset(resId); + } + return result; + } + + //Get alpha color + private static int calculateStatusBarColor(int color, int alpha) { + float a = 1 - alpha / 255f; + int red = color >> 16 & 0xff; + int green = color >> 8 & 0xff; + int blue = color & 0xff; + red = (int) (red * a + 0.5); + green = (int) (green * a + 0.5); + blue = (int) (blue * a + 0.5); + return 0xff << 24 | red << 16 | green << 8 | blue; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/common/server/NetworkService.java b/app/src/main/java/com/chwl/app/common/server/NetworkService.java new file mode 100644 index 0000000..5d1eee8 --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/server/NetworkService.java @@ -0,0 +1,207 @@ +package com.chwl.app.common.server; + +import android.app.Service; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.IBinder; +import android.util.Log; + +import com.chwl.app.R; +import com.chwl.library.utils.ResUtil; + +public class NetworkService extends Service { + + // Class that answers queries about the state of network connectivity. + // 系统网络连接相关的操作管理类. + + private ConnectivityManager connectivityManager; + // Describes the status of a network interface. + // 网络状态信息的实例 + private NetworkInfo info; + + /** + * 当前处于的网络 0 :null 1 :2G/3G 2 :wifi + */ + public static int netState; + + public static final String ACTION_NETWORK_STATE_CHANGE_SUCCESS = "ACTION_NETWORK_STATE_CHANGE_SUCCESS"; // An + // action + public static final String ACTION_NETWORK_STATE_CHANGE_FAILED = "ACTION_NETWORK_STATE_CHANGE_FAILED"; // An + private String TAG = "NetworkService"; + + private int count = -1; + + + /** + * 广播实例 + */ + private BroadcastReceiver mReceiver = new BroadcastReceiver() { + + @Override + public void onReceive(Context context, Intent intent) { + System.out.println(ResUtil.getString(R.string.common_server_networkservice_01)); + // The action of this intent or null if none is specified. + // action是行动的意思,也许是我水平问题无法理解为什么叫行动,我一直理解为标识(现在理解为意图) + String action = intent.getAction(); // 当前接受到的广播的标识(行动/意图) + + // 当当前接受到的广播的标识(意图)为网络状态的标识时做相应判断 + if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { + // 获取网络连接管理器 + connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); + + // 获取当前网络状态信息 + info = connectivityManager.getActiveNetworkInfo(); + + if (info != null && info.isAvailable()) { + + // 当NetworkInfo不为空且是可用的情况下,获取当前网络的Type状态 + // 根据NetworkInfo.getTypeName()判断当前网络 + String name = info.getTypeName(); + + // 更改NetworkService的静态变量,之后只要在Activity中进行判断就好了 + if (name.equals("WIFI")) { + netState = 2; + } else { + netState = 1; + } + + } else { + // NetworkInfo为空或者是不可用的情况下 + netState = 0; + +// Toast.makeText(context, ResUtil.getString(R.string.common_server_networkservice_02), Toast.LENGTH_SHORT).show(); + + /** + * 这里推荐使用本地广播的方式发送: + * LocalBroadcastManager.getInstance(getApplicationContext() + * ).sendBroadcast(intent); + */ + } + + if(netState == 0){ + sendNetBroadCast(ACTION_NETWORK_STATE_CHANGE_FAILED,netState); + Log.d(TAG, ResUtil.getString(R.string.common_server_networkservice_03)); + }else{ +// if (count != -1) { +// if (!ConnectionManager.getInstance().getConnection().isConnected()) { +// Log.d(TAG, ResUtil.getString(R.string.common_server_networkservice_04) + count); +// ChatManager.getInstance().reconnect(ChatManager.getInstance().getWorkHandler());// 重连服务器 +// } +// Log.d(TAG, ResUtil.getString(R.string.common_server_networkservice_05)); +// } + count++; + } + +// switch (netState) { +// case 2:// WIFI +// Log.d(TAG, ResUtil.getString(R.string.common_server_networkservice_06)); +// if (count != -1) { +// if (!ConnectionManager.getInstance().getConnection().isConnected()) { +// Log.d(TAG, ResUtil.getString(R.string.common_server_networkservice_07) + count); +// ChatManager.getInstance().reconnect(ChatManager.getInstance().getWorkHandler());// 重连服务器 +// } +// +// } +// count++; +// break; +// case 1:// other +// Log.d(TAG, ResUtil.getString(R.string.common_server_networkservice_08)); +// if (count != -1) { +// if (!ConnectionManager.getInstance().getConnection().isConnected()) { +// Log.d(TAG, ResUtil.getString(R.string.common_server_networkservice_09) + count); +// ChatManager.getInstance().reconnect(ChatManager.getInstance().getWorkHandler());// 重连服务器 +// } +// +// } +// count++; +// break; +// case 0:// no net +// Log.d(TAG, ResUtil.getString(R.string.common_server_networkservice_010)); +// break; +// +// default: +// break; +// } + + + } + } + }; + + /** + * 网络链接上的广播 + */ + public void sendNetBroadCast(String action, int netState){ + Intent it = new Intent(); + it.putExtra("networkStatus", netState); + it.setAction(action); + sendBroadcast(it); // 发送无网络广播给注册了当前服务广播的Activity + } + +// private ChatMsgFactory msgFactory; +// private ChatManager chatManager; + + // /** + // * 发送文字消息 + // */ + // private void sendTextReConnected(ChatMsg msg) { + // SendMsg sendMsg = msgFactory.creatSendMsgForGroupText(msg.getToUserId(), + // msg.getChatId(), msg.getContent()); + // chatManager.sendText(sendMsg); + // } + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public void onCreate() { + super.onCreate(); + System.out.println(ResUtil.getString(R.string.common_server_networkservice_011)); +// msgFactory = ChatMsgFactory.getInstance(); +// chatManager = ChatManager.getInstance(); + + // 注册网络状态的广播,绑定到mReceiver + IntentFilter mFilter = new IntentFilter(); + mFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); + registerReceiver(mReceiver, mFilter); + } + + @Override + public void onDestroy() { + super.onDestroy(); + System.out.println(ResUtil.getString(R.string.common_server_networkservice_012)); + // 注销接收 + unregisterReceiver(mReceiver); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + return super.onStartCommand(intent, flags, startId); + } + + /** + * 判断网络是否可用 + */ + public static boolean isNetworkAvailable(Context context) { + // 获取网络连接管理器 + ConnectivityManager mgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + + // 获取当前网络状态信息 + NetworkInfo[] info = mgr.getAllNetworkInfo(); + if (info != null) { + for (int i = 0; i < info.length; i++) { + if (info[i].getState() == NetworkInfo.State.CONNECTED) { + return true; + } + } + } + + return false; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/common/svga/SimpleSvgaCallback.java b/app/src/main/java/com/chwl/app/common/svga/SimpleSvgaCallback.java new file mode 100644 index 0000000..86da85b --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/svga/SimpleSvgaCallback.java @@ -0,0 +1,29 @@ +package com.chwl.app.common.svga; + +import com.opensource.svgaplayer.SVGACallback; + +/** + * Created by MadisonRong on 31/03/2018. + */ + +public class SimpleSvgaCallback implements SVGACallback { + @Override + public void onPause() { + + } + + @Override + public void onFinished() { + + } + + @Override + public void onRepeat() { + + } + + @Override + public void onStep(int i, double v) { + + } +} diff --git a/app/src/main/java/com/chwl/app/common/svga/SimpleSvgaParseCompletion.java b/app/src/main/java/com/chwl/app/common/svga/SimpleSvgaParseCompletion.java new file mode 100644 index 0000000..6d056fd --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/svga/SimpleSvgaParseCompletion.java @@ -0,0 +1,20 @@ +package com.chwl.app.common.svga; + +import com.opensource.svgaplayer.SVGAParser; +import com.opensource.svgaplayer.SVGAVideoEntity; + +/** + * Created by MadisonRong on 31/03/2018. + */ + +public class SimpleSvgaParseCompletion implements SVGAParser.ParseCompletion { + @Override + public void onComplete(SVGAVideoEntity svgaVideoEntity) { + + } + + @Override + public void onError() { + + } +} diff --git a/app/src/main/java/com/chwl/app/common/util/AppLifeCycleHelper.java b/app/src/main/java/com/chwl/app/common/util/AppLifeCycleHelper.java new file mode 100644 index 0000000..d17baf3 --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/util/AppLifeCycleHelper.java @@ -0,0 +1,90 @@ +package com.chwl.app.common.util; + +import android.app.Activity; +import android.app.Application; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.chwl.app.BuildConfig; +import com.chwl.app.application.App; +import com.chwl.core.utils.LogUtils; +import com.chwl.library.common.util.CoreUtils; + +/** + * Activity生命周期工具类 + */ +public class AppLifeCycleHelper implements Application.ActivityLifecycleCallbacks{ + private static boolean sBackground = false; + private static int sActivityReferences = 0; + private static boolean sIsActivityChangingConfigurations = false; + private static OnAppVisibleChange sOnAppVisibleChange = new OnAppVisibleChange(); + + @Override + public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle bundle) { + App.gStack.onActivityCreated(activity); + } + + @Override + public void onActivityStarted(@NonNull Activity activity) { + if (BuildConfig.DEBUG) { + LogUtils.d("当前Activity : "+ activity.getClass().getSimpleName()); + } + if (++AppLifeCycleHelper.sActivityReferences == 1 && !AppLifeCycleHelper.sIsActivityChangingConfigurations) { + AppLifeCycleHelper.onForeground(); + + //应用回到前台了 +// if (AuthModel.get().isImLogin()) { +// +// } + } + } + + @Override + public void onActivityResumed(@NonNull Activity activity) { + App.gStack.onActivityResumed(activity); +// Adjust.onResume(); + } + + @Override + public void onActivityPaused(@NonNull Activity activity) { +// Adjust.onPause(); + } + + @Override + public void onActivityStopped(@NonNull Activity activity) { + AppLifeCycleHelper.sIsActivityChangingConfigurations = activity.isChangingConfigurations(); + if (--AppLifeCycleHelper.sActivityReferences == 0 && !AppLifeCycleHelper.sIsActivityChangingConfigurations) { + AppLifeCycleHelper.onBackground(); + } + } + + @Override + public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle bundle) { + + } + + @Override + public void onActivityDestroyed(@NonNull Activity activity) { + App.gStack.onActivityDestroyed(activity); + } + + private static void onForeground() { + sBackground = false; + CoreUtils.send(sOnAppVisibleChange); + } + + private static void onBackground() { + sBackground = true; + CoreUtils.send(sOnAppVisibleChange); + } + + public static boolean isBackground() { + return sBackground; + } + + public static class OnAppVisibleChange { + } +} + diff --git a/app/src/main/java/com/chwl/app/common/util/BitmapUtil.java b/app/src/main/java/com/chwl/app/common/util/BitmapUtil.java new file mode 100644 index 0000000..1aa267a --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/util/BitmapUtil.java @@ -0,0 +1,164 @@ +package com.chwl.app.common.util; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Matrix; +import android.graphics.Point; +import android.net.Uri; + +import com.chwl.app.application.App; + +import java.io.ByteArrayOutputStream; +import java.io.FileDescriptor; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; + +import com.chwl.library.common.util.LibLogger; + +/** + * Created by wushaocheng + * Date: 2022/11/17 + */ +public class BitmapUtil { + + private static final String TAG = "BitmapUtil"; + + public static Bitmap decodeSampledBitmapFromFileDescriptor(FileDescriptor fd, int reqWidth, int reqHeight) { + final BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + options.inPreferredConfig = Bitmap.Config.RGB_565; + BitmapFactory.decodeFileDescriptor(fd, null, options); + options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); + options.inJustDecodeBounds = false; + return BitmapFactory.decodeFileDescriptor(fd, null, options); + } + + private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { + if (reqWidth == 0 || reqHeight == 0) { + return 1; + } + + final int height = options.outHeight; + final int width = options.outWidth; + LibLogger.info(TAG, "origin, w= " + width + " h=" + height); + int inSampleSize = 1; + + if (height > reqHeight || width > reqWidth) { + final int halfHeight = height / 2; + final int halfWidth = width / 2; + + while ((halfHeight / inSampleSize) >= reqHeight + && (halfWidth / inSampleSize) >= reqWidth) { + inSampleSize *= 2; + } + } + + LibLogger.info(TAG, "sampleSize:" + inSampleSize); + return inSampleSize; + } + + public static Bitmap setImgSize(Bitmap bm, float newWidth, float newHeight) { + if (bm == null) { + LibLogger.error(TAG, "bitmap is null."); + return null; + } + // 获得图片的宽高. + int width = bm.getWidth(); + int height = bm.getHeight(); + // 计算缩放比例. + float scaleWidth = newWidth / width; + float scaleHeight = newHeight / height; + // 取得想要缩放的matrix参数. + Matrix matrix = new Matrix(); + matrix.postScale(scaleWidth, scaleHeight); + // 得到新的图片. + return Bitmap.createBitmap(bm, 0, 0, width, height, matrix, true); + } + + public static Point getImageSize(String imgPath) { + Point point = new Point(); + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeFile(imgPath, options); + point.x = options.outWidth; + point.y = options.outHeight; + return point; + } + + /** + * 获取sd卡上的bitmap的大小 + * 不加载进内存 + */ + public static long getSdBitmapSize(Uri imageUri) { + return getSdBitmapSize(imageUri, null); + } + + /** + * androidQ 以上使用path拿不到图片信息,换成Uri + * + * @param imageUri + * @param inPreferredConfig + * @return + */ + private static long getSdBitmapSize(Uri imageUri, Bitmap.Config inPreferredConfig) { + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + if (inPreferredConfig != null) { + options.inPreferredConfig = inPreferredConfig; + } + try { + InputStream stream = App.gContext.getContentResolver().openInputStream(imageUri); + BitmapFactory.decodeStream(stream, null, options); + switch (options.inPreferredConfig) { + case ALPHA_8: + return options.outWidth * options.outHeight; + case RGB_565: + case ARGB_4444: + return options.outWidth * options.outHeight * 2; + case RGBA_F16: + return options.outWidth * options.outHeight * 8; + case ARGB_8888: + default: + return options.outWidth * options.outHeight * 4; + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + return 0; + } + } + + + public static Bitmap convertBitmap(Bitmap bitmap) { + if (bitmap == null) { + return null; + } + float density = App.gContext.getResources().getDisplayMetrics().density; + return BitmapUtil.setImgSize(bitmap, bitmap.getWidth() * density / 3.0f, bitmap.getHeight() * density / 3.0f); + } + + public static int caculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { + int width = options.outWidth; + int height = options.outHeight; + int inSampleSize = 1; + if (width > reqWidth || height > reqHeight) { + int widthRadio = Math.round(width * 1.0f / reqWidth); + int heightRadio = Math.round(height * 1.0f / reqHeight); + inSampleSize = Math.max(widthRadio, heightRadio); + } + return inSampleSize; + } + + + public static byte[] inputStream2ByteArr(InputStream inputStream) throws IOException { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + byte[] buff = new byte[1024]; + int len = 0; + while ( (len = inputStream.read(buff)) != -1) { + outputStream.write(buff, 0, len); + } + inputStream.close(); + outputStream.close(); + return outputStream.toByteArray(); + } +} diff --git a/app/src/main/java/com/chwl/app/common/util/DialogCommonUtil.java b/app/src/main/java/com/chwl/app/common/util/DialogCommonUtil.java new file mode 100644 index 0000000..1fb99eb --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/util/DialogCommonUtil.java @@ -0,0 +1,41 @@ +package com.chwl.app.common.util; + +import android.content.Context; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.chwl.app.R; +import com.chwl.app.common.dialog.DialogCommon; +import com.chwl.library.common.util.OtherExtKt; +import com.example.lib_utils.ktx.ResourcesKtxKt; + +public class DialogCommonUtil { + + + public static void showManagerLimit(Context context) { + DialogCommon dialogCommon = new DialogCommon(); + + LinearLayout layout = new LinearLayout(context); + layout.setOrientation(LinearLayout.VERTICAL); + + TextView textView = new TextView(context); + textView.setTextColor(ResourcesKtxKt.getColor(R.color.color_313131)); + textView.setTextSize(13); + textView.setText(ResourcesKtxKt.getString(R.string.roomManagerLimitErrorTips)); + textView.setPadding(OtherExtKt.toDP(25), 0, OtherExtKt.toDP(25), 0); + layout.addView(textView); + OtherExtKt.setViewWH(textView,LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT,false); + + ImageView imageView = new ImageView(context); + imageView.setImageResource(R.drawable.icon_manager_admin); + layout.addView(imageView); + OtherExtKt.setViewWH(imageView,LinearLayout.LayoutParams.MATCH_PARENT,OtherExtKt.toDP(258),false); + OtherExtKt.setMargin(imageView,23,10,23,10,true); + + dialogCommon.setMTitle(ResourcesKtxKt.getString(R.string.Tip)); + + dialogCommon.setMContentLayout(layout); + dialogCommon.show(context); + } +} diff --git a/app/src/main/java/com/chwl/app/common/util/PauseWorkerHandler.java b/app/src/main/java/com/chwl/app/common/util/PauseWorkerHandler.java new file mode 100644 index 0000000..e45ae01 --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/util/PauseWorkerHandler.java @@ -0,0 +1,86 @@ +package com.chwl.app.common.util; + +import android.os.Handler; +import android.os.Looper; +import com.chwl.core.utils.CoreLogger; + +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.HashMap; +import java.util.Map; +import java.util.Vector; + +import com.chwl.library.common.util.CoreUtils; + +/** + * Created by logwee on 2019/4/9. + */ +public class PauseWorkerHandler { + + private static PauseWorkerHandler sInstance = new PauseWorkerHandler(); + + private static final String TAG = "PauseWorkerHandler"; + public static final int CHECK_VISIBLE_INTERVAL = 500; + + private final Vector mRunnableQueueBuffer = new Vector<>(); + private final Map mSingleRunnableQueueBuffer = new HashMap<>(); + private boolean mPaused = false; + private Handler mHandler = new Handler(Looper.getMainLooper()); + + public static PauseWorkerHandler instance() { + return sInstance; + } + + private PauseWorkerHandler() { + CoreUtils.register(this); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onAppVisibleChangeEvent(AppLifeCycleHelper.OnAppVisibleChange event) { + mPaused = AppLifeCycleHelper.isBackground(); + mHandler.removeCallbacks(mCheckAppVisible); + mHandler.postDelayed(mCheckAppVisible, CHECK_VISIBLE_INTERVAL); + } + + private Runnable mCheckAppVisible = new Runnable() { + @Override + public void run() { + boolean isBackground = AppLifeCycleHelper.isBackground(); + CoreLogger.info(TAG, "onAppVisibleChangeEvent isBackground="+isBackground); + if (isBackground) { + pause(); + } else { + resume(); + } + } + }; + + public void post(Runnable runnable) { + if (mPaused) { + mRunnableQueueBuffer.add(runnable); + } else { + runnable.run(); + } + } + + public void resume() { + mPaused = false; + int size = mRunnableQueueBuffer.size(); + for (int i = 0; i < size; i++) { + final Runnable runnable = mRunnableQueueBuffer.elementAt(i); + runnable.run(); + } + mRunnableQueueBuffer.clear(); + + for (Map.Entry stringRunnableEntry : mSingleRunnableQueueBuffer.entrySet()) { + stringRunnableEntry.getValue().run(); + } + mSingleRunnableQueueBuffer.clear(); + } + + public void pause() { + mPaused = true; + } + +} diff --git a/app/src/main/java/com/chwl/app/common/widget/AgeSexView.java b/app/src/main/java/com/chwl/app/common/widget/AgeSexView.java new file mode 100644 index 0000000..afe8f00 --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/widget/AgeSexView.java @@ -0,0 +1,56 @@ +package com.chwl.app.common.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.chwl.app.R; + +/** + * Created by zhouxiangfeng on 17/2/26. + */ + +public class AgeSexView extends LinearLayout { + + private ImageView sexIv; + private TextView ageTv; + + public AgeSexView(Context context) { + super(context); + init(); + } + + public AgeSexView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public AgeSexView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + private void init(){ + View mView = LayoutInflater.from(getContext()).inflate(R.layout.layout_zone_age_sex_view,this,true); + sexIv = (ImageView)mView.findViewById(R.id.sex_iv); + ageTv = (TextView)mView.findViewById(R.id.age_tv); + } + + + + public AgeSexView setSexImg(int resId){ + sexIv.setImageResource(resId); + return this; + } + + + public AgeSexView setAgeText(int age){ + ageTv.setText(String.valueOf(age)); + return this; + } + +} diff --git a/app/src/main/java/com/chwl/app/common/widget/BadgeView.java b/app/src/main/java/com/chwl/app/common/widget/BadgeView.java new file mode 100644 index 0000000..f5f7c96 --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/widget/BadgeView.java @@ -0,0 +1,447 @@ +package com.chwl.app.common.widget; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Color; +import android.graphics.Typeface; +import android.graphics.drawable.ShapeDrawable; +import android.graphics.drawable.shapes.RoundRectShape; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewGroup.LayoutParams; +import android.view.ViewParent; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.AlphaAnimation; +import android.view.animation.Animation; +import android.view.animation.DecelerateInterpolator; +import android.widget.FrameLayout; +import android.widget.TabWidget; +import android.widget.TextView; + +/** + * A simple text label view that can be applied as a "badge" to any given {@link View}. + * This class is intended to be instantiated at runtime rather than included in XML layouts. + * + * @author Jeff Gilfelt + */ +public class BadgeView extends TextView { + + public static final int POSITION_TOP_LEFT = 1; + public static final int POSITION_TOP_RIGHT = 2; + public static final int POSITION_BOTTOM_LEFT = 3; + public static final int POSITION_BOTTOM_RIGHT = 4; + public static final int MY_POSITION_TOP_LEFT = 5; + + private static final int DEFAULT_MARGIN_DIP = 5; + private static final int DEFAULT_LR_PADDING_DIP = 5; + private static final int DEFAULT_CORNER_RADIUS_DIP = 8; + private static final int DEFAULT_POSITION = POSITION_TOP_RIGHT; + private static final int DEFAULT_BADGE_COLOR = Color.RED; + private static final int DEFAULT_TEXT_COLOR = Color.WHITE; + + private static Animation fadeIn; + private static Animation fadeOut; + + private Context context; + private View target; + + private int badgePosition; + private int badgeMargin; + private int badgeColor; + + private boolean isShown; + + private ShapeDrawable badgeBg; + + private int targetTabIndex; + + + public BadgeView(Context context) { + this(context, (AttributeSet) null, android.R.attr.textViewStyle); + } + + public BadgeView(Context context, AttributeSet attrs) { + this(context, attrs, android.R.attr.textViewStyle); + } + + /** + * Constructor - + * + * create a new BadgeView instance attached to a target {@link View}. + * + * @param context context for this view. + * @param target the View to attach the badge to. + */ + public BadgeView(Context context, View target) { + this(context, null, android.R.attr.textViewStyle, target, 0); + } + + /** + * Constructor - + * + * create a new BadgeView instance attached to a target {@link TabWidget} + * tab at a given index. + * + * @param context context for this view. + * @param target the TabWidget to attach the badge to. + * @param index the position of the tab within the target. + */ + public BadgeView(Context context, TabWidget target, int index) { + this(context, null, android.R.attr.textViewStyle, target, index); + } + + public BadgeView(Context context, AttributeSet attrs, int defStyle) { + this(context, attrs, defStyle, null, 0); + } + + public BadgeView(Context context, AttributeSet attrs, int defStyle, View target, int tabIndex) { + super(context, attrs, defStyle); + init(context, target, tabIndex); + } + + private void init(Context context, View target, int tabIndex) { + + this.context = context; + this.target = target; + this.targetTabIndex = tabIndex; + + // apply defaults + badgePosition = DEFAULT_POSITION; + badgeMargin = dipToPixels(DEFAULT_MARGIN_DIP); + badgeColor = DEFAULT_BADGE_COLOR; + + setTypeface(Typeface.DEFAULT_BOLD); + int paddingPixels = dipToPixels(DEFAULT_LR_PADDING_DIP); + setPadding(paddingPixels, 0, paddingPixels, 0); + setTextColor(DEFAULT_TEXT_COLOR); + + fadeIn = new AlphaAnimation(0, 1); + fadeIn.setInterpolator(new DecelerateInterpolator()); + fadeIn.setDuration(200); + + fadeOut = new AlphaAnimation(1, 0); + fadeOut.setInterpolator(new AccelerateInterpolator()); + fadeOut.setDuration(200); + + isShown = false; + + if (this.target != null) { + applyTo(this.target); + } else { + show(); + } + + } + + private void applyTo(View target) { + + LayoutParams lp = target.getLayoutParams(); + ViewParent parent = target.getParent(); + FrameLayout container = new FrameLayout(context); + + if (target instanceof TabWidget) { + + // set target to the relevant tab child container + target = ((TabWidget) target).getChildTabViewAt(targetTabIndex); + this.target = target; + + ((ViewGroup) target).addView(container, + new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); + + this.setVisibility(View.GONE); + container.addView(this); + + } else { + + // TODO verify that parent is indeed a ViewGroup + ViewGroup group = (ViewGroup) parent; + int index = group.indexOfChild(target); + + group.removeView(target); + group.addView(container, index, lp); + + container.addView(target); + + this.setVisibility(View.GONE); + container.addView(this); + + group.invalidate(); + + } + + } + + /** + * Make the badge visible in the UI. + * + */ + public void show() { + show(false, null); + } + + /** + * Make the badge visible in the UI. + * + * @param animate flag to apply the default fade-in animation. + */ + public void show(boolean animate) { + show(animate, fadeIn); + } + + /** + * Make the badge visible in the UI. + * + * @param anim Animation to apply to the view when made visible. + */ + public void show(Animation anim) { + show(true, anim); + } + + /** + * Make the badge non-visible in the UI. + * + */ + public void hide() { + hide(false, null); + } + + /** + * Make the badge non-visible in the UI. + * + * @param animate flag to apply the default fade-out animation. + */ + public void hide(boolean animate) { + hide(animate, fadeOut); + } + + /** + * Make the badge non-visible in the UI. + * + * @param anim Animation to apply to the view when made non-visible. + */ + public void hide(Animation anim) { + hide(true, anim); + } + + /** + * Toggle the badge visibility in the UI. + * + */ + public void toggle() { + toggle(false, null, null); + } + + /** + * Toggle the badge visibility in the UI. + * + * @param animate flag to apply the default fade-in/out animation. + */ + public void toggle(boolean animate) { + toggle(animate, fadeIn, fadeOut); + } + + /** + * Toggle the badge visibility in the UI. + * + * @param animIn Animation to apply to the view when made visible. + * @param animOut Animation to apply to the view when made non-visible. + */ + public void toggle(Animation animIn, Animation animOut) { + toggle(true, animIn, animOut); + } + + private void show(boolean animate, Animation anim) { + if (getBackground() == null) { + if (badgeBg == null) { + badgeBg = getDefaultBackground(); + } + setBackgroundDrawable(badgeBg); + } + applyLayoutParams(); + + if (animate) { + this.startAnimation(anim); + } + this.setVisibility(View.VISIBLE); + isShown = true; + } + + private void hide(boolean animate, Animation anim) { + this.setVisibility(View.GONE); + if (animate) { + this.startAnimation(anim); + } + isShown = false; + } + + private void toggle(boolean animate, Animation animIn, Animation animOut) { + if (isShown) { + hide(animate && (animOut != null), animOut); + } else { + show(animate && (animIn != null), animIn); + } + } + + /** + * Increment the numeric badge label. If the current badge label cannot be converted to + * an integer value, its label will be set to "0". + * + * @param offset the increment offset. + */ + public int increment(int offset) { + CharSequence txt = getText(); + int i; + if (txt != null) { + try { + i = Integer.parseInt(txt.toString()); + } catch (NumberFormatException e) { + i = 0; + } + } else { + i = 0; + } + i = i + offset; + setText(String.valueOf(i)); + return i; + } + + /** + * Decrement the numeric badge label. If the current badge label cannot be converted to + * an integer value, its label will be set to "0". + * + * @param offset the decrement offset. + */ + public int decrement(int offset) { + return increment(-offset); + } + + private ShapeDrawable getDefaultBackground() { + + int r = dipToPixels(DEFAULT_CORNER_RADIUS_DIP); + float[] outerR = new float[] {r, r, r, r, r, r, r, r}; + + RoundRectShape rr = new RoundRectShape(outerR, null, null); + ShapeDrawable drawable = new ShapeDrawable(rr); + drawable.getPaint().setColor(badgeColor); + + return drawable; + + } + + private void applyLayoutParams() { + + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + int width = getWidth(); + switch (badgePosition) { + + case MY_POSITION_TOP_LEFT: + lp.gravity = Gravity.LEFT | Gravity.TOP; + lp.setMargins(badgeMargin + target.getWidth()/8+ 15 , badgeMargin, 0, 0); + break; + + case POSITION_TOP_LEFT: + lp.gravity = Gravity.LEFT | Gravity.TOP; + lp.setMargins(badgeMargin, badgeMargin, 0, 0); + break; + case POSITION_TOP_RIGHT: + lp.gravity = Gravity.RIGHT | Gravity.TOP; + lp.setMargins(0, badgeMargin, badgeMargin, 0); + break; + case POSITION_BOTTOM_LEFT: + lp.gravity = Gravity.LEFT | Gravity.BOTTOM; + lp.setMargins(badgeMargin, 0, 0, badgeMargin); + break; + case POSITION_BOTTOM_RIGHT: + lp.gravity = Gravity.RIGHT | Gravity.BOTTOM; + lp.setMargins(0, 0, badgeMargin, badgeMargin); + break; + default: + break; + } + + setLayoutParams(lp); + + } + + /** + * Returns the target View this badge has been attached to. + * + */ + public View getTarget() { + return target; + } + + /** + * Is this badge currently visible in the UI? + * + */ + @Override + public boolean isShown() { + return isShown; + } + + /** + * Returns the positioning of this badge. + * + * one of POSITION_TOP_LEFT, POSITION_TOP_RIGHT, POSITION_BOTTOM_LEFT, POSITION_BOTTOM_RIGHT. + * + */ + public int getBadgePosition() { + return badgePosition; + } + + /** + * Set the positioning of this badge. + * + * @param layoutPosition one of POSITION_TOP_LEFT, POSITION_TOP_RIGHT, POSITION_BOTTOM_LEFT, POSITION_BOTTOM_RIGHT. + * + */ + public void setBadgePosition(int layoutPosition) { + this.badgePosition = layoutPosition; + } + + /** + * Returns the horizontal/vertical margin from the target View that is applied to this badge. + * + */ + public int getBadgeMargin() { + return badgeMargin; + } + + /** + * Set the horizontal/vertical margin from the target View that is applied to this badge. + * + * @param badgeMargin the margin in pixels. + */ + public void setBadgeMargin(int badgeMargin) { + this.badgeMargin = badgeMargin; + } + + /** + * Returns the color value of the badge background. + * + */ + public int getBadgeBackgroundColor() { + return badgeColor; + } + + /** + * Set the color value of the badge background. + * + * @param badgeColor the badge background color. + */ + public void setBadgeBackgroundColor(int badgeColor) { + this.badgeColor = badgeColor; + badgeBg = getDefaultBackground(); + } + + private int dipToPixels(int dip) { + Resources r = getResources(); + float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, r.getDisplayMetrics()); + return (int) px; + } + +} diff --git a/app/src/main/java/com/chwl/app/common/widget/ChangeColorIconWithText.java b/app/src/main/java/com/chwl/app/common/widget/ChangeColorIconWithText.java new file mode 100644 index 0000000..17c933c --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/widget/ChangeColorIconWithText.java @@ -0,0 +1,278 @@ +package com.chwl.app.common.widget; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.Bitmap.Config; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PaintFlagsDrawFilter; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.Rect; +import android.graphics.drawable.BitmapDrawable; +import android.os.Bundle; +import android.os.Looper; +import android.os.Parcelable; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.View; + +import com.chwl.app.R; + + +public class ChangeColorIconWithText extends View { + + private int mColor = 0xFF636363; + private Bitmap mIconBitmap; + private String mText = ""; + private int mTextSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 12, + getResources().getDisplayMetrics()); + + private Canvas mCanvas; + private Bitmap mBitmap; + private Paint mPaint; + + private float mAlpha; + + private Rect mIconRect; + private Rect mTextBound; + private Paint mTextPaint; + private String TAG = "ChangeColorIconWithText"; + + public ChangeColorIconWithText(Context context) { + this(context, null); + } + + public ChangeColorIconWithText(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + /** + * 获取自定义属性的值 + * + * @param context + * @param attrs + * @param defStyleAttr + */ + public ChangeColorIconWithText(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ChangeColorIconWithText); + + int n = a.getIndexCount(); + + for (int i = 0; i < n; i++) { + int attr = a.getIndex(i); + switch (attr) { + case R.styleable.ChangeColorIconWithText_icon: + BitmapDrawable drawable = (BitmapDrawable) a.getDrawable(attr); + mIconBitmap = drawable.getBitmap(); + break; + case R.styleable.ChangeColorIconWithText_color: + mColor = a.getColor(attr, 0xFF636363); + break; + case R.styleable.ChangeColorIconWithText_text: + mText = a.getString(attr); + break; + case R.styleable.ChangeColorIconWithText_text_size: + mTextSize = (int) a.getDimension(attr, + TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 12, getResources().getDisplayMetrics())); + break; + } + + } + + a.recycle(); + + mTextBound = new Rect(); + mTextPaint = new Paint(); + mTextPaint.setTextSize(mTextSize); + mTextPaint.setColor(mColor); + mTextPaint.getTextBounds(mText, 0, mText.length(), mTextBound); + } + + /** + * 图片宽和高的比例 + */ + private float ratio = 1f; + + public void setRatio(float ratio) { + this.ratio = ratio; + } + + @SuppressLint("DrawAllocation") + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + + // 父容器传过来的宽度方向上的模式 + int widthMode = MeasureSpec.getMode(widthMeasureSpec); + // 父容器传过来的高度方向上的模式 + int heightMode = MeasureSpec.getMode(heightMeasureSpec); + + // 父容器传过来的宽度的值 + int width = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() + - getPaddingRight(); + // 父容器传过来的高度的值 + int height = MeasureSpec.getSize(heightMeasureSpec) - getPaddingLeft() + - getPaddingRight(); + + if (widthMode == MeasureSpec.EXACTLY + && heightMode != MeasureSpec.EXACTLY) { + // 判断条件为,宽度模式为Exactly,也就是填充父窗体或者是指定宽度; + // 且高度模式不是Exaclty,代表设置的既不是fill_parent也不是具体的值,于是需要具体测量 + // 且图片的宽高比已经赋值完毕,不再是0.0f + // 表示宽度确定,要测量高度 + heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, + MeasureSpec.EXACTLY); + } else if (widthMode != MeasureSpec.EXACTLY + && heightMode == MeasureSpec.EXACTLY) { + // 判断条件跟上面的相反,宽度方向和高度方向的条件互换 + // 表示高度确定,要测量宽度 + + widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, + MeasureSpec.EXACTLY); + } + + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + int iconWidth = Math.min(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(), + getMeasuredHeight() - getPaddingTop() - getPaddingBottom() - mTextBound.height()); +// Log.d(TAG, String.valueOf(iconWidth)); + int left = getMeasuredWidth() / 2 - iconWidth / 2; + int top = getMeasuredHeight() / 2 - (mTextBound.height() + iconWidth) / 2; + mIconRect = new Rect(left, top, left + iconWidth, top + iconWidth); + + } + + public static int resolveSize(int size, int measureSpec) { + int result = size; + int specMode = MeasureSpec.getMode(measureSpec); + int specSize = MeasureSpec.getSize(measureSpec); + switch (specMode) { + case MeasureSpec.UNSPECIFIED: + result = size; + break; + case MeasureSpec.AT_MOST: + result = Math.min(size, specSize); + break; + case MeasureSpec.EXACTLY: + result = specSize; + break; + } + return result; + } + + + @Override + protected void onDraw(Canvas canvas) { + if (null != mIconBitmap) { + canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG)); + canvas.drawBitmap(mIconBitmap, null, mIconRect, null); + + int alpha = (int) Math.ceil(255 * mAlpha); + + // 内存去准备mBitmap , setAlpha , 纯色 ,xfermode , 图标 + setupTargetBitmap(alpha); + // 1、绘制原文本 ; 2、绘制变色的文本 + drawSourceText(canvas, alpha); + drawTargetText(canvas, alpha); + // drawCircleText(canvas, alpha); + + canvas.drawBitmap(mBitmap, 0, 0, null); + } + + } + + /** + * 绘制变色的文本 + * + * @param canvas + * @param alpha + */ + private void drawTargetText(Canvas canvas, int alpha) { + mTextPaint.setColor(mColor); + mTextPaint.setAlpha(alpha); + mTextPaint.setAntiAlias(true); + int x = getMeasuredWidth() / 2 - mTextBound.width() / 2; + int y = mIconRect.bottom + mTextBound.height(); + canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG)); + canvas.drawText(mText, x, y, mTextPaint); + + } + + /** + * 绘制原文本 + * + * @param canvas + * @param alpha + */ + private void drawSourceText(Canvas canvas, int alpha) { + mTextPaint.setColor(0xff636363); + mTextPaint.setAlpha(255 - alpha); + mTextPaint.setAntiAlias(true); + int x = getMeasuredWidth() / 2 - mTextBound.width() / 2; + int y = mIconRect.bottom + mTextBound.height(); + canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG)); + canvas.drawText(mText, x, y, mTextPaint); + + } + + /** + * 在内存中绘制可变色的Icon + */ + private void setupTargetBitmap(int alpha) { + mBitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), Config.ARGB_8888); + mCanvas = new Canvas(mBitmap); + mPaint = new Paint(); + mPaint.setColor(mColor); + mPaint.setAntiAlias(true); + mPaint.setDither(true); + mPaint.setAlpha(alpha); + mCanvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG)); + mCanvas.drawRect(mIconRect, mPaint); + mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); + mPaint.setAlpha(255); + mCanvas.drawBitmap(mIconBitmap, null, mIconRect, mPaint); + } + + private static final String INSTANCE_STATUS = "instance_status"; + private static final String STATUS_ALPHA = "status_alpha"; + + @Override + protected Parcelable onSaveInstanceState() { + Bundle bundle = new Bundle(); + bundle.putParcelable(INSTANCE_STATUS, super.onSaveInstanceState()); + bundle.putFloat(STATUS_ALPHA, mAlpha); + return bundle; + } + + @Override + protected void onRestoreInstanceState(Parcelable state) { + if (state instanceof Bundle) { + Bundle bundle = (Bundle) state; + mAlpha = bundle.getFloat(STATUS_ALPHA); + super.onRestoreInstanceState(bundle.getParcelable(INSTANCE_STATUS)); + return; + } + super.onRestoreInstanceState(state); + } + + public void setIconAlpha(float alpha) { + this.mAlpha = alpha; + invalidateView(); + } + + /** + * 重绘 + */ + private void invalidateView() { + if (Looper.getMainLooper() == Looper.myLooper()) { + invalidate(); + } else { + postInvalidate(); + } + } + +} diff --git a/app/src/main/java/com/chwl/app/common/widget/CircleGradualImageView.java b/app/src/main/java/com/chwl/app/common/widget/CircleGradualImageView.java new file mode 100644 index 0000000..6e96c5d --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/widget/CircleGradualImageView.java @@ -0,0 +1,134 @@ +package com.chwl.app.common.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.RadialGradient; +import android.graphics.Rect; +import android.graphics.Shader; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; + +import com.bumptech.glide.load.DataSource; +import com.bumptech.glide.load.engine.DiskCacheStrategy; +import com.bumptech.glide.load.engine.GlideException; +import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; +import com.bumptech.glide.load.resource.bitmap.CircleCrop; +import com.bumptech.glide.request.RequestListener; +import com.bumptech.glide.request.target.Target; +import com.netease.nim.uikit.support.glide.GlideApp; +import com.chwl.app.R; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; + +/** + * Created by MadisonRong on 23/04/2018. + */ + +public class CircleGradualImageView extends androidx.appcompat.widget.AppCompatImageView { + + private static final String TAG = "CircleGradualImageView"; + + private volatile float centreX; + private volatile float centreY; + private volatile float radius; + private float borderWidth; + private int borderColor; + private Paint bitmapPaint; + private Paint borderPaint; + private Shader shader; + private Rect dst; + private Bitmap bitmap; + + public CircleGradualImageView(Context context) { + this(context, null); + } + + public CircleGradualImageView(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public CircleGradualImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context, attrs, defStyleAttr); + } + + private void init(Context context, AttributeSet attrs, int defStyle) { + TypedArray typedArray = + context.obtainStyledAttributes(attrs, R.styleable.CircleGradualImageView, + defStyle, 0); + borderColor = typedArray.getColor(R.styleable.CircleGradualImageView_cgiv_border_color, + ContextCompat.getColor(context, R.color.appColor)); + borderWidth = typedArray.getDimension(R.styleable.CircleGradualImageView_cgiv_border_width, + UIUtil.dip2px(context, 2)); + typedArray.recycle(); + + bitmapPaint = new Paint(); + bitmapPaint.setAntiAlias(true); + bitmapPaint.setFilterBitmap(true); + + borderPaint = new Paint(); + borderPaint.setAntiAlias(true); + borderPaint.setFilterBitmap(true); + } + + public void setImage(String url) { + GlideApp.with(getContext().getApplicationContext()).load(url) + .override(getWidth() - (int) borderWidth * 2, getHeight() - (int) borderWidth * 2) + .transform(new CircleCrop() { + @Override + protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) { + bitmap = super.transform(pool, toTransform, outWidth, outHeight); + return bitmap; + } + }) + .centerCrop() + .placeholder(R.drawable.default_avatar) + .error(R.drawable.default_cover) + .dontAnimate() + .diskCacheStrategy(DiskCacheStrategy.DATA) + .listener(new RequestListener() { + @Override + public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { + return false; + } + + @Override + public boolean onResourceReady(Drawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { + postInvalidate(); + return true; + } + }) + .into(this); + + } + + @Override + protected void onDraw(Canvas canvas) { + centreX = getMeasuredWidth() / 2; + centreY = getMeasuredHeight() / 2; + radius = centreX > centreY ? centreY : centreX; + radius += borderWidth; + if (shader == null) { + shader = new RadialGradient(centreX, centreY, radius, borderColor, + ContextCompat.getColor(getContext(), R.color.transparent), Shader.TileMode.CLAMP); + } + borderPaint.setShader(shader); + canvas.drawCircle(centreX, centreY, radius, borderPaint); + + if (bitmap != null) { + if (dst == null) { + dst = new Rect((int) borderWidth, (int) borderWidth, + (int) (getWidth() - borderWidth), (int) (getHeight() - borderWidth)); + } + canvas.drawBitmap(bitmap, dst, dst, bitmapPaint); + } + + } + +} diff --git a/app/src/main/java/com/chwl/app/common/widget/CircleImageSpan.java b/app/src/main/java/com/chwl/app/common/widget/CircleImageSpan.java new file mode 100644 index 0000000..cdf28b1 --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/widget/CircleImageSpan.java @@ -0,0 +1,127 @@ +package com.chwl.app.common.widget; + +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.text.TextUtils; +import android.text.style.ImageSpan; + +import androidx.annotation.Nullable; + +import com.bumptech.glide.load.DataSource; +import com.bumptech.glide.load.engine.DiskCacheStrategy; +import com.bumptech.glide.load.engine.GlideException; +import com.bumptech.glide.request.RequestListener; +import com.bumptech.glide.request.target.Target; +import com.netease.nim.uikit.support.glide.GlideApp; +import com.chwl.library.common.util.Utils; +import com.chwl.app.ui.gift.widget.GlideCircleTransform; +import com.chwl.library.utils.config.BasicConfig; + +public class CircleImageSpan extends ImageSpan { + + private String url; + private boolean loading; + private int width; + private int height; + private Drawable drawable; + + + public CircleImageSpan(Drawable defaultDrawable , String url, int width, int height) { + super(defaultDrawable); + this.url = url; + this.width = width; + this.height = height; + this.drawable = defaultDrawable; + getDrawable().setBounds(0, 0, width, height); + loadPicAsync(); + } + + private void loadPicAsync() { + if (!loading && !TextUtils.isEmpty(url)) { + loading = true; + GlideApp.with(BasicConfig.INSTANCE.getAppContext()) + .asDrawable() + .diskCacheStrategy(DiskCacheStrategy.RESOURCE) + .dontAnimate() + .transform(new GlideCircleTransform()) + .override(width, height) + .load(url) + .listener(new RequestListener() { + @Override + public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { + loading = false; + return false; + } + + @Override + public boolean onResourceReady(Drawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { + loading = false; + CircleImageSpan.this.drawable = resource; + CircleImageSpan.this.drawable.setBounds(0, 0, width, height); + return true; + } + }) + .submit(); + } + } + + @Override + public Drawable getDrawable() { + return drawable; + } + + @Override + public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, + Paint paint) { + // Drawable drawable = getDrawable(); + if (getDrawable() == null) return; + canvas.save(); + + //获取画笔的文字绘制时的具体测量数据 + Paint.FontMetricsInt fm = paint.getFontMetricsInt(); + + //系统原有方法,默认是Bottom模式) + int transY = bottom - getDrawable().getBounds().bottom; + if (mVerticalAlignment == ALIGN_BASELINE) { + transY -= fm.descent; + } else if (mVerticalAlignment == ALIGN_BOTTOM) { + // 此处加入判断, 如果是自定义的居中对齐 + // 与文字的中间线对齐(这种方式不论是否设置行间距都能保障文字的中间线和图片的中间线是对齐的) + // y+ascent得到文字内容的顶部坐标,y+descent得到文字的底部坐标,(顶部坐标+底部坐标)/2=文字内容中间线坐标 + transY = ((y + fm.descent) + (y + fm.ascent)) / 2 - getDrawable().getBounds().bottom / 2; + } + + canvas.translate(x, transY); + getDrawable().draw(canvas); + canvas.restore(); + } + + /** + * 重写getSize方法,只有重写该方法后,才能保证不论是图片大于文字还是文字大于图片,都能实现中间对齐 + */ + @Override + public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) { + // Drawable drawable = getDrawable(); + if (getDrawable() != null) { + Rect rect = getDrawable().getBounds(); + if (fm != null) { + Paint.FontMetricsInt fmPaint = paint.getFontMetricsInt(); + int fontHeight = fmPaint.bottom - fmPaint.top; + int drHeight = rect.bottom - rect.top; + + int top = drHeight / 2 - fontHeight / 4; + int bottom = drHeight / 2 + fontHeight / 4; + + fm.ascent = -bottom; + fm.top = -bottom; + fm.bottom = top; + fm.descent = top; + } + return rect.right + Utils.dip2px(BasicConfig.INSTANCE.getAppContext(), 3); + } + return 0; + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/common/widget/CircleImageView.java b/app/src/main/java/com/chwl/app/common/widget/CircleImageView.java new file mode 100644 index 0000000..d985297 --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/widget/CircleImageView.java @@ -0,0 +1,260 @@ +package com.chwl.app.common.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.RectF; +import android.graphics.Shader; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.util.AttributeSet; + +import androidx.appcompat.widget.AppCompatImageView; + +import com.chwl.app.R; + + +public class CircleImageView extends AppCompatImageView { + + private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP; + + private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888; + private static final int COLORDRAWABLE_DIMENSION = 2; + + private static final int DEFAULT_BORDER_WIDTH = 0; + private static final int DEFAULT_BORDER_COLOR = Color.BLACK; + + private final RectF mDrawableRect = new RectF(); + private final RectF mBorderRect = new RectF(); + + private final Matrix mShaderMatrix = new Matrix(); + private final Paint mBitmapPaint = new Paint(); + private final Paint mBorderPaint = new Paint(); + + private int mBorderColor = DEFAULT_BORDER_COLOR; + private int mBorderWidth = DEFAULT_BORDER_WIDTH; + + private Bitmap mBitmap; + private BitmapShader mBitmapShader; + private int mBitmapWidth; + private int mBitmapHeight; + + private float mDrawableRadius; + private float mBorderRadius; + + private boolean mReady; + private boolean mSetupPending; + + public CircleImageView(Context context) { + this(context, null); + } + + public CircleImageView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public CircleImageView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0); + + mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_cborder_width, DEFAULT_BORDER_WIDTH); + mBorderColor = a.getColor(R.styleable.CircleImageView_cborder_color, DEFAULT_BORDER_COLOR); + + a.recycle(); + + init(); + } + + private void init() { + super.setScaleType(SCALE_TYPE); + mReady = true; + + if (mSetupPending) { + setup(); + mSetupPending = false; + } + } + + @Override + public ScaleType getScaleType() { + return SCALE_TYPE; + } + + @Override + public void setScaleType(ScaleType scaleType) { + if (scaleType != SCALE_TYPE) { + throw new IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType)); + } + } + + @Override + public void setAdjustViewBounds(boolean adjustViewBounds) { + if (adjustViewBounds) { + throw new IllegalArgumentException("adjustViewBounds not supported."); + } + } + + @Override + protected void onDraw(Canvas canvas) { + if (getDrawable() == null) { + return; + } + + canvas.drawCircle(getWidth() / 2, getHeight() / 2, mDrawableRadius, mBitmapPaint); + if (mBorderWidth != 0) { + canvas.drawCircle(getWidth() / 2, getHeight() / 2, mBorderRadius, mBorderPaint); + } + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + setup(); + } + + public int getBorderColor() { + return mBorderColor; + } + + public void setBorderColor(int borderColor) { + if (borderColor == mBorderColor) { + return; + } + + mBorderColor = borderColor; + mBorderPaint.setColor(mBorderColor); + invalidate(); + } + + public int getBorderWidth() { + return mBorderWidth; + } + + public void setBorderWidth(int borderWidth) { + if (borderWidth == mBorderWidth) { + return; + } + + mBorderWidth = borderWidth; + setup(); + } + + @Override + public void setImageBitmap(Bitmap bm) { + super.setImageBitmap(bm); + mBitmap = bm; + setup(); + } + + @Override + public void setImageDrawable(Drawable drawable) { + super.setImageDrawable(drawable); + mBitmap = getBitmapFromDrawable(drawable); + setup(); + } + + @Override + public void setImageResource(int resId) { + super.setImageResource(resId); + mBitmap = getBitmapFromDrawable(getDrawable()); + setup(); + } + + @Override + public void setImageURI(Uri uri) { + super.setImageURI(uri); + mBitmap = getBitmapFromDrawable(getDrawable()); + setup(); + } + + private Bitmap getBitmapFromDrawable(Drawable drawable) { + if (drawable == null) { + return null; + } + + if (drawable instanceof BitmapDrawable) { + return ((BitmapDrawable) drawable).getBitmap(); + } + + try { + Bitmap bitmap; + + if (drawable instanceof ColorDrawable) { + bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG); + } else { + bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), BITMAP_CONFIG); + } + + Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); + drawable.draw(canvas); + return bitmap; + } catch (OutOfMemoryError e) { + return null; + } + } + + private void setup() { + if (!mReady) { + mSetupPending = true; + return; + } + + if (mBitmap == null) { + return; + } + + mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + + mBitmapPaint.setAntiAlias(true); + mBitmapPaint.setShader(mBitmapShader); + + mBorderPaint.setStyle(Paint.Style.STROKE); + mBorderPaint.setAntiAlias(true); + mBorderPaint.setColor(mBorderColor); + mBorderPaint.setStrokeWidth(mBorderWidth); + + mBitmapHeight = mBitmap.getHeight(); + mBitmapWidth = mBitmap.getWidth(); + + mBorderRect.set(0, 0, getWidth(), getHeight()); + mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2, (mBorderRect.width() - mBorderWidth) / 2); + + mDrawableRect.set(mBorderWidth, mBorderWidth, mBorderRect.width() - mBorderWidth, mBorderRect.height() - mBorderWidth); + mDrawableRadius = Math.min(mDrawableRect.height() / 2, mDrawableRect.width() / 2); + + updateShaderMatrix(); + invalidate(); +// mBitmap = null; + } + + private void updateShaderMatrix() { + float scale; + float dx = 0; + float dy = 0; + + mShaderMatrix.set(null); + + if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) { + scale = mDrawableRect.height() / (float) mBitmapHeight; + dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f; + } else { + scale = mDrawableRect.width() / (float) mBitmapWidth; + dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f; + } + + mShaderMatrix.setScale(scale, scale); + mShaderMatrix.postTranslate((int) (dx + 0.5f) + mBorderWidth, (int) (dy + 0.5f) + mBorderWidth); + + mBitmapShader.setLocalMatrix(mShaderMatrix); + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/common/widget/CustomAutoWidthImageSpan.java b/app/src/main/java/com/chwl/app/common/widget/CustomAutoWidthImageSpan.java new file mode 100644 index 0000000..b796d65 --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/widget/CustomAutoWidthImageSpan.java @@ -0,0 +1,144 @@ +package com.chwl.app.common.widget; + +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.os.Looper; +import android.text.TextUtils; +import android.text.style.ImageSpan; +import android.widget.TextView; + +import androidx.annotation.Nullable; + +import com.bumptech.glide.load.DataSource; +import com.bumptech.glide.load.engine.DiskCacheStrategy; +import com.bumptech.glide.load.engine.GlideException; +import com.bumptech.glide.request.RequestListener; +import com.bumptech.glide.request.target.Target; +import com.netease.nim.uikit.support.glide.GlideApp; +import com.chwl.library.common.util.Utils; +import com.chwl.library.utils.config.BasicConfig; + +import java.lang.ref.WeakReference; + +public class CustomAutoWidthImageSpan extends ImageSpan { + + private String url; + private WeakReference reference; + private boolean loading; + private int width; + private int height; + private Drawable drawable; + + + public CustomAutoWidthImageSpan(Drawable defaultDrawable, TextView textView, String url, int height) { + super(defaultDrawable); + this.url = url; + this.reference = new WeakReference<>(textView); + this.height = height; + this.drawable = defaultDrawable; + loadPicAsync(); + } + + private void loadPicAsync() { + if (!loading && !TextUtils.isEmpty(url) && reference.get() != null) { + loading = true; + GlideApp.with(reference.get()) + .asDrawable() + .diskCacheStrategy(DiskCacheStrategy.RESOURCE) + .dontAnimate() + .dontTransform() + .load(url) + .listener(new RequestListener() { + @Override + public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { + loading = false; + return false; + } + + @Override + public boolean onResourceReady(Drawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { + loading = false; + if (resource == null) return true; + float ratio = (resource.getIntrinsicHeight() + 0.F) / resource.getIntrinsicWidth(); + width = Math.round(height / ratio); + TextView textView = reference.get(); + if (textView == null) return true; + CustomAutoWidthImageSpan.this.drawable = resource; + CustomAutoWidthImageSpan.this.drawable.setBounds(0, 0, width, height); + if (Looper.myLooper() != Looper.getMainLooper()) { + textView.post(new Runnable() { + @Override + public void run() { + textView.setText(textView.getText()); + } + }); + } else { + textView.setText(textView.getText()); + } + return true; + } + }) + .submit(); + } + } + + @Override + public Drawable getDrawable() { + return drawable; + } + + @Override + public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, + Paint paint) { + // Drawable drawable = getDrawable(); + if (getDrawable() == null) return; + canvas.save(); + + //获取画笔的文字绘制时的具体测量数据 + Paint.FontMetricsInt fm = paint.getFontMetricsInt(); + + //系统原有方法,默认是Bottom模式) + int transY = bottom - getDrawable().getBounds().bottom; + if (mVerticalAlignment == ALIGN_BASELINE) { + transY -= fm.descent; + } else if (mVerticalAlignment == ALIGN_BOTTOM) { + // 此处加入判断, 如果是自定义的居中对齐 + // 与文字的中间线对齐(这种方式不论是否设置行间距都能保障文字的中间线和图片的中间线是对齐的) + // y+ascent得到文字内容的顶部坐标,y+descent得到文字的底部坐标,(顶部坐标+底部坐标)/2=文字内容中间线坐标 + transY = ((y + fm.descent) + (y + fm.ascent)) / 2 - getDrawable().getBounds().bottom / 2; + } + + canvas.translate(x, transY); + getDrawable().draw(canvas); + canvas.restore(); + } + + /** + * 重写getSize方法,只有重写该方法后,才能保证不论是图片大于文字还是文字大于图片,都能实现中间对齐 + */ + @Override + public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) { + // Drawable drawable = getDrawable(); + if (getDrawable() != null) { + Rect rect = getDrawable().getBounds(); + if (fm != null) { + Paint.FontMetricsInt fmPaint = paint.getFontMetricsInt(); + int fontHeight = fmPaint.bottom - fmPaint.top; + int drHeight = rect.bottom - rect.top; + + int top = drHeight / 2 - fontHeight / 4; + int bottom = drHeight / 2 + fontHeight / 4; + + fm.ascent = -bottom; + fm.top = -bottom; + fm.bottom = top; + fm.descent = top; + } + return rect.right + Utils.dip2px(BasicConfig.INSTANCE.getAppContext(), 3); + } + return 0; + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/common/widget/CustomImageSpan.java b/app/src/main/java/com/chwl/app/common/widget/CustomImageSpan.java new file mode 100644 index 0000000..0d12b0d --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/widget/CustomImageSpan.java @@ -0,0 +1,355 @@ +package com.chwl.app.common.widget; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.LayerDrawable; +import android.text.TextUtils; +import android.text.style.ImageSpan; +import android.widget.TextView; + +import androidx.annotation.Nullable; + +import com.bumptech.glide.load.DataSource; +import com.bumptech.glide.load.engine.DiskCacheStrategy; +import com.bumptech.glide.load.engine.GlideException; +import com.bumptech.glide.request.RequestListener; +import com.bumptech.glide.request.target.Target; +import com.netease.nim.uikit.support.glide.GlideApp; +import com.chwl.library.common.util.Utils; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.library.utils.SizeUtils; +import com.chwl.library.utils.config.BasicConfig; + +import java.lang.ref.WeakReference; + +public class CustomImageSpan extends ImageSpan { + + private String url; + private WeakReference reference; + private boolean loading; + private int width; + private int height; + private Drawable drawable; + + private String content; + + public CustomImageSpan(Drawable drawable) { + super(drawable); + this.drawable = drawable; + } + + public CustomImageSpan(Drawable defaultDrawable, TextView textView, String url) { + super(defaultDrawable); + this.url = url; + this.reference = new WeakReference<>(textView); + this.drawable = defaultDrawable; + getDrawable().setBounds(0, 0, UIUtil.dip2px(textView.getContext(), 55), height); + loadPicAsyncNoWidthHeight(); + } + + public CustomImageSpan(Drawable defaultDrawable, TextView textView, String url, int width, int height) { + super(defaultDrawable); + this.url = url; + this.reference = new WeakReference<>(textView); + this.width = width; + this.height = height; + this.drawable = defaultDrawable; + getDrawable().setBounds(0, 0, width, height); + loadPicAsync(); + } + + /** + * 自定义背景 + 文字铭牌 + * @param defaultDrawable + * @param textView + * @param url + * @param content + */ + public CustomImageSpan(Drawable defaultDrawable, TextView textView, String url, String content) { + super(defaultDrawable); + this.content = content; + + this.url = url; + this.reference = new WeakReference<>(textView); + this.height = SizeUtils.dp2px(textView.getContext(), 20); + + // width 不初始化会导致后面布局被截断 + // 暂时先初始化为设计稿宽度 + // 不是一个很好的处理办法,可以优化 + final float ORI_HEIGHT = 40; // 原设计稿高度40px + float ratio = height / ORI_HEIGHT; + Paint paint = new Paint(); + paint.setTextSize(ratio * 22); + float textWidth = paint.measureText(content); + this.width = (int) (textWidth + (50 + 4) * ratio + 16 * ratio +10); + + this.drawable = defaultDrawable; + getDrawable().setBounds(0, 0, width, height); + loadPicAsyncWithHeight(); + } + + /** + * 官方主播铭牌类似情况:背景图和文本组合展示 + * @param url + * 图标链接 + * @param content + * 文本 + */ + public CustomImageSpan(Drawable defaultDrawable, TextView textView, String url, String content, int width, int height) { + super(defaultDrawable); + this.content = content; + + this.url = url; + this.reference = new WeakReference<>(textView); + this.width = width; + this.height = height; + this.drawable = defaultDrawable; + getDrawable().setBounds(0, 0, width, height); + loadPicAsync(); + } + + private void loadPicAsyncNoWidthHeight() { + if (!loading && !TextUtils.isEmpty(url) && reference.get() != null) { + if (isDestroyedActivity(reference.get().getContext())) { + return; + } + try { + loading = true; + GlideApp.with(reference.get()) + .asDrawable() + .diskCacheStrategy(DiskCacheStrategy.RESOURCE) + .dontAnimate() + .dontTransform() + .load(url) + .listener(new RequestListener() { + @Override + public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { + loading = false; + return false; + } + + @Override + public boolean onResourceReady(Drawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { + loading = false; + TextView textView = reference.get(); + if (textView == null || resource == null) return true; + resource = getNewDrawable(textView, resource); + + CustomImageSpan.this.drawable = resource; + int i = resource.getMinimumHeight() / 15; + CustomImageSpan.this.drawable.setBounds(0, 0, + UIUtil.dip2px(textView.getContext(), resource.getIntrinsicWidth() / i), + UIUtil.dip2px(textView.getContext(), resource.getMinimumHeight() % 15 == 0 ? 15 : 17)); + textView.postInvalidate(); + return true; + } + }) + .submit(); + } catch (Exception e) { + loading = false; + e.printStackTrace(); + } + } + } + + private void loadPicAsyncWithHeight() { + if (!loading && !TextUtils.isEmpty(url) && reference.get() != null) { + if (isDestroyedActivity(reference.get().getContext())) { + return; + } + try { + loading = true; + GlideApp.with(reference.get()) + .asDrawable() + .diskCacheStrategy(DiskCacheStrategy.RESOURCE) + .dontAnimate() + .dontTransform() + .load(url) + .listener(new RequestListener() { + @Override + public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { + loading = false; + return false; + } + + @Override + public boolean onResourceReady(Drawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { + loading = false; + TextView textView = reference.get(); + if (textView == null || resource == null) return true; + + float oriWidth = resource.getIntrinsicWidth(); + float oriHeight = resource.getIntrinsicHeight(); + width = (int) (oriWidth / oriHeight * height); + + resource = getTextDrawable(textView, resource); + + CustomImageSpan.this.drawable = resource; + CustomImageSpan.this.drawable.setBounds(0, 0, width, height); + textView.postInvalidate(); + return true; + } + }) + .submit(); + } catch (Exception e) { + loading = false; + e.printStackTrace(); + } + } + } + + private boolean isDestroyedActivity(Context context) { + return context instanceof Activity && ((Activity) context).isDestroyed(); + } + + private void loadPicAsync() { + if (!loading && !TextUtils.isEmpty(url) && reference.get() != null) { + if (isDestroyedActivity(reference.get().getContext())) { + return; + } + try { + loading = true; + GlideApp.with(reference.get()) + .asDrawable() + .diskCacheStrategy(DiskCacheStrategy.RESOURCE) + .dontAnimate() + .dontTransform() + .override(width, height) + .load(url) + .listener(new RequestListener() { + @Override + public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { + loading = false; + return false; + } + + @Override + public boolean onResourceReady(Drawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { + loading = false; + TextView textView = reference.get(); + if (textView == null || resource == null) return true; + resource = getNewDrawable(textView, resource); + + CustomImageSpan.this.drawable = resource; + CustomImageSpan.this.drawable.setBounds(0, 0, width, height); + textView.postInvalidate(); + return true; + } + }) + .submit(); + } catch (Exception e) { + loading = false; + e.printStackTrace(); + } + } + } + + private Drawable getNewDrawable(TextView textView, Drawable resource) { + if (!TextUtils.isEmpty(content)) { + float extraXOffset = SizeUtils.dp2px(textView.getContext(), 1); + + int width = resource.getIntrinsicWidth(); + float xLOffset = SizeUtils.dp2px(textView.getContext(), 15); + float xROffset = SizeUtils.dp2px(textView.getContext(), 6); + float tempWidth = width - xLOffset - xROffset; + float x = tempWidth / 2 + xLOffset + extraXOffset; + int size = SizeUtils.dp2px(textView.getContext(), 10); + + TextDrawable textDrawable = new TextDrawable(content, x, resource.getIntrinsicHeight(), size); + Drawable[] array = new Drawable[] {resource, textDrawable}; + LayerDrawable id = new LayerDrawable(array); + resource = id; + } + + return resource; + } + + /** + * 自定义背景 + 文字铭牌 + * @param textView + * @param resource + * @return + */ + private Drawable getTextDrawable(TextView textView, Drawable resource) { + final float ORI_HEIGHT = 40; // 原设计稿高度40px + float ratio = height / ORI_HEIGHT; + if (!TextUtils.isEmpty(content)) { + float extraXOffset = 4 * ratio; + + float xLOffset = 50 * ratio; + float xROffset = 16 * ratio; + float tempWidth = width - xLOffset - xROffset - extraXOffset; + float x = tempWidth / 2 + xLOffset + extraXOffset; + int size = (int) (22 * ratio); + + TextDrawable textDrawable = new TextDrawable(content, x, height, size); + Drawable[] array = new Drawable[] {resource, textDrawable}; + LayerDrawable id = new LayerDrawable(array); + resource = id; + } + + return resource; + } + + @Override + public Drawable getDrawable() { + return drawable; + } + + @Override + public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, + Paint paint) { + Drawable drawable = getDrawable(); + if (drawable == null) return; + canvas.save(); + + //获取画笔的文字绘制时的具体测量数据 + Paint.FontMetricsInt fm = paint.getFontMetricsInt(); + + //系统原有方法,默认是Bottom模式) + int transY = bottom - drawable.getBounds().bottom; + if (mVerticalAlignment == ALIGN_BASELINE) { + transY -= fm.descent; + } else if (mVerticalAlignment == ALIGN_BOTTOM) { + // 此处加入判断, 如果是自定义的居中对齐 + // 与文字的中间线对齐(这种方式不论是否设置行间距都能保障文字的中间线和图片的中间线是对齐的) + // y+ascent得到文字内容的顶部坐标,y+descent得到文字的底部坐标,(顶部坐标+底部坐标)/2=文字内容中间线坐标 + transY = ((y + fm.descent) + (y + fm.ascent)) / 2 - drawable.getBounds().bottom / 2; + } + + canvas.translate(x, transY); + drawable.draw(canvas); + canvas.restore(); + } + + /** + * 重写getSize方法,只有重写该方法后,才能保证不论是图片大于文字还是文字大于图片,都能实现中间对齐 + */ + @Override + public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) { + Drawable drawable = getDrawable(); + if (drawable != null) { + Rect rect = drawable.getBounds(); + if (fm != null) { + Paint.FontMetricsInt fmPaint = paint.getFontMetricsInt(); + int fontHeight = fmPaint.bottom - fmPaint.top; + int drHeight = rect.bottom - rect.top; + + int top = drHeight / 2 - fontHeight / 4; + int bottom = drHeight / 2 + fontHeight / 4; + + fm.ascent = -bottom; + fm.top = -bottom; + fm.bottom = top; + fm.descent = top; + } + return rect.right + Utils.dip2px(BasicConfig.INSTANCE.getAppContext(), 3); + } + return 0; + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/common/widget/DragLayout.java b/app/src/main/java/com/chwl/app/common/widget/DragLayout.java new file mode 100644 index 0000000..f8d1edb --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/widget/DragLayout.java @@ -0,0 +1,195 @@ +package com.chwl.app.common.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.RelativeLayout; + + +/** + * Created by huangmeng1 on 2018/3/7. + * Updated by MadisonRong on 2018/4/23. + */ + +public class DragLayout extends RelativeLayout { + + private static final String TAG = "DragLayout"; + + private int lastMoveX; + private int lastMoveY; + private int lastX; + private int lastY; + private volatile int dx; + private volatile int dy; + private volatile int left; + private volatile int top; + private volatile int right; + private volatile int bottom; + private int parentWidth; + private int parentHeight; + + public DragLayout(Context context) { + this(context, null); + } + + public DragLayout(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public DragLayout(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent event) { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + lastX = (int) event.getRawX(); + lastY = (int) event.getRawY(); + lastMoveX = lastX; + lastMoveY = lastY; + break; + case MotionEvent.ACTION_MOVE: + getParent().requestDisallowInterceptTouchEvent(true); + dx = (int) event.getRawX() - lastX; + dy = (int) event.getRawY() - lastY; + + left = getLeft() + dx; + top = getTop() + dy; + right = getRight() + dx; + bottom = getBottom() + dy; + + ViewGroup parent = (ViewGroup) getParent(); + if (parent != null) { + parentWidth = parent.getWidth(); + parentHeight = parent.getHeight(); + } + + if (left < 0) { + left = 0; + right = left + getWidth(); + } + if (right > parentWidth) { + right = parentWidth; + left = right - getWidth(); + } + if (top < 0) { + top = 0; + bottom = top + getHeight(); + } + + if (bottom > parentHeight) { + + bottom = parentHeight; + top = bottom - getHeight(); + } + + reSetLayoutParams(); + + lastX = (int) event.getRawX(); + lastY = (int) event.getRawY(); + break; + case MotionEvent.ACTION_UP: + if ((int) (Math.abs(event.getRawX() - lastMoveX)) >= 10 || + (int) (Math.abs(event.getRawY() - lastMoveY)) >= 10) { + return true; + } else { + return performClick(); + } + default: + break; + } + return super.onInterceptTouchEvent(event); + } + + private void reSetLayoutParams() { + ViewGroup.MarginLayoutParams layoutParams = null; + if (getLayoutParams() instanceof RelativeLayout.LayoutParams) { + layoutParams = new RelativeLayout.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT + ); + } else if (getLayoutParams() instanceof FrameLayout.LayoutParams) { + layoutParams = new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT + ); + } + + if (layoutParams != null) { + layoutParams.leftMargin = left; + layoutParams.topMargin = top; + layoutParams.width = getWidth(); + layoutParams.height = getHeight(); + setLayoutParams(layoutParams); + } + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + lastX = (int) event.getRawX(); + lastY = (int) event.getRawY(); + lastMoveX = lastX; + lastMoveY = lastY; + break; + case MotionEvent.ACTION_MOVE: + getParent().requestDisallowInterceptTouchEvent(true); + dx = (int) event.getRawX() - lastX; + dy = (int) event.getRawY() - lastY; + + left = getLeft() + dx; + top = getTop() + dy; + right = getRight() + dx; + bottom = getBottom() + dy; + + ViewGroup parent = (ViewGroup) getParent(); + if (parent != null) { + parentWidth = parent.getWidth(); + parentHeight = parent.getHeight(); + } + + if (left < 0) { + left = 0; + right = left + getWidth(); + } + if (right > parentWidth) { + right = parentWidth; + left = right - getWidth(); + } + if (top < 0) { + top = 0; + bottom = top + getHeight(); + } + + if (bottom > parentHeight) { + + bottom = parentHeight; + top = bottom - getHeight(); + } + + reSetLayoutParams(); + + lastX = (int) event.getRawX(); + lastY = (int) event.getRawY(); + break; + case MotionEvent.ACTION_UP: + if ((int) (Math.abs(event.getRawX() - lastMoveX)) >= 10 || + (int) (Math.abs(event.getRawY() - lastMoveY)) >= 10) { + return true; + } else { + return performClick(); + } + default: + break; + } + return true; + } + + @Override + public boolean performClick() { + return super.performClick(); + } + +} diff --git a/app/src/main/java/com/chwl/app/common/widget/FloatingLiveMiniView.java b/app/src/main/java/com/chwl/app/common/widget/FloatingLiveMiniView.java new file mode 100644 index 0000000..104f8f1 --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/widget/FloatingLiveMiniView.java @@ -0,0 +1,99 @@ +package com.chwl.app.common.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.widget.RelativeLayout; + +import androidx.annotation.Nullable; + +import com.chwl.app.R; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; + +/** + * 全局悬浮的最小化控件 + * Created by MadisonRong on 20/04/2018. + */ + +public class FloatingLiveMiniView extends RelativeLayout { + + private int movex; + private int movey; + private int dx; + private int dy; + private int left ; + private int top ; + private int right ; + private int bottom ; + private int screenHeight; + private int lastX; + private int lastY; + + public FloatingLiveMiniView(Context context) { + this(context, null); + } + + public FloatingLiveMiniView(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public FloatingLiveMiniView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context); + } + + private void init(Context context) { + inflate(context, R.layout.floating_live_mini_view, this); + screenHeight = getContext().getResources().getDisplayMetrics().heightPixels; + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + lastX = (int) event.getRawX(); + lastY = (int) event.getRawY(); + movex = lastX; + movey = lastY; + break; + case MotionEvent.ACTION_MOVE: + dx = (int) event.getRawX() - lastX; + dy = (int) event.getRawY() - lastY; + + left = getLeft() + dx; + top = getTop() + dy; + right = getRight() + dx; + bottom = getBottom() + dy; + if (left < 0) { + left = 0; + right = left + getWidth(); + } + if (right > UIUtil.getScreenWidth(getContext())) { + right = UIUtil.getScreenWidth(getContext()); + left = right - getWidth(); + } + if (top < 0) { + top = 0; + bottom = top + getHeight(); + } + + if (bottom > screenHeight) { + + bottom = screenHeight; + top = bottom - getHeight(); + } + layout(left, top, right, bottom); + lastX = (int) event.getRawX(); + lastY = (int) event.getRawY(); + break; + case MotionEvent.ACTION_UP: + if ((int) (event.getRawX() - movex) != 0 || (int) (event.getRawY() - movey) != 0) { + return true; + } + break; + default: + break; + } + return super.onTouchEvent(event); + } +} diff --git a/app/src/main/java/com/chwl/app/common/widget/LimitEditText.java b/app/src/main/java/com/chwl/app/common/widget/LimitEditText.java new file mode 100644 index 0000000..a37d6ae --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/widget/LimitEditText.java @@ -0,0 +1,94 @@ +package com.chwl.app.common.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.text.InputFilter; +import android.util.AttributeSet; +import android.widget.TextView; + +import androidx.appcompat.widget.AppCompatEditText; + +import com.chwl.app.R; +import com.chwl.app.utils.LimitInputFliter; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; + +/** + * App内定制的编辑框 + * Created by lvzebiao on 2019/1/28. + */ + +public class LimitEditText extends AppCompatEditText { + /**是否限制空格和换行*/ + private boolean banBlank; + /**限制最长输入*/ + private int length; + + public LimitEditText(Context context, AttributeSet attrs) { + this(context, attrs, R.attr.editTextStyle); + } + + public LimitEditText(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context, attrs); + } + + private void init(Context context, AttributeSet attrs) { + TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.LimitEditText); + //光标设置为APP主题色,默认ture + boolean cursor = array.getBoolean(R.styleable.LimitEditText_let_app_cursor, true); + if (cursor) { + //没有办法java直接改,采用反射 + try { + Field f = TextView.class.getDeclaredField("mCursorDrawableRes"); + f.setAccessible(true); + f.set(this, R.drawable.shape_edit_cursor); + } catch (Exception e) { + e.printStackTrace(); + } + } + //限制空格和换行输入,默认ture + banBlank = array.getBoolean(R.styleable.LimitEditText_let_ban_blank, false); + length = array.getInteger(R.styleable.LimitEditText_let_length, -1); + updateFilters(); + array.recycle(); + } + + /** + * 动态设置是否禁止空白 + */ + public void setBanBlank(boolean isBan) { + this.banBlank = isBan; + updateFilters(); + } + + public void setMaxLength(int length) { + this.length = length; + updateFilters(); + } + + private void updateFilters() { + List list = new ArrayList<>(); + if (banBlank) { + list.add(new LimitInputFliter()); + } + //限制最长输入 + if (length > 0) { + list.add(new InputFilter.LengthFilter(length)); + } + if (list.size() > 0) { + setFilters(list.toArray(new InputFilter[list.size()])); + } + } + + /** + * 设置文本,并且自动移动光标至尾部 + */ + public void setTextAutoCursor(CharSequence text) { + setText(text); + setSelection(getText().toString().length()); + } + +} diff --git a/app/src/main/java/com/chwl/app/common/widget/LoadingImageView.java b/app/src/main/java/com/chwl/app/common/widget/LoadingImageView.java new file mode 100644 index 0000000..0c3f0f4 --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/widget/LoadingImageView.java @@ -0,0 +1,59 @@ + +package com.chwl.app.common.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; +import android.widget.ImageView; + +import com.chwl.app.R; + + +/** + * 描述:Loading加载控件 + * + * @author zhengsun + * @since 2014年8月28日 下午4:13:37 + */ +public class LoadingImageView extends ImageView { + + public LoadingImageView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public LoadingImageView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + public LoadingImageView(Context context) { + super(context); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + Animation hyperspaceJumpAnimation = AnimationUtils.loadAnimation(getContext(), + R.anim.comm_loading); + startAnimation(hyperspaceJumpAnimation); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + clearAnimation(); + } + + @Override + protected void onVisibilityChanged(View changedView, int visibility) { + super.onVisibilityChanged(changedView, visibility); + if (visibility == View.INVISIBLE || visibility == View.GONE) { + clearAnimation(); + return; + } + Animation hyperspaceJumpAnimation = AnimationUtils.loadAnimation(getContext(), + R.anim.comm_loading); + startAnimation(hyperspaceJumpAnimation); + } +} diff --git a/app/src/main/java/com/chwl/app/common/widget/MaskImageView.java b/app/src/main/java/com/chwl/app/common/widget/MaskImageView.java new file mode 100644 index 0000000..65f1008 --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/widget/MaskImageView.java @@ -0,0 +1,208 @@ +package com.chwl.app.common.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.ColorMatrix; +import android.graphics.ColorMatrixColorFilter; +import android.util.AttributeSet; +import android.widget.ImageView; + +import com.chwl.app.R; + + +/** + * 可在背景图和前景图显示遮罩效果的ImageView (前提设置了setClickable(true)) + * + * @author huangziwei + * @date 2015.12.29 + */ +public class MaskImageView extends ImageView { + + // 遮罩的范围 + public static final int MASK_LEVEL_BACKGROUND = 1; // 背景图显示遮罩 + public static final int MASK_LEVEL_FOREGROUND = 2; // 前景图显示遮罩 + private boolean mIsIgnoreAlpha = true; // 是否忽略图片的透明度,默认为true,透明部分不显示遮罩 + + private boolean mIsShowMaskOnClick = true; // 点击时是否显示遮罩,默认开启 + private int mShadeColor = 0x00ffffff; // 遮罩颜色(argb,需要设置透明度) + + private int mMaskLevel = MASK_LEVEL_FOREGROUND; // 默认为前景图显示遮罩 + + ColorMatrix mColorMatrix = new ColorMatrix(); // 颜色矩阵 + ColorFilter mColorFilter; + + + public MaskImageView(Context context) { + this(context, null); + } + + public MaskImageView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public MaskImageView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(attrs); + } + + private void init(AttributeSet attrs) { + + TypedArray a = getContext().obtainStyledAttributes(attrs, + R.styleable.MaskImageView); + + + mIsIgnoreAlpha = a.getBoolean(R.styleable.MaskImageView_miv_is_ignore_alpha, mIsIgnoreAlpha); + mIsShowMaskOnClick = a.getBoolean(R.styleable.MaskImageView_miv_is_show_mask_on_click, mIsShowMaskOnClick); + mShadeColor = a.getColor(R.styleable.MaskImageView_miv_mask_color, mShadeColor); + mMaskLevel = a.getInt(R.styleable.MaskImageView_miv_mask_level, mMaskLevel); + + // 忽略透明度时的颜色矩阵 + float r = Color.alpha(mShadeColor) / 255f; + r = r - (1 - r) * 0.15f; + float rr = (1 - r) * 1.15f; + setColorMatrix(new float[]{ + rr, 0, 0, 0, Color.red(mShadeColor) * r, + 0, rr, 0, 0, Color.green(mShadeColor) * r, + 0, 0, rr, 0, Color.blue(mShadeColor) * r, + 0, 0, 0, 1, 0, + }); + + a.recycle(); + } + + private void setColorMatrix(float[] matrix) { + mColorMatrix.set(matrix); + mColorFilter = new ColorMatrixColorFilter(mColorMatrix); + } + + // all drawables instances loaded from the same resource share getScreenHeight common state + // 从同一个资源文件获取的drawable对象共享一个状态信息,为了避免修改其中一个drawable导致其他drawable被影响,需要调用mutate() + // 因为背景图在draw()阶段绘制,所以修改了背景图状态后必须调用invalidateSelf()刷新 + private void setDrawableColorFilter(ColorFilter colorFilter) { + if (mMaskLevel == MASK_LEVEL_BACKGROUND) { + if (getBackground() != null) { + getBackground().mutate(); + getBackground().setColorFilter(colorFilter); + getBackground().invalidateSelf(); + } + } else if (mMaskLevel == MASK_LEVEL_FOREGROUND) { + if (getDrawable() != null) { + getDrawable().mutate(); + getDrawable().setColorFilter(colorFilter); + getDrawable().invalidateSelf(); + } + } + } + + + /* 忽略透明度,添加遮罩原理 + + 创建新的滤镜 + ColorMatrix colorMatrix = new ColorMatrix(new float[]{ + getScreenHeight,b,c,d,e, + f,g,h,i,j, + k,l,m,n,o, + p,q,r,s,t}); + + 已知一个颜色值ARGB,则经过下面的矩阵运算可得出新的颜色值 + int red = getScreenHeight*R + b*R + c*R + d*R + e; + int green = f*G + g*G + h*G + i*G + j; + int blue = k*B + l*B + m*B + n*B + o; + int alpha = p*A + q*A + r*A + s*A + t; + + 设置图片滤镜 + getDrawable().setColorFilter(new ColorMatrixColorFilter(colorMatrix)); + + 绘图 + mDrawable.draw(canvas) + + */ + @Override + protected void onDraw(Canvas canvas) { + + if (mIsIgnoreAlpha) { // 忽略透明度 + if (mIsShowMaskOnClick && isPressed()) { + // 绘制遮罩层 + setDrawableColorFilter(mColorFilter); + } else { + setDrawableColorFilter(null); + } + super.onDraw(canvas); + } else { // 不忽略透明度 + setDrawableColorFilter(null); + if (mMaskLevel == MASK_LEVEL_BACKGROUND) { // 背景图 + if (mIsShowMaskOnClick && isPressed()) { + // 绘制遮罩层 + canvas.drawColor(mShadeColor); + } + super.onDraw(canvas); + } else { // 前景图 + super.onDraw(canvas); + if (mIsShowMaskOnClick && isPressed()) { + // 绘制遮罩层 + canvas.drawColor(mShadeColor); + } + } + } + + } + + /** + * view状态改变 + */ + @Override + protected void drawableStateChanged() { + super.drawableStateChanged(); + invalidate(); + } + + public boolean isIsIgnoreAlpha() { + return mIsIgnoreAlpha; + } + + public void setIsIgnoreAlpha(boolean mIsIgnoreAlpha) { + this.mIsIgnoreAlpha = mIsIgnoreAlpha; + invalidate(); + } + + public boolean isIsShowMaskOnClick() { + return mIsShowMaskOnClick; + } + + public void setIsShowMaskOnClick(boolean mIsShowMaskOnClick) { + this.mIsShowMaskOnClick = mIsShowMaskOnClick; + invalidate(); + } + + public int getShadeColor() { + return mShadeColor; + } + + public void setShadeColor(int mShadeColor) { + this.mShadeColor = mShadeColor; + // 忽略透明度时的颜色矩阵 + float r = Color.alpha(mShadeColor) / 255f; + r = r - (1 - r) * 0.15f; + float rr = (1 - r) * 1.15f; + setColorMatrix(new float[]{ + rr, 0, 0, 0, Color.red(mShadeColor) * r, + 0, rr, 0, 0, Color.green(mShadeColor) * r, + 0, 0, rr, 0, Color.blue(mShadeColor) * r, + 0, 0, 0, 1, 0, + }); + invalidate(); + } + + public int getMaskLevel() { + return mMaskLevel; + } + + public void setMaskLevel(int mMaskLevel) { + this.mMaskLevel = mMaskLevel; + invalidate(); + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/common/widget/OriginalDrawStatusClickSpan.java b/app/src/main/java/com/chwl/app/common/widget/OriginalDrawStatusClickSpan.java new file mode 100644 index 0000000..de00ccd --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/widget/OriginalDrawStatusClickSpan.java @@ -0,0 +1,42 @@ +package com.chwl.app.common.widget; + +import android.text.TextPaint; +import android.text.style.ClickableSpan; +import android.view.View; + +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; + +public abstract class OriginalDrawStatusClickSpan extends ClickableSpan{ + + private final Integer mColor; + private final boolean underlineText; + + public OriginalDrawStatusClickSpan() { + this(null); + } + + public OriginalDrawStatusClickSpan(@ColorInt Integer color) { + this.mColor = color; + this.underlineText = true; + } + + public OriginalDrawStatusClickSpan(@ColorInt Integer color, boolean underlineText) { + this.mColor = color; + this.underlineText = underlineText; + } + + @Override + public void onClick(@NonNull View widget) { + + } + + @Override + public void updateDrawState(@NonNull TextPaint ds) { + if (mColor != null) { + ds.setColor(mColor); + ds.setUnderlineText(underlineText); + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/common/widget/OvalImageView.java b/app/src/main/java/com/chwl/app/common/widget/OvalImageView.java new file mode 100644 index 0000000..9892f02 --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/widget/OvalImageView.java @@ -0,0 +1,63 @@ +package com.chwl.app.common.widget; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Path; +import android.graphics.RectF; +import android.util.AttributeSet; + + + +/* + *用来显示不规则图片, + * 上面两个是圆角,下面两个是直角 + * */ +public class OvalImageView extends androidx.appcompat.widget.AppCompatImageView { + /*圆角的半径,依次为左上角xy半径,右上角,右下角,左下角*/ + //此处可根据自己需要修改大小 + private Context mContext; + float[] rids = {dp2px(mContext,12), dp2px(mContext,12), dp2px(mContext,5), dp2px(mContext,12), 0.0f, 0.0f, 0.0f, 0.0f}; + + public OvalImageView(Context context) { + super(context); + mContext = context; + + } + + + public OvalImageView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + + public OvalImageView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int width = MeasureSpec.getSize(widthMeasureSpec); + setMeasuredDimension(width, width); + } + + /** + * 画图 + * + * @param canvas + */ + protected void onDraw(Canvas canvas) { + Path path = new Path(); + int w = this.getWidth(); + int h = this.getHeight(); + /*向路径中添加圆角矩形。radii数组定义圆角矩形的四个圆角的x,y半径。radii长度必须为8*/ + path.addRoundRect(new RectF(0, 0, w, h), rids, Path.Direction.CW); + canvas.clipPath(path); + super.onDraw(canvas); + } + + public int dp2px(Context context,final float dpValue) { + final float scale = context.getResources().getDisplayMetrics().density; + return (int) (dpValue * scale + 0.5f); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/common/widget/PlayerView.java b/app/src/main/java/com/chwl/app/common/widget/PlayerView.java new file mode 100644 index 0000000..f801bc4 --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/widget/PlayerView.java @@ -0,0 +1,54 @@ +package com.chwl.app.common.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import com.chwl.app.R; + +/** + * Created by zhouxiangfeng on 17/2/26. + */ + +public class PlayerView extends View { + + private ImageView playerIv; + private TextView timeTv; + + private static final int MODE_PLAYING = 1 ; + private static final int MODE_NORMAL = 0 ; + + public PlayerView(Context context) { + super(context); + init(); + } + + public PlayerView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public PlayerView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + private void init(){ + View mView = LayoutInflater.from(getContext()).inflate(R.layout.layout_audio_player_view,null); + playerIv = (ImageView)mView.findViewById(R.id.player_iv); + timeTv = (TextView)mView.findViewById(R.id.time_tv); + } + + public void updateView(int mode){ + if(mode == MODE_NORMAL){ + playerIv.setImageResource(R.drawable.btn_play); + + }else{ + playerIv.setImageResource(R.drawable.btn_pause); + } + } + +} diff --git a/app/src/main/java/com/chwl/app/common/widget/RectRoundImageView.java b/app/src/main/java/com/chwl/app/common/widget/RectRoundImageView.java new file mode 100644 index 0000000..029ede5 --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/widget/RectRoundImageView.java @@ -0,0 +1,94 @@ +package com.chwl.app.common.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Outline; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.View; +import android.view.ViewOutlineProvider; + +import com.google.android.material.imageview.ShapeableImageView; +import com.google.android.material.shape.CornerFamily; +import com.google.android.material.shape.ShapeAppearanceModel; +import com.chwl.app.R; + + +/** + * 自定义View,实现圆角,圆形等效果 + * + * @author zhy + */ +public class RectRoundImageView extends ShapeableImageView { + + /** + * TYPE_CIRCLE / TYPE_ROUND + */ + private int type; + public static final int TYPE_CIRCLE = 0; + public static final int TYPE_ROUND = 1; + + /** + * 圆角的大小 + */ + private int mRadius = 8; + + public RectRoundImageView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public RectRoundImageView(Context context) { + this(context, null); + } + + /** + * 初始化一些自定义的参数 + * + * @param context + * @param attrs + * @param defStyle + */ + public RectRoundImageView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + TypedArray a = context.getTheme().obtainStyledAttributes(attrs, + R.styleable.RectRoundImageView, defStyle, 0); + + int n = a.getIndexCount(); + for (int i = 0; i < n; i++) { + int attr = a.getIndex(i); + switch (attr) { + case R.styleable.RectRoundImageView_type: + type = a.getInt(attr, 0);// 默认为Circle + break; + case R.styleable.RectRoundImageView_borderRadius: + mRadius = a.getDimensionPixelSize(attr, (int) TypedValue + .applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10f, + getResources().getDisplayMetrics()));// 默认为10DP + break; + } + } + setScaleType(ScaleType.CENTER_CROP); + a.recycle(); + setup(type, mRadius); + } + + private void setup(int type, int cornerSize) { + if (type == TYPE_CIRCLE) { + setOutlineProvider(new ViewOutlineProvider() { + @Override + public void getOutline(View view, Outline outline) { + int min = Math.min(view.getWidth(), view.getHeight()); + int left = (view.getWidth() - min) / 2; + int top = (view.getHeight() - min) / 2; + outline.setOval(left, top, min, min); + } + }); + setClipToOutline(true); + } else if (type == TYPE_ROUND) { + setShapeAppearanceModel(ShapeAppearanceModel.builder() + .setAllCorners(CornerFamily.ROUNDED, cornerSize) + .build()); + } + } +} diff --git a/app/src/main/java/com/chwl/app/common/widget/SlideListViewPager.java b/app/src/main/java/com/chwl/app/common/widget/SlideListViewPager.java new file mode 100644 index 0000000..da2dde2 --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/widget/SlideListViewPager.java @@ -0,0 +1,58 @@ +package com.chwl.app.common.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.view.Display; +import android.view.WindowManager; + +import androidx.viewpager.widget.ViewPager; + +public class SlideListViewPager extends ViewPager { + + private Context context; + + public SlideListViewPager(Context context) { + super(context); + // TODO Auto-generated constructor stub + this.context = context; + } + + public SlideListViewPager(Context context, AttributeSet attrs) { + super(context, attrs); + // TODO Auto-generated constructor stub + this.context = context; + } + +// @Override +// public boolean onInterceptTouchEvent(MotionEvent event) {//限制出发滑动的范围 +// if(event.getAction() == MotionEvent.ACTION_DOWN){ +// float x = event.getX(); +// if(x < 10 || x > getScreenWidth(context) - 10){ +// return true; +// }else{ +// return false; +// } +// } +// return super.onInterceptTouchEvent(event); +// } + + // 获取屏幕的宽度 + public static int getScreenWidth(Context context) { + WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + Display display = manager.getDefaultDisplay(); + return display.getWidth(); + } + + // 获取屏幕的宽度 + public static int getScreenWidths(Context context) { + DisplayMetrics dm = new DisplayMetrics(); + WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + manager.getDefaultDisplay().getMetrics(dm); + + int screenWidth = dm.widthPixels; + + int screenHeight = dm.heightPixels; + return screenWidth; + } +} diff --git a/app/src/main/java/com/chwl/app/common/widget/StatusLayout.java b/app/src/main/java/com/chwl/app/common/widget/StatusLayout.java new file mode 100644 index 0000000..c09e01c --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/widget/StatusLayout.java @@ -0,0 +1,127 @@ +package com.chwl.app.common.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.os.Handler; +import android.os.Message; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.chwl.app.R; +import com.chwl.library.utils.log.MLog; + + +/** + * 状态布局:无数据,网络错误,加载中 + * Created by xujiexing on 14-7-16. + */ +public class StatusLayout extends RelativeLayout { + + private int paddingBottom; + + public StatusLayout(Context context) { + super(context); + } + + public StatusLayout(Context context, AttributeSet attrs) { + super(context, attrs); + initParams(context, attrs); + } + + public StatusLayout(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + initParams(context, attrs); + } + + private TextView mLoadingMore; + private View mLoadingContainer; + private View mProgress; + + private void initParams(Context context, AttributeSet attrs) { + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.StatusLayout); + paddingBottom = a.getDimensionPixelOffset(R.styleable.StatusLayout_status_bottom, 0); + a.recycle(); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + addLoadingFooter(); + addStatus(); + } + + private void addLoadingFooter() { + View status = LayoutInflater.from(getContext()).inflate(R.layout.layout_loading_more, null); + LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); + params.addRule(ALIGN_PARENT_BOTTOM); + status.setVisibility(View.GONE); + this.addView(status, getChildCount(), params); + mLoadingMore = findViewById(R.id.loading_text); + mLoadingContainer = findViewById(R.id.loading_more); + mProgress = findViewById(R.id.loading_progress); + } + + /** + * 加载,出错,网络错误等状态显示的container + */ + private void addStatus() { + setId(R.id.status_layout); + if (paddingBottom > 0) { + setPadding(0, 0, 0, paddingBottom); + setOnHierarchyChangeListener(new OnHierarchyChangeListener() { + @Override + public void onChildViewAdded(View parent, View child) { + setBackgroundResource(R.color.common_bg_color); + } + + @Override + public void onChildViewRemoved(View parent, View child) { + setBackgroundResource(R.color.transparent); + } + }); + } + setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); + } + + public void showErrorPage(int tips, OnClickListener listener) { + if (mLoadingMore == null) + return; + if (tips <= 0) + tips = R.string.click_or_pull_refresh; + String text = getContext().getString(tips); + + mLoadingMore.setText(text); + mLoadingContainer.setOnClickListener(listener); + mProgress.setVisibility(View.GONE); + mLoadingContainer.setVisibility(View.VISIBLE); + } + + public void showLoadMore() { + mLoadingMore.setText(getContext().getString(R.string.loading)); + mProgress.setVisibility(View.VISIBLE); + mLoadingContainer.setOnClickListener(null); + mLoadingContainer.setVisibility(View.VISIBLE); + } + + public void hideLoadMore() { + try { + mLoadingContainer.setVisibility(View.GONE); + } catch (Exception e) { + MLog.error(this, "hideLoadMore error ", e); + mHandler.sendEmptyMessage(0); + } + + } + + Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + mLoadingContainer.setVisibility(View.GONE); + MLog.info(this, "hideLoadMore in handler", ""); + } + }; +} diff --git a/app/src/main/java/com/chwl/app/common/widget/TextDrawable.java b/app/src/main/java/com/chwl/app/common/widget/TextDrawable.java new file mode 100644 index 0000000..97e1b87 --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/widget/TextDrawable.java @@ -0,0 +1,66 @@ +package com.chwl.app.common.widget; + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.drawable.Drawable; +import android.text.TextUtils; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +public class TextDrawable extends Drawable { + + private String mContent; + private Paint mPaint; + private float mWidth; + private float mHeight; + + public TextDrawable(String content, float width, float height, int size) { + mContent = content; + mWidth = width; + mHeight = height; + + mPaint = new Paint(); + mPaint.setColor(Color.WHITE); + mPaint.setAntiAlias(true); + mPaint.setStrokeWidth(5); + mPaint.setStyle(Paint.Style.FILL); + mPaint.setTextAlign(Paint.Align.CENTER); + mPaint.setTextSize(size); + } + + @Override + public void draw(@NonNull Canvas canvas) { + if (!TextUtils.isEmpty(mContent)) { + Paint.FontMetrics fontMetrics = mPaint.getFontMetrics(); + float top = fontMetrics.top;//为基线到字体上边框的距离 + float bottom = fontMetrics.bottom;//为基线到字体下边框的距离 + Log.i("TextDrawable", "top:" + top); + Log.i("TextDrawable", "bottom:" + bottom); + + float y = mHeight / 2 - top / 2 - bottom / 2; + + canvas.drawText(mContent, mWidth, y, mPaint); + } + + } + + @Override + public void setAlpha(int alpha) { + + } + + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) { + + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } +} diff --git a/app/src/main/java/com/chwl/app/common/widget/TutuSwitchView.java b/app/src/main/java/com/chwl/app/common/widget/TutuSwitchView.java new file mode 100644 index 0000000..5cd47d4 --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/widget/TutuSwitchView.java @@ -0,0 +1,29 @@ +package com.chwl.app.common.widget; + +import android.content.Context; +import android.util.AttributeSet; + +import androidx.core.content.ContextCompat; + +import com.chwl.app.R; +import com.chwl.library.widget.IOSSwitchView; + +/** + * 开关控件,涉及ui,继承library的 {@link com.chwl.library.widget.IOSSwitchView} + * 改写UI + * Created by lvzebiao on 2019/1/25. + */ + +public class TutuSwitchView extends IOSSwitchView { + + public TutuSwitchView(Context context, AttributeSet attrs) { + super(context, attrs); + setNoStrokeColor(true); + setmIsKeepRate(true); + } + + @Override + public int getSelectedColor() { + return ContextCompat.getColor(getContext(), R.color.app_248cfe); + } +} diff --git a/app/src/main/java/com/chwl/app/common/widget/dialog/BaseAlertDialogBuilder.java b/app/src/main/java/com/chwl/app/common/widget/dialog/BaseAlertDialogBuilder.java new file mode 100644 index 0000000..ddd3811 --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/widget/dialog/BaseAlertDialogBuilder.java @@ -0,0 +1,18 @@ +package com.chwl.app.common.widget.dialog; + +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AlertDialog; + +public class BaseAlertDialogBuilder extends AlertDialog.Builder { + + public BaseAlertDialogBuilder(@NonNull Context context) { + super(context); + } + + public BaseAlertDialogBuilder(@NonNull Context context, int themeResId) { + super(context, themeResId); + } + +} diff --git a/app/src/main/java/com/chwl/app/common/widget/dialog/ChooseWorldsIndicatorAdapter.java b/app/src/main/java/com/chwl/app/common/widget/dialog/ChooseWorldsIndicatorAdapter.java new file mode 100644 index 0000000..7e0303f --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/widget/dialog/ChooseWorldsIndicatorAdapter.java @@ -0,0 +1,77 @@ +package com.chwl.app.common.widget.dialog; + +import android.content.Context; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import androidx.core.content.ContextCompat; + +import com.chwl.app.R; +import com.chwl.app.decoration.view.widgets.BadgeScaleTransitionPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.CommonNavigatorAdapter; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.indicators.LinePagerIndicator; +import com.chwl.core.home.bean.TabInfo; + +import java.util.List; + +public class ChooseWorldsIndicatorAdapter extends CommonNavigatorAdapter { + + private Context mContext; + private List mTitleList; + private int mBottomMargin; + + public ChooseWorldsIndicatorAdapter(Context context, List titleList, int bottomMargin) { + mContext = context; + mTitleList = titleList; + mBottomMargin = bottomMargin; + } + + @Override + public int getCount() { + return mTitleList == null ? 0 : mTitleList.size(); + } + + @Override + public IPagerTitleView getTitleView(Context context, final int i) { + BadgeScaleTransitionPagerTitleView scaleTransitionPagerTitleView = new BadgeScaleTransitionPagerTitleView(context); + scaleTransitionPagerTitleView.setNormalColor(ContextCompat.getColor(mContext, R.color.color_B3B3B3)); + scaleTransitionPagerTitleView.setSelectedColor(ContextCompat.getColor(mContext, R.color.color_333333)); + scaleTransitionPagerTitleView.setMinScale(1); + scaleTransitionPagerTitleView.setTextSize(16); + scaleTransitionPagerTitleView.setText(mTitleList.get(i).getName()); + scaleTransitionPagerTitleView.setOnClickListener(view -> { + if (mOnItemSelectListener != null) { + mOnItemSelectListener.onItemSelect(i); + } + }); + return scaleTransitionPagerTitleView; + } + + + @Override + public IPagerIndicator getIndicator(Context context) { + LinePagerIndicator indicator = new LinePagerIndicator(context); + indicator.setMode(LinePagerIndicator.MODE_EXACTLY); + indicator.setLineHeight(UIUtil.dip2px(mContext, 3)); + indicator.setRoundRadius(UIUtil.dip2px(mContext, 1.5)); + indicator.setLineWidth(UIUtil.dip2px(mContext, 12)); + indicator.setColors(context.getResources().getColor(R.color.appColor)); + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + lp.bottomMargin = mBottomMargin; + indicator.setLayoutParams(lp); + return indicator; + } + + private OnItemSelectListener mOnItemSelectListener; + + public void setOnItemSelectListener(OnItemSelectListener onItemSelectListener) { + mOnItemSelectListener = onItemSelectListener; + } + + public interface OnItemSelectListener { + void onItemSelect(int position); + } +} diff --git a/app/src/main/java/com/chwl/app/common/widget/dialog/CommonPopupDialog.java b/app/src/main/java/com/chwl/app/common/widget/dialog/CommonPopupDialog.java new file mode 100644 index 0000000..ac03fb6 --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/widget/dialog/CommonPopupDialog.java @@ -0,0 +1,160 @@ +package com.chwl.app.common.widget.dialog; + +import android.content.Context; +import android.os.Bundle; +import android.util.DisplayMetrics; +import android.view.Display; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.widget.FrameLayout; +import android.widget.TextView; + +import com.chwl.app.R; +import com.chwl.app.ui.widget.ButtonItem; +import com.chwl.library.common.util.Utils; +import com.example.lib_core.component.SuperBottomSheetDialog; +import com.google.android.material.bottomsheet.BottomSheetBehavior; + +import java.util.List; + +/** + * @author xiaoyu + */ +public class CommonPopupDialog extends SuperBottomSheetDialog implements OnClickListener { + private static final int BUTTON_ITEM_ID = 135798642; + + private int mId; + private ViewGroup mRootView; + protected ViewGroup mContentView; + private TextView mMessageTv; + private TextView mCancelBtn; + private View v2; + private int id; + private String title; + private List buttons; + private ButtonItem bottomButton; + private Context context; + private boolean isFullScreen = true; + + public CommonPopupDialog(Context context, String title, List buttons, String cancelBtnText) { + this(0, context, title, buttons, new ButtonItem(cancelBtnText, null)); + } + + public CommonPopupDialog(Context context, String title, List buttons, final ButtonItem bottomButton) { + this(0, context, title, buttons, bottomButton); + } + + public CommonPopupDialog(Context context, String title, List buttons, String cancelBtnText, boolean isFullScreen) { + this(0, context, title, buttons, new ButtonItem(cancelBtnText, null)); + this.isFullScreen = isFullScreen; + } + + public CommonPopupDialog(int id, Context context, String title, List buttons, final ButtonItem bottomButton) { + super(context, R.style.ErbanBottomSheetDialog); + this.context = context; + this.id = id; + this.title = title; + this.buttons = buttons; + this.bottomButton = bottomButton; + setCanceledOnTouchOutside(true); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mId = id; + mRootView = (ViewGroup) View.inflate(getContext(), R.layout.layout_common_popup_dialog, null); + mContentView = mRootView.findViewById(R.id.ll_more); + mMessageTv = mRootView.findViewById(R.id.tv_message); + mCancelBtn = mRootView.findViewById(R.id.btn_cancel); + mCancelBtn.setOnClickListener(v -> { + if (bottomButton != null && bottomButton.mClickListener != null) { + bottomButton.mClickListener.onClick(); + } + dismiss(); + }); + + setContentView(mRootView); + + Window window = getWindow(); + WindowManager.LayoutParams params = window.getAttributes(); + params.width = WindowManager.LayoutParams.MATCH_PARENT; + params.height = WindowManager.LayoutParams.MATCH_PARENT; + WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + Display d = windowManager.getDefaultDisplay(); + DisplayMetrics realDisplayMetrics = new DisplayMetrics(); + d.getRealMetrics(realDisplayMetrics); + window.setAttributes(params); + window.setWindowAnimations(R.style.ErbanCommonWindowAnimationStyle); + + int size = buttons == null ? 0 : buttons.size(); + if (size > 0) { + if (title != null && !title.isEmpty()) { + setMessage(title); + } + mContentView.setVisibility(View.VISIBLE); + for (int i = 0; i < size; i++) { + addItem(buttons.get(i)); + } + } + if (bottomButton != null && bottomButton.mText != null && !bottomButton.mText.isEmpty()) { + mCancelBtn.setVisibility(View.VISIBLE); + mCancelBtn.setText(bottomButton.mText); + } + FrameLayout bottomSheet = findViewById(R.id.design_bottom_sheet); + if (bottomSheet != null) { + BottomSheetBehavior.from(bottomSheet).setSkipCollapsed(false); + BottomSheetBehavior.from(bottomSheet).setPeekHeight( + (int) context.getResources().getDimension(R.dimen.dialog_common_button_item_height) * (size + 3) + + Utils.dip2px(context, 5)); + } + } + + public CommonPopupDialog setMessage(String text) { + mMessageTv.setVisibility(View.VISIBLE); + mMessageTv.setText(text); + return this; + } + + public void addItem(final ButtonItem buttonItem) { + if (buttonItem.mView != null) { + mContentView.addView(buttonItem.mView, mContentView.getChildCount()); + }else { + TextView item = (TextView) LayoutInflater.from(getContext()).inflate(buttonItem.mLayout, mContentView, false); + if (buttonItem.mTheme != -1) { + item.setTextAppearance(getContext(), buttonItem.mTheme); + } + if (buttonItem.getTextColor() != 0) { + item.setTextColor(buttonItem.getTextColor()); + } + item.setText(buttonItem.mText); + item.setOnClickListener(v -> { + buttonItem.mClickListener.onClick(); + dismiss(); + }); + item.setId(BUTTON_ITEM_ID + mContentView.getChildCount()); + mContentView.addView(item, mContentView.getChildCount()); + } + + } + + public void addDivider() { + View v2 = LayoutInflater.from(getContext()).inflate(R.layout.layout_common_popup_dialog_divider, mContentView, false); + v2.setVisibility(View.VISIBLE); + mContentView.addView(v2, mContentView.getChildCount()); + } + + public int getId() { + return mId; + } + + @Override + public void onClick(View v) { + } + +} diff --git a/app/src/main/java/com/chwl/app/common/widget/dialog/CustomPopupDialog.java b/app/src/main/java/com/chwl/app/common/widget/dialog/CustomPopupDialog.java new file mode 100644 index 0000000..2e455e5 --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/widget/dialog/CustomPopupDialog.java @@ -0,0 +1,118 @@ +package com.chwl.app.common.widget.dialog; + +import android.app.AlertDialog; +import android.content.Context; +import android.text.TextUtils; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.widget.TextView; + +import com.chwl.app.R; +import com.chwl.app.ui.widget.ButtonItem; +import com.chwl.library.utils.ResolutionUtils; + +import java.util.List; + +public class CustomPopupDialog extends AlertDialog implements OnClickListener { + + private ViewGroup mRootView; + private ViewGroup mContentView; + private TextView mMessageTv; + private TextView mCancelBtn; + private View v2; + + public CustomPopupDialog(Context context, String title, List buttons) { + super(context); + show(); + + mRootView = (ViewGroup) View.inflate(getContext(), R.layout.layout_custom_popup_dialog, null); + mContentView = (ViewGroup) mRootView.findViewById(R.id.ll_more); + mMessageTv = (TextView) mRootView.findViewById(R.id.tv_message); + /*mCancelBtn = (TextView) mRootView.findViewById(R.id.btn_cancel); + mCancelBtn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if(bottomButton!=null && bottomButton.mClickListener!=null){ + bottomButton.mClickListener.onClick(); + } + dismiss(); + } + });*/ + + Window window = getWindow(); + WindowManager.LayoutParams params = window.getAttributes(); + params.height = WindowManager.LayoutParams.WRAP_CONTENT; + params.width = (int) (ResolutionUtils.getScreenWidth(context) * 0.85); + window.setGravity( Gravity.CENTER ); + window.setAttributes(params); + window.setBackgroundDrawableResource(android.R.color.transparent); + //window.setWindowAnimations(R.style.DialogAnimation); + window.setContentView(mRootView); + + int size = buttons == null ? 0 : buttons.size(); + if(size > 0){ + if(!TextUtils.isEmpty(title)){ + setMessage(title); + } + mContentView.setVisibility(View.VISIBLE); + for (int i = 0; i < size; i++) { + if (i == 0 && TextUtils.isEmpty(title)) { + addItem(buttons.get(0), 0); + } else { + addDivider(); + addItem(buttons.get(i), i == size - 1 ? 2 : 1); + } + } + } + /*if(bottomButton != null && bottomButton.mText!=null && !bottomButton.mText.isEmpty()){ + mCancelBtn.setVisibility(View.VISIBLE); + mCancelBtn.setText(bottomButton.mText); + }*/ + } + + public CustomPopupDialog setMessage(String text) { + mMessageTv.setVisibility(View.VISIBLE); + mMessageTv.setText(text); + return this; + } + + public void addItem(final ButtonItem buttonItem, int level){ + TextView item = (TextView) LayoutInflater.from(getContext()).inflate(buttonItem.mLayout, mContentView, false); + item.setText(buttonItem.mText); + item.getBackground().setLevel(level); + if (buttonItem.mButtonType == ButtonItem.BUTTON_TYPE_CANCEL) { +// item.setTextColor(getContext().getResources().getColorStateList(R.drawable.dialog_bottom_btn_color)); + item.setTextColor(getContext().getResources().getColor(R.color.text_color_system)); + } + if(buttonItem.mClickListener!=null) { + item.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + buttonItem.mClickListener.onClick(); + dismiss(); + } + }); + }else{ + item.setTextColor(getContext().getResources().getColor(R.color.text_color_system)); + item.setGravity(Gravity.LEFT); + item.setText("  "+buttonItem.mText); + } + mContentView.addView(item, mContentView.getChildCount()); + } + + public void addDivider(){ + View v2 = LayoutInflater.from(getContext()).inflate(R.layout.layout_common_popup_dialog_divider, mContentView, false); + v2.setVisibility(View.VISIBLE); + mContentView.addView(v2, mContentView.getChildCount()); + } + + @Override + public void onClick(View v) { + } + +} diff --git a/app/src/main/java/com/chwl/app/common/widget/dialog/DialogManager.java b/app/src/main/java/com/chwl/app/common/widget/dialog/DialogManager.java new file mode 100644 index 0000000..815db82 --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/widget/dialog/DialogManager.java @@ -0,0 +1,1199 @@ +package com.chwl.app.common.widget.dialog; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.os.Build; +import android.text.SpannableString; +import android.text.TextUtils; +import android.text.style.ForegroundColorSpan; +import android.view.Gravity; +import android.view.KeyEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.widget.Button; +import android.widget.EditText; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.Switch; +import android.widget.TextView; + +import androidx.appcompat.app.AlertDialog; + +import com.chwl.app.R; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.app.ui.widget.ButtonItem; +import com.chwl.app.utils.SpannableBuilder; +import com.chwl.core.utils.ActivityUtil; +import com.chwl.library.common.util.OtherExtKt; +import com.chwl.library.utils.log.MLog; +import com.makeramen.roundedimageview.RoundedImageView; +import com.netease.nim.uikit.common.util.string.StringUtil; +import com.netease.nim.uikit.support.glide.GlideApp; + +import java.util.List; + +import kotlinx.coroutines.Job; + +//import javax.xml.soap.Text; + +public class DialogManager { + + private static final String TAG = "DialogManager"; + + private volatile Dialog mDialog; + private Context mContext; + private AlertDialog.Builder mBuilder; + private boolean mCanceledOnClickBackKey = true; + private boolean mCanceledOnClickOutside = true; + private boolean mReCreate = true; + /** + * 新增的一種彈框類型,支持只彈一次 + */ + private Switch switchTips; + private int mProgressMax = 0; + private String mTip; + private boolean isError; + + public DialogManager(Context context) { + mContext = context; + mBuilder = new BaseAlertDialogBuilder(context, R.style.MyAlertDialogStyle); + mDialog = mBuilder.create(); + } + + public DialogManager(Context context, boolean noCreate) { + mContext = context; + mBuilder = new BaseAlertDialogBuilder(context, R.style.MyAlertDialogStyle); + if (!noCreate) { + mDialog = mBuilder.create(); + } + } + + public DialogManager(Context context, boolean canceledOnClickBackKey, boolean canceledOnClickOutside) { + mContext = context; + mBuilder = new BaseAlertDialogBuilder(context, R.style.MyAlertDialogStyle); + mDialog = mBuilder.create(); + mCanceledOnClickBackKey = canceledOnClickBackKey; + mCanceledOnClickOutside = canceledOnClickOutside; + } + + public void recycle() { + mDialog = null; + } + + public DialogManager(boolean isError) { + this.isError = isError; + } + + public static boolean isHtmlAlertDialog(String html) { + try { + return html.matches(".*<([^>]*)>.*"); + } catch (Exception e) { + return false; + } + } + + /** + * 註釋 見 {@link DialogManager#showOkCancelDialog( + *CharSequence, CharSequence, CharSequence, CharSequence, boolean, + * boolean, boolean, OkCancelDialogListener, OnKeyBackListener, boolean)} + */ + public static void setDialog(Dialog dialog, CharSequence title, CharSequence message, CharSequence okLabel, + CharSequence cancelLabel, boolean isCanCancel, boolean canceledOnTouchOutside, + final boolean isAutoHide, final OkCancelDialogListener l, + final OnKeyBackListener backListener, boolean dismissAfterBack) { + dialog.setCancelable(isCanCancel); + dialog.setCanceledOnTouchOutside(canceledOnTouchOutside); + + Window window = dialog.getWindow(); + window.setContentView(R.layout.layout_common_ok_cancel_dialog); + //標題 + TextView tvTilte = window.findViewById(R.id.tv_title); + if (tvTilte != null) { + if (!TextUtils.isEmpty(title)) { + tvTilte.setVisibility(View.VISIBLE); + tvTilte.setText(title); + } else { + tvTilte.setVisibility(View.GONE); + } + } + //內容 + TextView tip = window.findViewById(R.id.message); + tip.setText(message); + + TextView ok = window.findViewById(R.id.btn_ok); + if (!TextUtils.isEmpty(okLabel)) { + ok.setText(okLabel); + } + ok.setOnClickListener(v -> { + if (isAutoHide) { + dialog.dismiss(); + } + if (l != null) { + l.onOk(); + } + }); + + TextView cancel = window.findViewById(R.id.btn_cancel); + if (!TextUtils.isEmpty(cancelLabel)) { + cancel.setText(cancelLabel); + cancel.setOnClickListener(v -> { + if (isAutoHide) { + dialog.dismiss(); + } + if (l != null) { + l.onCancel(); + } + }); + } else { + cancel.setVisibility(View.GONE); + } + + if (backListener != null) { + dialog.setOnKeyListener((dialog1, keyCode, event) -> { + if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0 + && event.getAction() == KeyEvent.ACTION_DOWN) { + if (dismissAfterBack) { + dialog.dismiss(); + } + backListener.onBack(); + return true; + } + return false; + }); + } + } + + public static void setDialog2(Dialog dialog, CharSequence title, CharSequence message, CharSequence okLabel, + CharSequence cancelLabel, boolean isCanCancel, boolean canceledOnTouchOutside, + final boolean isAutoHide, final OkCancelDialogListener l, + final OnKeyBackListener backListener, boolean dismissAfterBack) { + dialog.setCancelable(isCanCancel); + dialog.setCanceledOnTouchOutside(canceledOnTouchOutside); + + Window window = dialog.getWindow(); + window.setContentView(R.layout.layout_common_ok_cancel_dialog); + //標題 + TextView tvTilte = window.findViewById(R.id.tv_title); + if (tvTilte != null) { + if (!TextUtils.isEmpty(title)) { + tvTilte.setVisibility(View.VISIBLE); + tvTilte.setText(title); + } else { + tvTilte.setVisibility(View.GONE); + } + } + //內容 + TextView tip = window.findViewById(R.id.message); + tip.setText(message); + + TextView ok = window.findViewById(R.id.btn_ok); + if (!TextUtils.isEmpty(okLabel)) { + ok.setText(okLabel); + } else { + ok.setVisibility(View.GONE); + } + ok.setOnClickListener(v -> { + if (isAutoHide) { + dialog.dismiss(); + } + if (l != null) { + l.onOk(); + } + }); + + TextView cancel = window.findViewById(R.id.btn_cancel); + if (!TextUtils.isEmpty(cancelLabel)) { + cancel.setText(cancelLabel); + cancel.setOnClickListener(v -> { + if (isAutoHide) { + dialog.dismiss(); + } + if (l != null) { + l.onCancel(); + } + }); + } else { + cancel.setVisibility(View.GONE); + } + + if (backListener != null) { + dialog.setOnKeyListener((dialog1, keyCode, event) -> { + if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0 + && event.getAction() == KeyEvent.ACTION_DOWN) { + if (dismissAfterBack) { + dialog.dismiss(); + } + backListener.onBack(); + return true; + } + return false; + }); + } + } + + /** + * 註釋 見 {@link DialogManager#showOkCancelDialog( + *CharSequence, CharSequence, CharSequence, CharSequence, boolean, + * boolean, boolean, OkCancelDialogListener, OnKeyBackListener, boolean)} + */ + public static void setHelloDialog(Dialog dialog, String avatar, int gender, CharSequence title, CharSequence message, CharSequence okLabel, + CharSequence cancelLabel, boolean isCanCancel, boolean canceledOnTouchOutside, + final boolean isAutoHide, final OkCancelDialogListener l, + final OnKeyBackListener backListener, boolean dismissAfterBack, Context context) { + dialog.setCancelable(isCanCancel); + dialog.setCanceledOnTouchOutside(canceledOnTouchOutside); + + Window window = dialog.getWindow(); + window.setContentView(R.layout.layout_newbie_hello_dialog); + //頭像 + RoundedImageView ivAvatar = window.findViewById(R.id.iv_avatar); + if (ivAvatar != null) { + if (!TextUtils.isEmpty(avatar)) { + ivAvatar.setVisibility(View.VISIBLE); + GlideApp.with(context) + .load(avatar) +// .diskCacheStrategy(DiskCacheStrategy.ALL) +// .transforms(new CenterCrop(), +// new RoundedCorners(context.getResources().getDimensionPixelOffset(R.dimen.dp_6))) + .into(ivAvatar); + } else { + ivAvatar.setVisibility(View.GONE); + } + } + + //性別 + ImageView ivGender = window.findViewById(R.id.iv_gender); + ivGender.setImageDrawable(gender == 1 ? context.getResources().getDrawable(R.drawable.ic_gender_male) : context.getResources().getDrawable(R.drawable.ic_gender_female)); + //標題 + TextView tvTilte = window.findViewById(R.id.tv_title); + if (tvTilte != null) { + if (!TextUtils.isEmpty(title)) { + tvTilte.setVisibility(View.VISIBLE); + tvTilte.setText(title); + } else { + tvTilte.setVisibility(View.GONE); + } + } + //內容 + TextView tip = window.findViewById(R.id.message); + tip.setText(message); + + TextView ok = window.findViewById(R.id.btn_ok); + if (!TextUtils.isEmpty(okLabel)) { + ok.setText(okLabel); + } + ok.setOnClickListener(v -> { + if (isAutoHide) { + dialog.dismiss(); + } + if (l != null) { + l.onOk(); + } + }); + + TextView cancel = window.findViewById(R.id.btn_cancel); + if (!TextUtils.isEmpty(cancelLabel)) { + cancel.setText(cancelLabel); + cancel.setOnClickListener(v -> { + if (isAutoHide) { + dialog.dismiss(); + } + if (l != null) { + l.onCancel(); + } + }); + } else { + cancel.setVisibility(View.GONE); + } + + if (backListener != null) { + dialog.setOnKeyListener((dialog1, keyCode, event) -> { + if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0 + && event.getAction() == KeyEvent.ACTION_DOWN) { + if (dismissAfterBack) { + dialog.dismiss(); + } + backListener.onBack(); + return true; + } + return false; + }); + } + } + + public static Dialog createDialog(Context context) { + AlertDialog.Builder builder = new BaseAlertDialogBuilder(context, R.style.MyAlertDialogStyle); + return builder.create(); + } + + public Context getContext() { + return mContext; + } + + @TargetApi(17) + public boolean checkActivityValid() { + if (mContext == null) { + MLog.warn(this, "Fragment " + this + " not attached to Activity"); + return false; + } + if (mDialog != null && mDialog.getWindow() == null) { + MLog.warn(this, "window null"); + return false; + } + if (((Activity) mContext).isFinishing()) { + MLog.warn(this, "activity is finishing"); + return false; + } + + if (Build.VERSION.SDK_INT >= 17 && ((Activity) mContext).isDestroyed()) { + MLog.warn(this, "activity is isDestroyed"); + return false; + } + return true; + } + + public void dismissDialog() { + //註釋這個判斷,因為不保留活動情況下,((Activity)mContext).isDestroyed() 為true 導致不執行dismiss一個dialog + //而mDialog.getWindow()不為null,還是可以dismiss一個dialog的。 +// if(!checkActivityValid()) +// return; + //加上一個try,強行吞異常 + try { + if (mContext != null && mDialog != null && mDialog.getWindow() != null) { + if (mContext instanceof Activity) { + Activity activity = (Activity) mContext; + if (!activity.isFinishing()) { + //如果dialog在延時比如handler。postDelay中調用, + // 而activity.已經destory, + // 會報異常java.lang.IllegalArgumentException: + // View not attached to window manager + mDialog.dismiss(); + } + } else { + if (mDialog != null) { + mDialog.dismiss(); + } + } + } + } catch (Exception e) { + + } + } + + public boolean isDialogShowing() { + if (mDialog != null) { + return mDialog.isShowing(); + } + return false; + } + + public void setCanceledOnClickBackKey(boolean cancelable) { + mCanceledOnClickBackKey = cancelable; + } + + public void setCanceledOnClickOutside(boolean cancelable) { + mCanceledOnClickOutside = cancelable; + } + + /** + * 只有確定按鈕 + * 帶標題 + */ + public void showOkWithTitleDialog(CharSequence title, CharSequence message, + CharSequence okLabel, boolean isCanCancel, OkCancelDialogListener l) { + showOkCancelDialog(title, message, okLabel, null, isCanCancel, l); + } + + public void showOkWithTitleDialog(CharSequence message, boolean isCanCancel) { + showOkWithTitleDialog(getContext().getString(R.string.common_tip), message, getContext().getString(R.string.text_ok), isCanCancel, null); + } + + public void showOkWithTitleDialog(CharSequence message) { + showOkWithTitleDialog(message, true); + } + + public void showOkDialog(CharSequence message) { + showOkDialog(message, true); + } + + public void showOkDialog(CharSequence message, boolean isCanCancel) { + showOkDialog(message, isCanCancel, null); + } + + public void showOkDialog(CharSequence message, final OkCancelDialogListener l) { + showOkDialog(message, mCanceledOnClickOutside, l); + } + + public void showOkDialog(CharSequence message, boolean isCanCancel, final OkCancelDialogListener l) { + showOkDialog(message, getContext().getString(R.string.text_ok), isCanCancel, l); + } + + public void showOkDialog(CharSequence message, CharSequence okLable, boolean isCanCancel, final OkCancelDialogListener l) { + showOkCancelDialog(message, okLable, null, isCanCancel, l); + } + + public void showCommonPopupDialog(List btnItems) { + showCommonPopupDialog(null, btnItems, ""); + } + + public void showCommonPopupDialog(String cancelBtnText) { + showCommonPopupDialog(null, null, cancelBtnText); + } + + public void showCommonPopupDialog(String title, int layout_bottom_select_dialog, ButtonItem bottomButton) { + showCommonPopupDialog(null, null, bottomButton); + } + + public void showCommonPopupDialog(String title, List btnItems) { + showCommonPopupDialog(title, btnItems, ""); + } + + public void showCommonPopupDialog(List btnItems, String cancelBtnText) { + showCommonPopupDialog(null, btnItems, cancelBtnText); + } + + public void showCommonPopupDialog(List btnItems, String cancelBtnText, boolean isFullscreen) { + showCommonPopupDialog(null, btnItems, cancelBtnText, isFullscreen); + } + + public void showCommonPopupDialog(List btnItems, ButtonItem bottomButton) { + showCommonPopupDialog(null, btnItems, bottomButton); + } + + public void showCommonPopupDialog(String title, List btnItems, ButtonItem bottomButton) { + + if (!checkActivityValid()) { + MLog.info(this, "showCommonPopupDialog ActivityInvalid."); + return; + } + + if (mDialog.isShowing()) { + mDialog.dismiss(); + } + mDialog = new CommonPopupDialog(mContext, title, btnItems, bottomButton); + mDialog.setCancelable(mCanceledOnClickBackKey); + mDialog.setCanceledOnTouchOutside(mCanceledOnClickOutside); + mDialog.show(); + } + + public void showCommonPopupDialog(String title, List btnItems, String cancelBtnText, boolean isFullScreen) { + + if (!checkActivityValid()) { + MLog.info(this, "showCommonPopupDialog ActivityInvalid.."); + return; + } + + if (mDialog.isShowing()) { + mDialog.dismiss(); + } + mDialog = new CommonPopupDialog(mContext, title, btnItems, cancelBtnText, isFullScreen); + mDialog.setCancelable(mCanceledOnClickBackKey); + mDialog.setCanceledOnTouchOutside(true); + mDialog.show(); + } + + public void showCommonPopupDialog(String title, List btnItems, String cancelBtnText) { + + if (!checkActivityValid()) { + MLog.info(this, "showCommonPopupDialog ActivityInvalid.."); + return; + } + + if (mDialog.isShowing()) { + mDialog.dismiss(); + } + mDialog = new CommonPopupDialog(mContext, title, btnItems, cancelBtnText); + mDialog.setCancelable(mCanceledOnClickBackKey); + mDialog.setCanceledOnTouchOutside(true); + mDialog.show(); + } + + public void showCustomPopupDialog(String title, List btnItems) { + if (!checkActivityValid()) { + MLog.info(this, "showCommonPopupDialog ActivityInvalid..."); + return; + } + if (mDialog.isShowing()) { + mDialog.dismiss(); + } + mDialog = new CustomPopupDialog(mContext, title, btnItems); + mDialog.setCancelable(mCanceledOnClickBackKey); + mDialog.setCanceledOnTouchOutside(mCanceledOnClickOutside); + mDialog.show(); + } + + public void showCommonPopupDialog(int id, String title, List btnItems, ButtonItem bottomButton) { + if (!checkActivityValid()) { + MLog.info(this, "showCommonPopupDialog ActivityInvalid...."); + return; + } + if (mDialog.isShowing()) { + mDialog.dismiss(); + } + mDialog = new CommonPopupDialog(id, mContext, title, btnItems, bottomButton); + mDialog.setCancelable(mCanceledOnClickBackKey); + mDialog.setCanceledOnTouchOutside(mCanceledOnClickOutside); + mDialog.show(); + } + + public int getShowingDialogId() { + if (mDialog != null && mDialog.isShowing() && mDialog instanceof CommonPopupDialog) { + return ((CommonPopupDialog) mDialog).getId(); + } + return 0; + } + + public Dialog getDialog() { + return mDialog; + } + + public void showNewbieHelloDialog(String avatar, int gender, CharSequence titleStr, CharSequence message, CharSequence okLabel, CharSequence cancelLabel, boolean cancelable, final OkCancelDialogListener l, Context context) { + showHelloDialog(avatar, gender, titleStr, message, okLabel, cancelLabel, cancelable, mCanceledOnClickOutside, true, l, null, false, context); + } + + public void showOkCancelDialog(CharSequence message, boolean cancelable, final OkCancelDialogListener l) { + showOkCancelDialog(message, getContext().getString(R.string.text_ok), + getContext().getString(R.string.text_canle), cancelable, l); + } + + public void showOkCancelDialog(CharSequence message, CharSequence okLabel, final OkCancelDialogListener l) { + showOkCancelDialog(message, okLabel, getContext().getString(R.string.text_canle), true, l); + } + + public void showOkCancelDialog(CharSequence message, final OkCancelDialogListener l) { + showOkCancelDialog(message, getContext().getString(R.string.text_ok), + getContext().getString(R.string.text_canle), true, l); + } + + public void showOkCancelDialog(CharSequence message, CharSequence okLabel, CharSequence cancelLabel, final OkCancelDialogListener l) { + showOkCancelDialog(message, okLabel, cancelLabel, true, l); + } + + public void showTipsDialog(String message, OkCancelDialogListener l) { + showOkCancelWithTitleDialog(getContext().getString(R.string.common_tip), new SpannableString(message), + getContext().getString(R.string.text_ok), getContext().getString(R.string.text_canle), l); + } + + public void showTipsDialog(CharSequence message, String okLabel, OkCancelDialogListener l) { + showOkCancelWithTitleDialog(getContext().getString(R.string.common_tip), message, + okLabel, getContext().getString(R.string.text_canle), l); + } + + public void showOkCancelWithTitleDialog(CharSequence message, + final OkCancelDialogListener l) { + showOkCancelWithTitleDialog(message, getContext().getString(R.string.text_ok), + mCanceledOnClickOutside, l); + } + + public void showOkCancelWithTitleDialog(CharSequence message, CharSequence okLabel, + final OkCancelDialogListener l) { + showOkCancelWithTitleDialog(message, okLabel, mCanceledOnClickOutside, l); + } + + public void showOkCancelWithTitleDialog(CharSequence message, + CharSequence okLabel, + boolean isCanCancel, + final OkCancelDialogListener l) { + showOkCancelWithTitleDialog(getContext().getString(R.string.common_tip), message, okLabel, + isCanCancel, l); + } + + public void showOkCancelWithTitleDialog(CharSequence titleStr, CharSequence message, + CharSequence okLabel, boolean isCanCancel, + final OkCancelDialogListener l) { + showOkCancelDialog(titleStr, message, okLabel, getContext().getString(R.string.text_canle), + isCanCancel, l); + } + + public void showOkCancelWithTitleDialog(CharSequence titleStr, CharSequence message, + CharSequence okLabel, CharSequence cancelLabel, + final OkCancelDialogListener l) { + showOkCancelDialog(titleStr, message, okLabel, cancelLabel, l); + } + + public void showOkCancelWithTitleDialog(CharSequence titleStr, CharSequence message, + CharSequence okLabel, CharSequence cancelLabel, + boolean isCanCancel, + final OkCancelDialogListener l) { + showOkCancelDialog(titleStr, message, okLabel, cancelLabel, isCanCancel, l); + } + + public void showOkCancelDialog(CharSequence title, CharSequence message, CharSequence okLabel, CharSequence cancelLabel, + final OkCancelDialogListener l) { + showOkCancelDialog(title, message, okLabel, cancelLabel, mCanceledOnClickOutside, l); + } + + public void showOkCancelDialog(CharSequence title, CharSequence message, CharSequence okLabel, + CharSequence cancelLabel, boolean isCanCancel, + final OkCancelDialogListener l) { + showOkCancelDialog(title, message, okLabel, cancelLabel, isCanCancel, true, l); + } + + /** + * 1、通用的dialog設置,以後盡量所有的dialog都引到這個方法,方便以後改版 + * 2、如果UI要求彈框是完全自定義的,再重新寫過 + * + * @param title 標題,空則隱藏 (ui說,有些彈框帶標題,有些不帶,兩種情況共存) + * @param message 內容,不能為空,配合{@link com.chwl.app.utils.SpannableBuilder} 變色使用 + * @param okLabel ok按鈕,不能隱藏,默認為 text="確定" + * @param cancelLabel 取消按鈕,空則隱藏,一般現在都用text="取消" + * @param l 點擊監聽 + * @param isCanCancel 點擊返回鍵是否可以取消,默認=false,dialog初始化的時候,為false + * (ui說,ture和false根據情況而定,一般自己根據理解選擇) + * @param canceledOnTouchOutside ture的話,點擊背景消失 + * @param isAutoHide 默認ture,點擊按鈕的時候,自動隱藏dialog,(暫時用不到屬性,放著先) + * @param backListener 彈窗返回鍵的監聽 + * @param dismissAfterBack 點擊返回鍵是否自動dismiss + */ + public void showOkCancelDialog(CharSequence title, CharSequence message, CharSequence okLabel, + CharSequence cancelLabel, boolean isCanCancel, boolean canceledOnTouchOutside, + final boolean isAutoHide, final OkCancelDialogListener l, + final OnKeyBackListener backListener, boolean dismissAfterBack) { + + if (!checkActivityValid()) { + MLog.info(this, "showOkCancelDialog ActivityInvalid...."); + return; + } + + if (mDialog.isShowing()) { + mDialog.dismiss(); + } + mDialog = mBuilder.create(); + mDialog.show(); + + setDialog(mDialog, title, message, okLabel, cancelLabel, isCanCancel, + canceledOnTouchOutside, isAutoHide, l, backListener, dismissAfterBack); + + } + + public void showHelloDialog(String avatar, int gender, CharSequence title, CharSequence message, CharSequence okLabel, + CharSequence cancelLabel, boolean isCanCancel, boolean canceledOnTouchOutside, + final boolean isAutoHide, final OkCancelDialogListener l, final OnKeyBackListener backListener, boolean dismissAfterBack + , Context context) { + + if (!checkActivityValid()) { + MLog.info(this, "showOkCancelDialog ActivityInvalid...."); + return; + } + + if (mDialog.isShowing()) { + mDialog.dismiss(); + } + mDialog = mBuilder.create(); + mDialog.show(); + + setHelloDialog(mDialog, avatar, gender, title, message, okLabel, cancelLabel, isCanCancel, + canceledOnTouchOutside, isAutoHide, l, backListener, dismissAfterBack, context); + + } + + public void showOkCancelDialog(CharSequence title, CharSequence message, CharSequence okLabel, + CharSequence cancelLabel, boolean isCanCancel, + final boolean isAutoHide, final OkCancelDialogListener l) { + //一般情況,點擊背景和返回鍵一起處理 + showOkCancelDialog(title, message, okLabel, cancelLabel, isCanCancel, isCanCancel, + isAutoHide, l, null, false); + } + + public void showOkCancelDialog(CharSequence message, CharSequence okLabel, CharSequence cancelLabel, + boolean cancelable, final OkCancelDialogListener l) { + showOkCancelDialog(null, message, okLabel, cancelLabel, cancelable, l); + } + + public void showOkCancelDialog(CharSequence title, CharSequence[] messages, + final OkCancelDialogListener l) { + showOkCancelDialog(title, messages, getContext().getString(R.string.text_ok), + getContext().getString(R.string.text_canle), mCanceledOnClickOutside, l); + } + + /** + * @param title 不需要則傳空 + * @param messages 黑色文字和主題色文字輪著來的一個字符串數組 + */ + public void showOkCancelDialog(CharSequence title, CharSequence[] messages, + CharSequence okLable, CharSequence cancelLable, + boolean isCanCancel, + final OkCancelDialogListener l) { + SpannableBuilder builder = new SpannableBuilder(); + for (int i = 0; i < messages.length; i++) { + if (i % 2 == 0) { + builder.append(messages[i]); + } else { + builder.append(messages[i], new ForegroundColorSpan( + getContext().getResources().getColor(R.color.appColor))); + } + } + showOkCancelDialog(title, builder.build(), okLable, + cancelLable, isCanCancel, l); + } + + /** + * @param messages 黑色文字和主題色文字輪著來的一個字符串數組 + */ + public void showOkCancelWithTitleDialog(CharSequence[] messages, + final OkCancelDialogListener l) { + showOkCancelDialog(getContext().getString(R.string.common_tip), messages, l); + } + + public void showOkCancelWithTitleDialog(CharSequence[] messages, String okLable, boolean isCanCancel, + final OkCancelDialogListener l) { + showOkCancelDialog(getContext().getString(R.string.common_tip), messages, okLable, + getContext().getString(R.string.text_canle), isCanCancel, l); + } + + public void showBuyCarSucDialog(String msg) { + + if (!checkActivityValid()) { + MLog.info(this, "showOkCancelDialog ActivityInvalid.."); + return; + } + if (mDialog.isShowing()) { + mDialog.dismiss(); + } + mDialog = mBuilder.create(); + + mDialog.setCancelable(true); + mDialog.setCanceledOnTouchOutside(mCanceledOnClickOutside); + mDialog.show(); + Window window = mDialog.getWindow(); + window.setContentView(R.layout.dialog_buy_decoration); + TextView view = window.findViewById(R.id.tv_msg); + view.setText(msg); + window.setGravity(Gravity.CENTER); + window.findViewById(R.id.tv_iknow).setOnClickListener(v -> mDialog.dismiss()); + } + + public void showLuckyMoneyConfirmToPayDialog(String amount, String fee, String coinName, View.OnClickListener listener) { + if (!checkActivityValid()) { + MLog.info(this, "showOkCancelDialog ActivityInvalid.."); + return; + } + if (mDialog.isShowing()) { + mDialog.dismiss(); + } + mDialog = mBuilder.create(); + mDialog.setCancelable(false); + mDialog.setCanceledOnTouchOutside(false); + mDialog.show(); + Window window = mDialog.getWindow(); + window.setContentView(R.layout.dialog_lucky_money_confirm_to_pay); + window.setGravity(Gravity.CENTER); + TextView subTitle = window.findViewById(R.id.tv_sub_title_pay_lucky_money); + subTitle.setText(mContext.getString(R.string.lucky_money_pay_sub_title, coinName)); + TextView amountTextView = window.findViewById(R.id.tv_lucky_money_amount); + amountTextView.setText(amount); + TextView amountCoinName = window.findViewById(R.id.tv_coin_name); + amountCoinName.setText(coinName); + TextView feeTextView = window.findViewById(R.id.tv_lucky_money_fee); + feeTextView.setText(fee); + TextView feeCoinName = window.findViewById(R.id.tv_lucky_money_fee_coin_name); + feeCoinName.setText(coinName); + window.findViewById(R.id.iv_close).setOnClickListener(v -> mDialog.dismiss()); + Button btn = window.findViewById(R.id.btn_ready_to_pay); + btn.setOnClickListener(v -> { + mDialog.dismiss(); + listener.onClick(v); + }); + } + + public void showInAppSharingConfirmDialog(String avatar, String nick, String msg, OkCancelDialogListener l) { + if (!checkActivityValid()) { + MLog.info(this, "showOkCancelDialog ActivityInvalid...."); + return; + } + + if (mDialog.isShowing()) { + mDialog.dismiss(); + } + mDialog = mBuilder.create(); + + mDialog.setCancelable(true); + mDialog.setCanceledOnTouchOutside(true); + mDialog.show(); + Window window = mDialog.getWindow(); + window.setGravity(Gravity.CENTER); + window.setContentView(R.layout.dialog_in_app_sharing_confirm); + + ImageView avatarView = window.findViewById(R.id.iv_avatar); + ImageLoadUtils.loadAvatar(getContext().getApplicationContext(), avatar, avatarView); + + TextView nickView = window.findViewById(R.id.tv_nick); + nickView.setText(nick); + + TextView tvMessage = window.findViewById(R.id.message); + tvMessage.setText(msg); + + TextView ok = window.findViewById(R.id.btn_ok); + ok.setOnClickListener(v -> { + mDialog.dismiss(); + if (l != null) { + l.onOk(); + } + }); + + TextView cancel = window.findViewById(R.id.btn_cancel); + cancel.setOnClickListener(v -> { + mDialog.dismiss(); + if (l != null) { + l.onCancel(); + } + }); + } + + public void showCustomViewDialog(View contentView) { + if (!checkActivityValid()) { + MLog.info(this, "showOkCancelColorDialog ActivityInvalid...."); + return; + } + if (mDialog.isShowing()) { + mDialog.dismiss(); + } + mDialog = mBuilder.create(); + mDialog.show(); + Window window = mDialog.getWindow(); + window.setContentView(contentView); + + } + + public void showCustomViewDialog(int id) { + if (!checkActivityValid()) { + MLog.info(this, "showOkCancelColorDialog ActivityInvalid...."); + return; + } + if (mDialog.isShowing()) { + mDialog.dismiss(); + } + mDialog = mBuilder.create(); + mDialog.show(); + Window window = mDialog.getWindow(); + window.setContentView(id); + + } + + public void showOkCancelSwitchDialog(CharSequence message, OkCancelDialogListener l) { + if (!ActivityUtil.isValidContext(mContext)) { + return; + } + showOkCancelSwitchDialog(mContext.getString(R.string.common_tip), message, + mContext.getString(R.string.text_ok), mContext.getString(R.string.text_canle), + mCanceledOnClickOutside, l); + } + + public void showOkCancelSwitchDialog(CharSequence title, CharSequence message, CharSequence okLabel, + CharSequence cancelLabel, boolean isCanCancel, OkCancelDialogListener l) { + if (!ActivityUtil.isValidContext(mContext)) { + return; + } + View contentView = View.inflate(mContext, R.layout.dialog_custom_one_show_tips, null); + TextView tvTitle = contentView.findViewById(R.id.tv_title); + if (TextUtils.isEmpty(title)) { + tvTitle.setVisibility(View.GONE); + } else { + tvTitle.setVisibility(View.VISIBLE); + tvTitle.setText(title); + } + TextView tvMessage = contentView.findViewById(R.id.message); + tvMessage.setText(message); + switchTips = contentView.findViewById(R.id.switch_tips); + showOkCancelCustomDialog(contentView, okLabel, cancelLabel, isCanCancel, l); + } + + public void showOkCancelCustomDialog(View customView, boolean isCanCancel, OkCancelDialogListener l) { + showOkCancelCustomDialog(customView, getContext().getString(R.string.text_ok), + getContext().getString(R.string.text_canle), isCanCancel, true, l); + } + + public void showOkCancelCustomDialog(View customView, CharSequence okLabel, CharSequence cancelLabel, + boolean isCanCancel, OkCancelDialogListener l) { + showOkCancelCustomDialog(customView, okLabel, cancelLabel, isCanCancel, true, l); + } + + public void showOkCancelCustomDialog(View customView, CharSequence okLabel, CharSequence cancelLabel, + boolean isCanCancel, boolean isAutoHide, OkCancelDialogListener l) { + if (!checkActivityValid()) { + MLog.info(this, "showOkCancelDialog ActivityInvalid...."); + return; + } + + if (mDialog.isShowing()) { + mDialog.dismiss(); + } + mDialog = mBuilder.create(); + + mDialog.setCancelable(isCanCancel); + mDialog.setCanceledOnTouchOutside(isCanCancel); + mDialog.show(); + Window window = mDialog.getWindow(); + window.setContentView(R.layout.layout_custom_ok_cancel_dialog); + FrameLayout flContent = window.findViewById(R.id.fl_content); + flContent.addView(customView, new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT + )); + TextView ok = window.findViewById(R.id.btn_ok); + if (!TextUtils.isEmpty(okLabel)) { + ok.setText(okLabel); + } + ok.setOnClickListener(v -> { + if (isAutoHide) { + mDialog.dismiss(); + } + if (l != null) { + l.onOk(); + } + }); + + TextView cancel = window.findViewById(R.id.btn_cancel); + if (!TextUtils.isEmpty(cancelLabel)) { + cancel.setText(cancelLabel); + cancel.setOnClickListener(v -> { + if (isAutoHide) { + mDialog.dismiss(); + } + if (l != null) { + l.onCancel(); + } + }); + } else { + cancel.setVisibility(View.GONE); + } + + } + + public void setReCreate(boolean reCreate) { + mReCreate = reCreate; + } + + public void showProgressDialog(Context context) { + showProgressDialog(context, "請稍後...", mCanceledOnClickBackKey); + } + + public void showProgressDialog(Context context, boolean cancelable) { + showProgressDialog(context, "請稍後...", cancelable); + } + + public void showProgressDialog(Context context, String msg) { + showProgressDialog(context, msg, mCanceledOnClickBackKey); + } + + public void showProgressDialog(Context context, String msg, boolean cancelable) { + showProgressDialog(context, msg, cancelable, null); + } + + public void showProgressDialog(Context context, String msg, boolean cancelable, DialogInterface.OnDismissListener listener) { + showProgressDialog(context, msg, cancelable, mCanceledOnClickOutside, listener); + } + + public void showProgressDialog(Context context, String msg, boolean cancelable, boolean outSideCancelable, + DialogInterface.OnDismissListener listener, DialogInterface.OnCancelListener cancelListener) { + showProgressDialog(context, msg, cancelable, outSideCancelable, listener); + if (cancelListener != null && mDialog != null) { + mDialog.setOnCancelListener(cancelListener); + } + } + + private Job mTimeOutJob; + /** + * @param context + * @param msg + * @param cancelable 點擊返回鍵是否可取消 + * @param outSideCancelable 點擊對話框外部是否可取消 + * @param listener + */ + public void showProgressDialog(Context context, String msg, boolean cancelable, boolean outSideCancelable, DialogInterface.OnDismissListener listener) { + if (!checkActivityValid()) { + MLog.info(this, "showProgressDialog ActivityInvalid"); + return; + } + if (mDialog.isShowing()) { +// startTimeOutJob(mDialog); + return; + } + if (mReCreate) { + mDialog = mBuilder.create(); + } + mDialog.setCancelable(cancelable); + mDialog.setCanceledOnTouchOutside(outSideCancelable); + if (null != mContext) { + mDialog.show(); + } + mDialog.setContentView(R.layout.layout_progress_dialog); + TextView tvTip = mDialog.findViewById(R.id.tv_tip); + tvTip.setText(R.string.common_loading_tips); + + mDialog.setOnDismissListener(dialog -> { + if (listener != null) { + listener.onDismiss(dialog); + } + }); + +// startTimeOutJob(mDialog); + + } + + private void startTimeOutJob(Dialog dialog){ + if (dialog == null) return; + + if (mTimeOutJob != null) { + mTimeOutJob.cancel(null); + mTimeOutJob = null; + } + + mTimeOutJob = OtherExtKt.delayStart(5000,() -> { + if (dialog != null && dialog.isShowing()) { + dialog.dismiss(); + } + return null; + }); + mTimeOutJob.start(); + } + + public void setText(String text) { + mTip = text; + } + + public void setMax(int max) { + mProgressMax = max; + } + + public void setProgress(int progress) { + if (mDialog != null && mDialog.isShowing() && mProgressMax > 0) { + ((TextView) mDialog.findViewById(R.id.tv_tip)).setText(mTip + progress * 100 / mProgressMax + "%"); + } + } + + public void hideProgressDialog() { + if (mDialog != null) { + mDialog.hide(); + } + } + + /** + * 加好友或群驗證碼的對話框 + */ + public void showInputPwdDialog(String title, String okLabel, String cancelLabel, final String resultCode, final InputPwdDialogListener listener) { + + if (!checkActivityValid()) { + MLog.info(this, "showPicAddFriendGroupDialog ActivityInvalid...."); + return; + } + + if (mDialog.isShowing()) { + mDialog.hide(); + } + mDialog.show(); + + Window window = mDialog.getWindow(); + window.setContentView(R.layout.layout_pic_login_dialog); + TextView titleView = window.findViewById(R.id.pic_login_title); + final EditText input = window.findViewById(R.id.pic_login_input); + final TextView failMsg = window.findViewById(R.id.pic_login_fail_msg); + TextView confirm = window.findViewById(R.id.btn_confirm); + TextView mCancel = window.findViewById(R.id.btn_cancel); + mDialog.setCancelable(false); + mDialog.setCanceledOnTouchOutside(false); + + //只用下面這一行彈出對話框時需要點擊輸入框才能彈出軟鍵盤 + window.clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); + //加上下面這一行彈出對話框時軟鍵盤隨之彈出 + window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE); + if (!TextUtils.isEmpty(title)) + titleView.setText(title); + if (!TextUtils.isEmpty(cancelLabel)) + mCancel.setText(cancelLabel); + if (!TextUtils.isEmpty(okLabel)) + confirm.setText(okLabel); + + confirm.setOnClickListener(v -> { + if (!StringUtil.isEmpty(resultCode)) { + if (resultCode.equals(input.getText().toString())) { + if (listener != null) { + listener.onConfirm(); + mDialog.dismiss(); + } + } else { + failMsg.setVisibility(View.VISIBLE); + } + } else { + failMsg.setVisibility(View.VISIBLE); + } + }); + + mCancel.setOnClickListener(v -> { + if (listener != null) { + listener.onCancel(); + mDialog.dismiss(); + } + }); + } + + private String getTicketProtcol(long channelId, long subChannelId, String title) { + return "yy://pd-[sid=" + channelId + "&subid=" + subChannelId + "]\n" + title; + } + + private String getTicketProtcol(long channelId, long subChannelId) { + return "yy://pd-[sid=" + channelId + "&subid=" + subChannelId + "]"; + } + + public AlertDialog.Builder getBuilder() { + return mBuilder; + } + + public boolean isOpenSwitch() { + return switchTips != null && switchTips.isChecked(); + } + + public interface DynamicTokenLoginDialogListener { + public void onOK(String token); + + public void onCancle(); + } + + public interface InputPwdDialogListener { + public void onConfirm(); + + public void onCancel(); + } + + public interface OkCancelDialogListener { + + default void onCancel() { + //默認空實現 + } + + void onOk(); + } + + public interface OnClickListener { + public void onClick(View view, int btnIndex); + } + + public interface OnInputPasswordClickListener { + void onOk(String password); + + void onCancel(); + } + + public interface LambdaOkDialogListener extends OkCancelDialogListener { + default void onCancel() { + //do nothing + } + } + + public interface OnKeyBackListener { + void onBack(); + } + + public static abstract class AbsOkDialogListener implements OkCancelDialogListener { + public void onCancel() { + //do nothing + } + + public abstract void onOk(); + } + +} diff --git a/app/src/main/java/com/chwl/app/common/widget/dialog/DialogUiHelper.java b/app/src/main/java/com/chwl/app/common/widget/dialog/DialogUiHelper.java new file mode 100644 index 0000000..f2ced21 --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/widget/dialog/DialogUiHelper.java @@ -0,0 +1,80 @@ +package com.chwl.app.common.widget.dialog; + +import android.content.Context; + +import com.chwl.app.R; +import com.chwl.app.application.IReportConstants; +import com.chwl.app.application.ReportManager; +import com.chwl.app.radish.task.activity.TaskCenterActivity; +import com.chwl.app.ui.pay.ChargeActivity; +import com.chwl.app.ui.webview.CommonWebViewActivity; +import com.chwl.core.Constants; +import com.chwl.core.UriProvider; +import com.chwl.core.pay.PayModel; +import com.chwl.core.pay.bean.WalletInfo; +import com.chwl.core.utils.ActivityUtil; +import com.chwl.library.common.util.DeviceUtil; +import com.chwl.library.utils.AppMetaDataUtil; +import com.chwl.library.utils.ResUtil; + +import java.util.HashMap; + +/** + * 弹框帮助类,减少一些的代码的冗余 + * create by lvzebiao @2019/3/22 + */ +public class DialogUiHelper { + + public static String CHARGE_FROM = ""; + + /** + * 萝卜不足统一弹框处理 + */ + public static void showRadishNotEnoughDialog(Context context, DialogManager dialogManager) { + if (!ActivityUtil.isValidContext(context)) { + return; + } + if (dialogManager == null) { + dialogManager = new DialogManager(context); + } + String[] messages = new String[]{ResUtil.getString(R.string.widget_dialog_dialoguihelper_01), ResUtil.getString(R.string.widget_dialog_dialoguihelper_02)}; + dialogManager.showOkCancelWithTitleDialog(messages, ResUtil.getString(R.string.widget_dialog_dialoguihelper_03), true, () -> { + if (!ActivityUtil.isValidContext(context)) { + return; + } + TaskCenterActivity.start(context, TaskCenterActivity.FromPage.RADISH_NOT_ENOUGH_DIALOG); + }); + } + + public static void showNeedCharge(Context context, DialogManager dialogManager) { + if (!ActivityUtil.isValidContext(context)) { + return; + } + if (dialogManager == null) { + dialogManager = new DialogManager(context); + } + dialogManager.showOkCancelDialog(ResUtil.getString(R.string.widget_dialog_dialoguihelper_04), + true, () -> { + //充值 + WalletInfo goldWalletInfo = PayModel.get().getCurrentWalletInfo(); + HashMap map = new HashMap<>(5); + map.put(IReportConstants.PAYPAGE_TYPE, IReportConstants.TWO); + if (goldWalletInfo != null) { + map.put(IReportConstants.ACCOUNT_BALANCE, goldWalletInfo.getDiamondNum()); + } + map.put(IReportConstants.MODULE, IReportConstants.MOLISTAR_PAY); + ReportManager.get().reportEvent(IReportConstants.PAYPAGE_SHOW, map); +// if (AppMetaDataUtil.getChannelID().equals(Constants.GOOGLE)) { + ChargeActivity.start(context); +// } else { +// CommonWebViewActivity.start( +// context, UriProvider.getOfficialPay( +// 4, +// DeviceUtil.getDeviceId(context) +// ) +// ); +// } + }); + } + +} diff --git a/app/src/main/java/com/chwl/app/common/widget/dialog/ListViewMenuItem.java b/app/src/main/java/com/chwl/app/common/widget/dialog/ListViewMenuItem.java new file mode 100644 index 0000000..4587f63 --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/widget/dialog/ListViewMenuItem.java @@ -0,0 +1,31 @@ +package com.chwl.app.common.widget.dialog; + +/** + * Creator: Chanry + * Date:2016/7/20 + * Time: 17:31 + *

+ * Description: 列表长按出现的菜单 + */ +public class ListViewMenuItem { + + public String mTitle; + public OnClickListener mClickListener; + + public interface OnClickListener { + void onClick(); + } + + public void setTitle(String title) { + mTitle = title; + } + + public void setOnClickListener(OnClickListener listener) { + this.mClickListener = listener; + } + + public ListViewMenuItem(String mTitle, OnClickListener mClickListener) { + this.mTitle = mTitle; + this.mClickListener = mClickListener; + } +} diff --git a/app/src/main/java/com/chwl/app/common/widget/dialog/LoadingImageView.java b/app/src/main/java/com/chwl/app/common/widget/dialog/LoadingImageView.java new file mode 100644 index 0000000..4d81e92 --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/widget/dialog/LoadingImageView.java @@ -0,0 +1,57 @@ +package com.chwl.app.common.widget.dialog; + +import android.animation.ObjectAnimator; +import android.content.Context; +import android.util.AttributeSet; +import android.view.animation.LinearInterpolator; + +import androidx.appcompat.widget.AppCompatImageView; + +/** + * create by lvzebiao @2019/12/5 + */ +public class LoadingImageView extends AppCompatImageView { + + private ObjectAnimator loadingAnim; + + public LoadingImageView(Context context) { + this(context, null); + } + + public LoadingImageView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public LoadingImageView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + startAnim(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + stopAnim(); + } + + public void startAnim() { + stopAnim(); + loadingAnim = ObjectAnimator.ofFloat(this, "rotation", 0f, 360f); + loadingAnim.setDuration(1000); + loadingAnim.setRepeatCount(-1); + loadingAnim.setInterpolator(new LinearInterpolator()); + loadingAnim.start(); + } + + private void stopAnim() { + if (loadingAnim != null) { + loadingAnim.cancel(); + loadingAnim = null; + } + } + +} diff --git a/app/src/main/java/com/chwl/app/common/widget/dialog/TimeOutProgressDialog.java b/app/src/main/java/com/chwl/app/common/widget/dialog/TimeOutProgressDialog.java new file mode 100644 index 0000000..6039191 --- /dev/null +++ b/app/src/main/java/com/chwl/app/common/widget/dialog/TimeOutProgressDialog.java @@ -0,0 +1,89 @@ +package com.chwl.app.common.widget.dialog; + +import android.app.Activity; +import android.os.Handler; +import android.os.Looper; + +import com.chwl.app.R; +import com.chwl.library.utils.SingleToastUtil; + +/** + * Created by qinbo on 2014/7/2. + */ +public class TimeOutProgressDialog { + private Activity mContext; + private String msg; + + private long time; + + private DialogManager dialogManager; + /** + * + * @param context + * @param msg + * @param time 单位微妙 + */ + public TimeOutProgressDialog(Activity context, String msg, long time){ + this.mContext = context; + this.msg = msg; + this.time = time; + + dialogManager = new DialogManager(mContext); + } + + public TimeOutProgressDialog(Activity context){ + this.mContext = context; + dialogManager = new DialogManager(mContext); + } + + public void setTime(long time) { + this.time = time; + } + + + private Handler handler = new Handler(Looper.myLooper()); + + public void showProcessProgress() { + /*if (dialogManager == null && mContext != null) { + dialogManager = new DialogManager(mContext); + }else{ + MLog.error(this, "parent activity not instance of ActivitySupport."); + }*/ + if (dialogManager != null&&mContext != null) { + hideProcessProgress(); + dialogManager.showProgressDialog(mContext, msg, false, false, null); + handler.postDelayed(processProgressTimeoutTask, time); + } + } + + public void showProcessProgress(String tip, long seconds) { + if (dialogManager != null && mContext != null) { + hideProcessProgress(); + dialogManager.showProgressDialog(mContext, tip, false, false, null); + handler.postDelayed(processProgressTimeoutTask, seconds); + } + } + + public void hideProcessProgress() { + handler.removeCallbacks(processProgressTimeoutTask); + if (dialogManager != null) { + dialogManager.dismissDialog(); + } + } + + private Runnable processProgressTimeoutTask = new Runnable() { + @Override + public void run() { + //if (mContext != null) { + if (dialogManager != null) { + dialogManager.dismissDialog(); + } +// if (!NetworkUtils.isNetworkAvailable(mContext)) { +// Toast.makeText(mContext,R.string.str_network_not_capable, Toast.LENGTH_LONG).show(); +// } else { + SingleToastUtil.showToast(R.string.str_network_not_capable); + //} + //} + } + }; +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/constants/AnyType.java b/app/src/main/java/com/chwl/app/constants/AnyType.java new file mode 100644 index 0000000..b95b4f4 --- /dev/null +++ b/app/src/main/java/com/chwl/app/constants/AnyType.java @@ -0,0 +1,9 @@ +package com.chwl.app.constants; + +public class AnyType { + + public @interface ObtainWay { + int ACT = 2; + int Def = 1; + } +} diff --git a/app/src/main/java/com/chwl/app/constants/BundleKeys.java b/app/src/main/java/com/chwl/app/constants/BundleKeys.java new file mode 100644 index 0000000..2a348a1 --- /dev/null +++ b/app/src/main/java/com/chwl/app/constants/BundleKeys.java @@ -0,0 +1,24 @@ +package com.chwl.app.constants; + +/** + * @author jack + * @Description + * @Date 2018/4/16 + */ + +public class BundleKeys { + public final static String KEY_OBJ = "KEY_OBJ"; + + public final static String KEY_EXTRA_1 = "KEY_EXTRA_1"; + public final static String KEY_EXTRA_2 = "KEY_EXTRA_2"; + public final static String KEY_EXTRA_3 = "KEY_EXTRA_3"; + public final static String KEY_EXTRA_4 = "KEY_EXTRA_4"; + public final static String KEY_EXTRA_5 = "KEY_EXTRA_5"; + + public final static String NICK = "NICK"; + public final static String AVATAR = "AVATAR"; + public final static String ER_BAN_NO = "ER_BAN_NO"; + public final static String TARGET_ID = "TARGET_ID"; + + +} diff --git a/app/src/main/java/com/chwl/app/constants/UserInfoConstants.java b/app/src/main/java/com/chwl/app/constants/UserInfoConstants.java new file mode 100644 index 0000000..99eff9e --- /dev/null +++ b/app/src/main/java/com/chwl/app/constants/UserInfoConstants.java @@ -0,0 +1,10 @@ +package com.chwl.app.constants; + +public @interface UserInfoConstants { + + public @interface CpSet{ + //1-cp头像是否展示,2-cp动画 + int cpAvatar = 1; + int cpAnim = 2; + } +} diff --git a/app/src/main/java/com/chwl/app/decoration/adapter/CarShopAdapter.java b/app/src/main/java/com/chwl/app/decoration/adapter/CarShopAdapter.java new file mode 100644 index 0000000..73e8b06 --- /dev/null +++ b/app/src/main/java/com/chwl/app/decoration/adapter/CarShopAdapter.java @@ -0,0 +1,69 @@ +package com.chwl.app.decoration.adapter; + +import android.view.View; + +import com.chwl.app.R; +import com.chwl.app.bindadapter.BaseAdapter; +import com.chwl.app.bindadapter.BindingViewHolder; +import com.chwl.app.databinding.ItemCarShopBinding; +import com.chwl.core.decoration.car.bean.CarInfo; +import com.chwl.library.utils.ListUtils; + +/** + * Created by huangmeng1 on 2018/5/9. + */ +public class CarShopAdapter extends BaseAdapter { + private int selectPosition; + + public int getSelectPosition() { + return selectPosition; + } + + public void setSelectPosition(int selectPosition) { + this.selectPosition = selectPosition; + } + + public CarShopAdapter(int layoutResId, int brid) { + super(layoutResId, brid); + } + + @Override + protected void convert(BindingViewHolder helper, CarInfo item) { + super.convert(helper, item); + helper.addOnClickListener(R.id.tv_try_drive); + + ItemCarShopBinding binding = (ItemCarShopBinding) helper.getBinding(); + boolean isSelect = selectPosition == helper.getAdapterPosition(); + binding.llCarHolder.setSelected(isSelect); + binding.setSelectPosition(isSelect); + + if (item.getLabelType() == CarInfo.TAG_TYPE_NORMAL) { + binding.ivTag.setVisibility(View.GONE); + + } else if (CarInfo.TAG_TYPE_NEW == item.getLabelType()) { + binding.ivTag.setVisibility(View.VISIBLE); + binding.ivTag.setImageResource(R.drawable.ic_mark_new); + + } else if (CarInfo.TAG_TYPE_DISCOUNT == item.getLabelType()) { + binding.ivTag.setVisibility(View.VISIBLE); + binding.ivTag.setImageResource(R.drawable.ic_mark_discount); + + } else if (CarInfo.TAG_TYPE_LIMIT == item.getLabelType()) { + binding.ivTag.setVisibility(View.VISIBLE); + binding.ivTag.setImageResource(R.drawable.ic_mark_limit); + + } else if (CarInfo.TAG_TYPE_EXCLUSIVE == item.getLabelType()) { + binding.ivTag.setVisibility(View.VISIBLE); + binding.ivTag.setImageResource(R.drawable.ic_mark_exclusive); + } + } + + public void setCarInfoHasBeenBought(CarInfo carInfo) { + if (carInfo.getCarId() <= 0 || ListUtils.isListEmpty(mData)) return; + int index = mData.indexOf(carInfo); + if (index == -1) return; + mData.get(index).setStatus(CarInfo.STATUS_USER_CAN_USE); + mData.get(index).setRemainingDay(carInfo.getDays()); + notifyItemChanged(index); + } +} diff --git a/app/src/main/java/com/chwl/app/decoration/adapter/DecorationCommonAdapter.kt b/app/src/main/java/com/chwl/app/decoration/adapter/DecorationCommonAdapter.kt new file mode 100644 index 0000000..4cce2a8 --- /dev/null +++ b/app/src/main/java/com/chwl/app/decoration/adapter/DecorationCommonAdapter.kt @@ -0,0 +1,22 @@ +package com.chwl.app.decoration.adapter + +import android.widget.ImageView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.ui.utils.load +import com.chwl.core.decoration.bean.DecorationInfo + + +open class DecorationCommonAdapter(layoutResId: Int = R.layout.item_decoration_common) : + BaseQuickAdapter(layoutResId) { + + override fun convert(helper: BaseViewHolder, item: DecorationInfo) { + helper.getView(R.id.iv_pic).load(item.pic) + helper.setText(R.id.tv_name, "${item.name}(${item.dressDay})${helper.itemView.context.getString(R.string.day)}") + .setText(R.id.tv_price, item.dressPrice.toString()) + .setGone(R.id.tv_limit, item.dressLimitStatus == 0) + .addOnClickListener(R.id.tv_buy, R.id.tv_send) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/decoration/adapter/DressUpAdapter.kt b/app/src/main/java/com/chwl/app/decoration/adapter/DressUpAdapter.kt new file mode 100644 index 0000000..e2c85bc --- /dev/null +++ b/app/src/main/java/com/chwl/app/decoration/adapter/DressUpAdapter.kt @@ -0,0 +1,141 @@ +package com.chwl.app.decoration.adapter + +import android.view.Gravity +import android.view.ViewGroup +import com.chwl.app.R +import com.chwl.app.bindadapter.BaseBindingAdapter +import com.chwl.app.bindadapter.BaseBindingViewHolder +import com.chwl.app.constants.AnyType +import com.chwl.app.databinding.ItemDressUpLayoutBinding +import com.chwl.app.decoration.ui.activity.DressUpTabActivity +import com.chwl.app.decoration.util.DressUpUtil +import com.chwl.core.decoration.bean.DressUpInfo +import com.chwl.library.common.util.isVerify +import com.chwl.library.common.util.setViewWH +import com.chwl.library.common.util.setVis +import com.chwl.library.common.util.toColor +import com.example.lib_utils.ktx.dp +import com.example.lib_utils.ktx.getString + +class DressUpAdapter : BaseBindingAdapter() { + +// val myVipLevel = UserModel.get().cacheLoginUserInfo?.userVipInfoVO?.vipLevel?:-1 + + override fun convert( + helper: BaseBindingViewHolder, + item: DressUpInfo + ) { + val binding = helper.binding + setViewDef(binding) + + + if (item.isSelect) { + binding.bg.setBackgroundResource(R.drawable.ic_dress_item_s) + } else { + binding.bg.setBackgroundResource(R.drawable.ic_dress_item_n) + } + + binding.bg.setViewWH(height = if (item.isMy) 190 else 244) + + if (item.isNull) { + binding.empty.setVis(true) + binding.name.text = R.string.Not_used.getString() + binding.name.setVis(true) + return + } + + DressUpUtil.setItemPic(item,binding.picLayout) + binding.picLayout.setVis(true) + + + binding.name.text = item.name + binding.name.gravity = if (item.isMy) Gravity.CENTER else Gravity.START + binding.name.setVis(true) + + + DressUpUtil.setTextPrice(binding.price, item, true) + if (item.isMy) { + binding.price.setVis(false) + } else { + binding.price.setVis(item.obtainWay != AnyType.ObtainWay.ACT) + } + + + //1-普通 2-活动 + binding.discount.setViewWH(height = ViewGroup.LayoutParams.WRAP_CONTENT, isDP = false) + if (item.obtainWay == AnyType.ObtainWay.ACT) { + binding.discount.setViewWH(height = 48) + binding.name.setPadding(0,10.dp,0,10.dp) + binding.discount.text = R.string.obtainWayActionItem.getString() + } else { + binding.discount.setViewWH(height = 29) + binding.name.setPadding(0,5.dp,0,0) + if (item.vipLimit > 0) { + binding.discount.text = R.string.vipLimit.getString(item.vipLimit) + } else { + binding.discount.text = R.string.vipDiscount.getString(item.vipLevel,"${item.discount}%") + } + } + binding.discount.setVis(!item.isMy) + + + if (item.dressType != DressUpTabActivity.TAB_USER_CARD && item.effect.isVerify()) { + binding.btnPlay.setVis(true) + } else { + binding.btnPlay.setVis(false) + } + + + binding.limit.setVis(true) + if (item.isMy) { + if (item.isHasExpired) { + binding.limit.changeGradientColor( + "#C1CDDB".toColor(), + -1, + "#C1CDDB".toColor() + ) + binding.limit.text = R.string.Expired.getString() + } else { + binding.limit.changeGradientColor( + "#A1CAFD".toColor(), + -1, + "#A1CAFD".toColor() + ) + if (item.expireDays > 0) { + binding.limit.text = R.string.sDays.getString(item.expireDays) + } else { + binding.limit.text = R.string.unDay.getString() + } + } + } else { + binding.limit.changeGradientColor( + "#FFE3B2".toColor(), + -1, + "#E9A71D".toColor() + ) + if (item.dressLimitStatus != 0) { + binding.limit.setVis(false) + } else { + binding.limit.text = R.string.limit.getString() + } + } + + + + + helper.addOnClickListener(R.id.btnPlay) + + } + + private fun setViewDef(binding : ItemDressUpLayoutBinding) { +// binding.bg.setVis(false) +// binding.picBg.setVis(false) + binding.picLayout.setVis(false) +// binding.name.setVis(false) + binding.price.setVis(false) + binding.discount.setVis(false) + binding.empty.setVis(false) + binding.btnPlay.setVis(false) + binding.limit.setVis(false) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/decoration/adapter/MyCarAdapter.java b/app/src/main/java/com/chwl/app/decoration/adapter/MyCarAdapter.java new file mode 100644 index 0000000..ea06089 --- /dev/null +++ b/app/src/main/java/com/chwl/app/decoration/adapter/MyCarAdapter.java @@ -0,0 +1,146 @@ +package com.chwl.app.decoration.adapter; + +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import com.netease.nim.uikit.support.glide.GlideApp; +import com.chwl.app.R; +import com.chwl.app.bindadapter.BaseAdapter; +import com.chwl.app.bindadapter.BindingViewHolder; +import com.chwl.app.databinding.ItemCarGarageNormalBinding; +import com.chwl.core.decoration.car.bean.CarInfo; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; + +import org.jetbrains.annotations.NotNull; + +/** + * Created by yudi + * on 2018/3/2. + */ +public class MyCarAdapter extends BaseAdapter { + + public MyCarAdapter(int layoutResId, int brid) { + super(layoutResId, brid); + } + + @Override + protected void convert(@NotNull BindingViewHolder helper, CarInfo item) { + super.convert(helper, item); + + ItemCarGarageNormalBinding binding = (ItemCarGarageNormalBinding) helper.getBinding(); + + GlideApp.with(binding.ivCarCover) + .load(item.getPic()) + .dontAnimate() + .dontTransform() + .fitCenter() + .into(binding.ivCarCover); + + helper.addOnClickListener(R.id.tv_used); + + // 倒计时 + int remainingDay = item.getRemainingDay(); + int status = item.getStatus(); + boolean canUse; + + if (remainingDay >= 0 && status == CarInfo.STATUS_USER_CAN_USE) { + canUse = true; + } else { + canUse = false; + } + + // 时间 + if (remainingDay >= 0 && status == CarInfo.STATUS_USER_CAN_USE) { + String days; + if (item.getRemainingDay() > 99){ + days = "99+"; + }else { + days = item.getRemainingDay()+""; + } + binding.tvCounters.setText(String.format(binding.tvCounters.getResources().getString(R.string.decoration_status_wrapper), + binding.tvCounters.getResources().getString(R.string.decoration_remainder) + days + ResUtil.getString(R.string.decoration_adapter_mycaradapter_01))); + } else { + if (status == CarInfo.STATUS_OFF_SHELF || status == CarInfo.STATUS_OUT_OF_DATE) { + binding.tvCounters.setText(String.format(binding.tvCounters.getResources().getString(R.string.decoration_status_wrapper), + binding.tvCounters.getResources().getString(R.string.past_due))); + } + } + + + setUseButton(binding.tvUsed, canUse, item.isUsing()); + updateTag(item, binding.ivTag); + + } + + private void setUseButton(TextView tvUsed, boolean canUse, boolean isUsing) { + + if (!canUse) { + tvUsed.setVisibility(View.GONE); + tvUsed.setText(ResUtil.getString(R.string.decoration_adapter_mycaradapter_02)); + tvUsed.setBackgroundResource(R.drawable.base_shape_negative_30dp); + tvUsed.setEnabled(false); + tvUsed.setTextColor(mContext.getResources().getColor(R.color.base_color_negative_text)); + } else if (isUsing) { + tvUsed.setVisibility(View.VISIBLE); + tvUsed.setText(ResUtil.getString(R.string.decoration_adapter_mycaradapter_03)); + tvUsed.setBackgroundResource(R.drawable.base_shape_negative_30dp); + tvUsed.setEnabled(true); + tvUsed.setTextColor(mContext.getResources().getColor(R.color.base_color_negative_text)); + } else { + tvUsed.setVisibility(View.VISIBLE); + tvUsed.setText(ResUtil.getString(R.string.decoration_adapter_mycaradapter_04)); + tvUsed.setBackgroundResource(R.drawable.base_selector_theme_30dp); + tvUsed.setTextColor(mContext.getResources().getColor(R.color.base_selector_color_theme_btn)); + tvUsed.setEnabled(true); + } + + } + + private void updateTag(CarInfo carInfo, ImageView ivTag) { + if (CarInfo.TAG_TYPE_NORMAL == carInfo.getLabelType()) { + ivTag.setVisibility(View.GONE); + } else if (CarInfo.TAG_TYPE_NEW == carInfo.getLabelType()) { + ivTag.setVisibility(View.VISIBLE); + ivTag.setImageResource(R.drawable.ic_mark_new); + } else if (CarInfo.TAG_TYPE_DISCOUNT == carInfo.getLabelType()) { + ivTag.setVisibility(View.VISIBLE); + ivTag.setImageResource(R.drawable.ic_mark_discount); + } else if (CarInfo.TAG_TYPE_LIMIT == carInfo.getLabelType()) { + ivTag.setVisibility(View.VISIBLE); + ivTag.setImageResource(R.drawable.ic_mark_limit); + } else if (CarInfo.TAG_TYPE_EXCLUSIVE == carInfo.getLabelType()) { + ivTag.setVisibility(View.VISIBLE); + ivTag.setImageResource(R.drawable.ic_mark_exclusive); + } + } + + public void check(CarInfo selectedCarInfo) { + if (ListUtils.isListEmpty(mData)) return; + // 数据上改变那个using字段 + for (int i = 0; i < mData.size(); i++) { + CarInfo carInfo = mData.get(i); + if (selectedCarInfo.getCarId() == carInfo.getCarId()) { + carInfo.setUsing(1); + } else { + carInfo.setUsing(0); + } + } + notifyDataSetChanged(); + } + + public void setCarInfoHasBeenRenew(CarInfo carInfo) { + if (carInfo.getCarId() <= 0 || ListUtils.isListEmpty(mData)) return; + int index = mData.indexOf(carInfo); + if (index == -1) return; + if (mData.get(index).getRemainingDay() > 0) { + mData.get(index).setRemainingDay(mData.get(index).getRemainingDay() + carInfo.getDays()); + } else { + mData.get(index).setRemainingDay(carInfo.getDays()); + } + mData.get(index).setStatus(CarInfo.STATUS_USER_CAN_USE); + notifyItemChanged(index); + } + +} diff --git a/app/src/main/java/com/chwl/app/decoration/adapter/MyChatBubbleAdapter.java b/app/src/main/java/com/chwl/app/decoration/adapter/MyChatBubbleAdapter.java new file mode 100644 index 0000000..e5ff656 --- /dev/null +++ b/app/src/main/java/com/chwl/app/decoration/adapter/MyChatBubbleAdapter.java @@ -0,0 +1,80 @@ +package com.chwl.app.decoration.adapter; + +import android.view.View; + +import androidx.annotation.NonNull; + +import com.chwl.app.BR; +import com.chwl.app.R; +import com.chwl.app.bindadapter.BaseAdapter; +import com.chwl.app.bindadapter.BindingViewHolder; +import com.chwl.app.databinding.ItemMyChatBubbleBinding; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.decoration.headwear.bean.ChatBubbleInfo; +import com.chwl.core.decoration.headwear.bean.HeadWearInfo; +import com.chwl.library.utils.ResUtil; + +/** + * Created by huangmeng1 on 2018/5/11. + */ + +public class MyChatBubbleAdapter extends BaseAdapter { + + public MyChatBubbleAdapter() { + super(R.layout.item_my_chat_bubble, BR.headWearInfo); + } + + @Override + protected void convert(@NonNull BindingViewHolder helper, ChatBubbleInfo item) { + super.convert(helper, item); + ItemMyChatBubbleBinding binding = (ItemMyChatBubbleBinding) helper.getBinding(); + ImageLoadUtils.loadImage(mContext, item.getBubbleUrl(), binding.ivUserCardWear); + helper.addOnClickListener(R.id.tv_used); + + if (item.getLabelType() == HeadWearInfo.LABEL_TYPE_NORMAL) { + binding.ivTag.setVisibility(View.GONE); + + } else if (HeadWearInfo.LABEL_TYPE_NEW == item.getLabelType()) { + binding.ivTag.setVisibility(View.VISIBLE); + binding.ivTag.setImageResource(R.drawable.ic_mark_new); + + } else if (HeadWearInfo.LABEL_TYPE_DISCOUNT == item.getLabelType()) { + binding.ivTag.setVisibility(View.VISIBLE); + binding.ivTag.setImageResource(R.drawable.ic_mark_discount); + + } else if (HeadWearInfo.LABEL_TYPE_LIMIT == item.getLabelType()) { + binding.ivTag.setVisibility(View.VISIBLE); + binding.ivTag.setImageResource(R.drawable.ic_mark_limit); + + } else if (HeadWearInfo.LABEL_TYPE_EXCLUSIVE == item.getLabelType()) { + binding.ivTag.setVisibility(View.VISIBLE); + binding.ivTag.setImageResource(R.drawable.ic_mark_exclusive); + } + + // 过期状态不可使用 + if (item.isHasExpired()) { + binding.tvUsed.setVisibility(View.GONE); + binding.tvUsed.setEnabled(false); + binding.tvUsed.setText(ResUtil.getString(R.string.decoration_adapter_mychatbubbleadapter_01)); + } else { + binding.tvUsed.setVisibility(View.VISIBLE); + binding.tvUsed.setEnabled(true); + + } + + // 日期展示 + if (item.isHasExpired()) { // 过期 + binding.tvCounters.setText(mContext.getString(R.string.past_due)); + } else { + String days; + if (item.getExpireDays() > 99) { + days = "99+"; + } else { + days = item.getExpireDays() + ""; + } + binding.tvCounters.setText(mContext.getString(R.string.decoration_remainder) + days + mContext.getString(R.string.day)); + } + + } + +} diff --git a/app/src/main/java/com/chwl/app/decoration/adapter/MyHeadWearAdapter.java b/app/src/main/java/com/chwl/app/decoration/adapter/MyHeadWearAdapter.java new file mode 100644 index 0000000..5df7071 --- /dev/null +++ b/app/src/main/java/com/chwl/app/decoration/adapter/MyHeadWearAdapter.java @@ -0,0 +1,81 @@ +package com.chwl.app.decoration.adapter; + +import android.view.View; + +import com.chwl.app.R; +import com.chwl.app.bindadapter.BaseAdapter; +import com.chwl.app.bindadapter.BindingViewHolder; +import com.chwl.app.databinding.ItemMyHeadWearBinding; +import com.chwl.app.utils.AvatarHelper; +import com.chwl.core.decoration.headwear.bean.HeadWearInfo; +import com.chwl.core.noble.NobleUtil; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.widget.SVGAView; + +/** + * Created by huangmeng1 on 2018/5/11. + */ + +public class MyHeadWearAdapter extends BaseAdapter { + + public MyHeadWearAdapter(int layoutResId, int brid) { + super(layoutResId, brid); + } + + private SVGAView.SVGACache svgaCache = SVGAView.newCache(10); + + @Override + protected void convert(BindingViewHolder helper, HeadWearInfo item) { + super.convert(helper, item); + ItemMyHeadWearBinding binding = (ItemMyHeadWearBinding) helper.getBinding(); + binding.ivCarCover.bindCache(svgaCache); + AvatarHelper.loadAvatarFrame(binding.ivCarCover, item.getFirstUrl(), item.getType()); + helper.addOnClickListener(R.id.tv_used); + + if (item.getLabelType() == HeadWearInfo.LABEL_TYPE_NORMAL) { + binding.ivTag.setVisibility(View.GONE); + + } else if (HeadWearInfo.LABEL_TYPE_NEW == item.getLabelType()) { + binding.ivTag.setVisibility(View.VISIBLE); + binding.ivTag.setImageResource(R.drawable.ic_mark_new); + + } else if (HeadWearInfo.LABEL_TYPE_DISCOUNT == item.getLabelType()) { + binding.ivTag.setVisibility(View.VISIBLE); + binding.ivTag.setImageResource(R.drawable.ic_mark_discount); + + } else if (HeadWearInfo.LABEL_TYPE_LIMIT == item.getLabelType()) { + binding.ivTag.setVisibility(View.VISIBLE); + binding.ivTag.setImageResource(R.drawable.ic_mark_limit); + + } else if (HeadWearInfo.LABEL_TYPE_EXCLUSIVE == item.getLabelType()) { + binding.ivTag.setVisibility(View.VISIBLE); + binding.ivTag.setImageResource(R.drawable.ic_mark_exclusive); + } + + // 过期状态不可使用 + if (item.getStatus() == 2) { + binding.tvUsed.setVisibility(View.GONE); + binding.tvUsed.setEnabled(false); + binding.tvUsed.setText(ResUtil.getString(R.string.decoration_adapter_myheadwearadapter_01)); + } else { + binding.tvUsed.setVisibility(View.VISIBLE); + binding.tvUsed.setEnabled(true); + + } + + // 日期展示 + if (item.getStatus() == 2) { // 过期 + binding.tvCounters.setText(mContext.getString(R.string.past_due)); + } else { + String days; + if (item.getExpireDays() > 99){ + days = "99+"; + }else { + days = item.getExpireDays()+""; + } + binding.tvCounters.setText(mContext.getString(R.string.decoration_remainder) + days + mContext.getString(R.string.day)); + } + + } + +} diff --git a/app/src/main/java/com/chwl/app/decoration/adapter/MyNamePlateAdapter.java b/app/src/main/java/com/chwl/app/decoration/adapter/MyNamePlateAdapter.java new file mode 100644 index 0000000..c6ed227 --- /dev/null +++ b/app/src/main/java/com/chwl/app/decoration/adapter/MyNamePlateAdapter.java @@ -0,0 +1,63 @@ +package com.chwl.app.decoration.adapter; + +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.netease.nim.uikit.support.glide.GlideApp; +import com.chwl.app.R; +import com.chwl.core.decoration.nameplate.bean.NamePlateInfo; +import com.chwl.library.utils.ResUtil; + +/** + * Created by yudi + * on 2018/3/2. + */ +public class MyNamePlateAdapter extends BaseQuickAdapter { + + public MyNamePlateAdapter() { + super(R.layout.item_nameplate_normal); + + } + + @Override + protected void convert(BaseViewHolder helper, NamePlateInfo.NameplateListBean item) { + helper.addOnClickListener(R.id.tv_used); + //铭牌名称 + helper.setText(R.id.tv_nameplate_name, item.getNameplateName()); + //铭牌图标 + ImageView ivCover = helper.getView(R.id.iv_nameplate_cover); + GlideApp.with(mContext) + .load(item.getNameplateImage()) + .into(ivCover); + + + //使用按钮 + TextView tvUsed = helper.getView(R.id.tv_used); + tvUsed.setBackgroundResource(item.isUsing() ? R.drawable.base_shape_e6e6e6_30dp : R.drawable.base_selector_theme_30dp); + tvUsed.setTextColor(item.isUsing() ? mContext.getResources().getColor(R.color.color_FFFFFF) : + mContext.getResources().getColor(R.color.base_selector_color_theme_btn)); + tvUsed.setText(item.isUsing() ? R.string.label_used : R.string.label_can_use); + if (item.isIsExpired()) { // 过期 + // 日期展示 + helper.setText(R.id.tv_counters, mContext.getString(R.string.past_due)); + tvUsed.setVisibility(View.GONE); + tvUsed.setEnabled(false); + tvUsed.setBackgroundResource(R.drawable.base_shape_e6e6e6_30dp); + tvUsed.setText(ResUtil.getString(R.string.decoration_adapter_mynameplateadapter_01)); + tvUsed.setTextColor(mContext.getResources().getColor(R.color.color_FFFFFF)); + } else { + String days; + if (item.getExpireDays() > 99) { + days = "99+"; + } else { + days = item.getExpireDays() + ""; + } + helper.setText(R.id.tv_counters, mContext.getString(R.string.decoration_remainder) + days + mContext.getString(R.string.day)); + tvUsed.setVisibility(View.VISIBLE); + tvUsed.setEnabled(true); + } + } +} diff --git a/app/src/main/java/com/chwl/app/decoration/adapter/MyUserCardWearAdapter.java b/app/src/main/java/com/chwl/app/decoration/adapter/MyUserCardWearAdapter.java new file mode 100644 index 0000000..16bb7c0 --- /dev/null +++ b/app/src/main/java/com/chwl/app/decoration/adapter/MyUserCardWearAdapter.java @@ -0,0 +1,120 @@ +package com.chwl.app.decoration.adapter; + +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.bumptech.glide.load.DataSource; +import com.bumptech.glide.load.engine.GlideException; +import com.bumptech.glide.request.RequestListener; +import com.bumptech.glide.request.target.Target; +import com.chwl.app.R; +import com.chwl.app.bindadapter.BaseAdapter; +import com.chwl.app.bindadapter.BindingViewHolder; +import com.chwl.app.databinding.ItemMyUserCardWearBinding; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.decoration.headwear.bean.HeadWearInfo; +import com.chwl.core.decoration.headwear.bean.UserCardWearInfo; +import com.chwl.library.common.glide.GlideUtils; +import com.chwl.library.utils.ResUtil; + +import java.io.File; + +/** + * Created by huangmeng1 on 2018/5/11. + */ + +public class MyUserCardWearAdapter extends BaseAdapter { + + public MyUserCardWearAdapter(int layoutResId, int brid) { + super(layoutResId, brid); + } + + @Override + protected void convert(@NonNull BindingViewHolder helper, UserCardWearInfo item) { + super.convert(helper, item); + ItemMyUserCardWearBinding binding = (ItemMyUserCardWearBinding) helper.getBinding(); + binding.ivUserCardWearMp4.setLoop(Integer.MAX_VALUE); + + GlideUtils.instance().downloadFromUrl2(binding.ivUserCardWearMp4.getContext(), item.getPic(), new RequestListener() { + @Override + public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { + ImageLoadUtils.loadImage(mContext, item.getPic(), binding.ivUserCardWear); + return true; + } + + @Override + public boolean onResourceReady(File resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { + if (resource != null) { + binding.ivUserCardWearMp4.startPlay(resource); + } + return true; + } + }); + +// String filePath = PathHelper.INSTANCE.generateResourcesFilePath(item.getPic()); +// DownloadRequest request = DownloadRequest.Companion.build(item.getPic(), filePath, "gift_effect_download", null, 60000L); +// DownloadManager.INSTANCE.download(request, new FileDownloadListener() { +// @Override +// public void onDownloadCompleted(@NonNull DownloadTask task) { +// String path = task.getRequest().getPath(); +// binding.ivUserCardWearMp4.startPlay(new File(path)); +// } +// +// @Override +// public void onDownloadError(@NonNull DownloadException exception) { +// ImageLoadUtils.loadImage(mContext, item.getPic(), binding.ivUserCardWear); +// } +// }); + + + helper.addOnClickListener(R.id.tv_used); + + if (item.getLabelType() == HeadWearInfo.LABEL_TYPE_NORMAL) { + binding.ivTag.setVisibility(View.GONE); + + } else if (HeadWearInfo.LABEL_TYPE_NEW == item.getLabelType()) { + binding.ivTag.setVisibility(View.VISIBLE); + binding.ivTag.setImageResource(R.drawable.ic_mark_new); + + } else if (HeadWearInfo.LABEL_TYPE_DISCOUNT == item.getLabelType()) { + binding.ivTag.setVisibility(View.VISIBLE); + binding.ivTag.setImageResource(R.drawable.ic_mark_discount); + + } else if (HeadWearInfo.LABEL_TYPE_LIMIT == item.getLabelType()) { + binding.ivTag.setVisibility(View.VISIBLE); + binding.ivTag.setImageResource(R.drawable.ic_mark_limit); + + } else if (HeadWearInfo.LABEL_TYPE_EXCLUSIVE == item.getLabelType()) { + binding.ivTag.setVisibility(View.VISIBLE); + binding.ivTag.setImageResource(R.drawable.ic_mark_exclusive); + } + + // 过期状态不可使用 + if (item.isHasExpired()) { + binding.tvUsed.setVisibility(View.GONE); + binding.tvUsed.setEnabled(false); + binding.tvUsed.setText(ResUtil.getString(R.string.decoration_adapter_myusercardwearadapter_01)); + } else { + binding.tvUsed.setVisibility(View.VISIBLE); + binding.tvUsed.setEnabled(true); + + } + + // 日期展示 + if (item.isHasExpired()) { // 过期 + binding.tvCounters.setText(mContext.getString(R.string.past_due)); + } else { + String days; + if (item.getExpireDays() > 99) { + days = "99+"; + } else { + days = item.getExpireDays() + ""; + } + binding.tvCounters.setText(mContext.getString(R.string.decoration_remainder) + days + mContext.getString(R.string.day)); + } + + } + +} diff --git a/app/src/main/java/com/chwl/app/decoration/helper/DecorationDialogHelper.java b/app/src/main/java/com/chwl/app/decoration/helper/DecorationDialogHelper.java new file mode 100644 index 0000000..fbfedd6 --- /dev/null +++ b/app/src/main/java/com/chwl/app/decoration/helper/DecorationDialogHelper.java @@ -0,0 +1,363 @@ +package com.chwl.app.decoration.helper; + +import android.content.Context; +import android.view.View; +import android.widget.RadioButton; +import android.widget.RadioGroup; +import android.widget.TextView; + +import com.chwl.app.R; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.app.common.widget.dialog.DialogUiHelper; +import com.chwl.core.decoration.bean.BaseDecoration; +import com.chwl.core.decoration.bean.CurrencyType; +import com.chwl.core.decoration.car.CarModel; +import com.chwl.core.decoration.headwear.HeadwearModel; +import com.chwl.core.utils.ActivityUtil; +import com.chwl.core.utils.net.BalanceNotEnoughExeption; +import com.chwl.core.utils.net.RadishNotEnoughException; +import com.chwl.core.utils.net.RxHelper; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; + +import io.reactivex.functions.BiConsumer; +import lombok.Data; + +/** + * 装扮弹框统一处理 + * 赠送弹框,购买弹框 + * 4种情况 {@link DecorationSaleType} {@link Options} 引入 + * + * create by lvzebiao @2019/3/22 + */ +public class DecorationDialogHelper { + + private Context context; + + private RadioButton rbRadish; + + private Options options; + + private DialogManager dialogManager; + + public DecorationDialogHelper(Context context, DialogManager dialogManager, Options options) { + this.context = context; + this.options = options; + if (this.options == null) { + throw new IllegalArgumentException("option is null"); + } + this.dialogManager = dialogManager; + if (this.dialogManager == null) { + this.dialogManager = new DialogManager(context); + } + } + + /** + * 购买或者赠送弹框 + */ + public void showBuyOrDonateDialog() { + if (!ActivityUtil.isValidContext(context)) { + return; + } + if (dialogManager == null) { + dialogManager = new DialogManager(context); + } + View view = getBuyContentView(); + if (view == null) { + return; + } + dialogManager.showOkCancelCustomDialog(view, ResUtil.getString(R.string.decoration_helper_decorationdialoghelper_01), ResUtil.getString(R.string.decoration_helper_decorationdialoghelper_02), false, this::handleDialogOkClick); + } + + private View getBuyContentView() { + int type = options.getType(); + BaseDecoration decoration = options.getDecoration(); + String nick = options.getNick(); + View customViewGoldRadish = View.inflate(context, R.layout.custom_view_gold_radish, null); + TextView tvBuyTitle = customViewGoldRadish.findViewById(R.id.tv_buy_title); + TextView tvBuyContent = customViewGoldRadish.findViewById(R.id.tv_buy_content); + RadioGroup rgBuyUnit = customViewGoldRadish.findViewById(R.id.rg_buy_unit); + TextView tvSingleUnit = customViewGoldRadish.findViewById(R.id.tv_single_unit); + RadioButton rbGold = customViewGoldRadish.findViewById(R.id.rb_gold); + rbRadish = customViewGoldRadish.findViewById(R.id.rb_radish); + + String content = ""; + if (type == DecorationSaleType.BUY_HEAD_WEAR) { + int formatMsgId; + if (decoration.isRenew()) { + formatMsgId = R.string.renew_decoration_info_text; + } else { + formatMsgId = R.string.buy_decoration_info_text; + } + content = context.getResources().getString(formatMsgId, + decoration.getName(), String.valueOf(decoration.getDays())); + } else if (type == DecorationSaleType.BUY_CAR) { + int formatMsgId; + if (decoration.isRenew()) { + formatMsgId = R.string.renew_decoration_info_text; + } else { + formatMsgId = R.string.buy_decoration_info_text; + } + content = context.getResources().getString(formatMsgId, + decoration.getName(), String.valueOf(decoration.getDays())); + } else if (type == DecorationSaleType.SEND_HEAD_WEAR) { + content = context.getResources().getString(R.string.donate_decoration_info_text, + DecorationHelper.getSimpleNick(nick), + decoration.getName(), String.valueOf(decoration.getDays())); + } else if (type == DecorationSaleType.SEND_CAR) { + content = context.getResources().getString(R.string.donate_decoration_info_text, + DecorationHelper.getSimpleNick(nick), + decoration.getName(), String.valueOf(decoration.getDays())); + } + int titleRes; + if (type == DecorationSaleType.SEND_CAR || type == DecorationSaleType.SEND_HEAD_WEAR) { + titleRes = R.string.donate_tips_text; + } else { + titleRes = R.string.buy_tips_text; + + } + tvBuyTitle.setText(titleRes); + tvBuyContent.setText(content); + //显示价格 + //赠送的话只显示price + //购买的话需要区分price和renewPrice + int price; + int radishPrice; + if (type == DecorationSaleType.SEND_CAR || type == DecorationSaleType.SEND_HEAD_WEAR) { + price = decoration.getPrice(); + radishPrice = decoration.getRadishPrice(); + } else { + price = decoration.getRealPrice(); + radishPrice = decoration.getRealRadishPrice(); + } + if (decoration.isOnlyGoldSale()) { + rgBuyUnit.setVisibility(View.GONE); + tvSingleUnit.setVisibility(View.VISIBLE); + tvSingleUnit.setText(context.getResources().getString(R.string.how_much_gold, + price)); + } else if (decoration.isOnlyRadishSale()) { + rgBuyUnit.setVisibility(View.GONE); + tvSingleUnit.setVisibility(View.VISIBLE); + tvSingleUnit.setText(context.getResources().getString(R.string.how_much_radish, + radishPrice)); + } else if (decoration.isGoldAndRadishSale()) { + rgBuyUnit.setVisibility(View.VISIBLE); + tvSingleUnit.setVisibility(View.GONE); + rbGold.setText(context.getResources().getString(R.string.how_much_gold, + price)); + rbRadish.setText(context.getResources().getString(R.string.how_much_radish, + radishPrice)); + } else { + return null; + } + return customViewGoldRadish; + } + + /** + * 识别支付币类型 + */ + private int calcCurrencyType() { + int currencyType = CurrencyType.GOLD; + BaseDecoration decoration = options.getDecoration(); + if (decoration == null) { + return currencyType; + } + if (decoration.isGoldAndRadishSale()) { + if (rbRadish != null && rbRadish.isChecked()) { + currencyType = CurrencyType.RADISH; + } + } else if (decoration.isOnlyRadishSale()) { + currencyType = CurrencyType.RADISH; + } + return currencyType; + } + + @SuppressWarnings("ResultOfMethodCallIgnored") + private void handleDialogOkClick() { + switch (options.getType()) { + case DecorationSaleType.BUY_HEAD_WEAR: + dialogManager.showProgressDialog(context, "", true); + DialogUiHelper.CHARGE_FROM = ResUtil.getString(R.string.decoration_helper_decorationdialoghelper_03); + HeadwearModel.get().buyHeadWearV2(options.getDecoration().getDecorationId(), calcCurrencyType()) + .compose(RxHelper.bindContext(context)) + .map(s -> { + if (options.getDecoration().isRenew()) { + return ResUtil.getString(R.string.decoration_helper_decorationdialoghelper_04); + } + return ResUtil.getString(R.string.decoration_helper_decorationdialoghelper_05); + }) + .subscribe(new DecorationConsumer()); + + break; + + case DecorationSaleType.BUY_CAR: + DialogUiHelper.CHARGE_FROM = ResUtil.getString(R.string.decoration_helper_decorationdialoghelper_06); + dialogManager.showProgressDialog(context, "", true); + CarModel.get().buyThisCarV2(options.getDecoration().getDecorationId(), calcCurrencyType()) + .compose(RxHelper.bindContext(context)) + .map(s -> { + if (options.getDecoration().isRenew()) { + return ResUtil.getString(R.string.decoration_helper_decorationdialoghelper_07); + } + return ResUtil.getString(R.string.decoration_helper_decorationdialoghelper_08); + }) + .subscribe(new DecorationConsumer()); + break; + + case DecorationSaleType.SEND_CAR: + DialogUiHelper.CHARGE_FROM = ResUtil.getString(R.string.decoration_helper_decorationdialoghelper_09); + CarModel.get().sendCarV2( + String.valueOf(options.getTargetUid()), + String.valueOf(options.getDecoration().getDecorationId()), + calcCurrencyType()) + .compose(RxHelper.bindContext(context)) + .map(s -> ResUtil.getString(R.string.decoration_helper_decorationdialoghelper_010)) + .subscribe(new DecorationConsumer()); + break; + + case DecorationSaleType.SEND_HEAD_WEAR: + DialogUiHelper.CHARGE_FROM = ResUtil.getString(R.string.decoration_helper_decorationdialoghelper_011); + HeadwearModel.get().sendHeadWearV2( + calcCurrencyType(), + String.valueOf(options.getDecoration().getDecorationId()), + String.valueOf(options.getTargetUid())) + .compose(RxHelper.bindContext(context)) + .map(s -> ResUtil.getString(R.string.decoration_helper_decorationdialoghelper_012)) + .subscribe(new DecorationConsumer()); + break; + } + } + + public class DecorationConsumer implements BiConsumer { + + @Override + public void accept(String string, Throwable throwable) throws Exception { + if (!ActivityUtil.isValidContext(context)) { + return; + } + if (dialogManager.isDialogShowing()) { + dialogManager.dismissDialog(); + } + if (throwable == null) { + if (!options.isCustomSuccessCallback()) { + dialogManager.showBuyCarSucDialog(string); + } + if (listener != null) { + if (options.getType() == DecorationSaleType.BUY_HEAD_WEAR) { + listener.onBuyHeadwearSuccess(); + } else if (options.getType() == DecorationSaleType.BUY_CAR) { + listener.onBuyCarSuccess(); + } else if (options.getType() == DecorationSaleType.SEND_CAR) { + listener.onSendCarSuccess(); + } else if (options.getType() == DecorationSaleType.SEND_HEAD_WEAR) { + listener.onSendHeadwearSuccess(); + } + } + } else { + if (throwable instanceof BalanceNotEnoughExeption) { + DialogUiHelper.showNeedCharge(context, dialogManager); + } else if (throwable instanceof RadishNotEnoughException) { + DialogUiHelper.showRadishNotEnoughDialog(context, dialogManager); + } else { +// Toast.makeText(context, throwable.getMessage(), Toast.LENGTH_SHORT).show(); + SingleToastUtil.showToastShort(throwable.getMessage()); + } + } + } + } + + public void setOptions(Options options) { + this.options = options; + } + + @Data + public static class Options { + private BaseDecoration decoration; + /** + * 弹框类型 + * {@link DecorationSaleType} + */ + private int type; + + private String nick; + + private long targetUid; + /** + * ture的话,完全自定义购买成功回调 + */ + private boolean customSuccessCallback; + + public String getNick() { + if (nick == null) { + nick = ""; + } + return nick; + } + } + + public static class Builder { + + private Options options; + + public Builder() { + options = new Options(); + } + + public Builder setDecoration(BaseDecoration decoration) { + options.setDecoration(decoration); + return this; + } + + public Builder setType(int type) { + options.setType(type); + return this; + } + + public Builder setNick(String nick) { + options.setNick(nick); + return this; + } + + public Builder setTargetUid(long targetUid) { + options.setTargetUid(targetUid); + return this; + } + + public Builder setCustomSuccessCallback(boolean customSuccessCallback) { + options.setCustomSuccessCallback(customSuccessCallback); + return this; + } + + public Options create() { + return options; + } + + } + + private OnOpDecorationListener listener; + + public void setOnOpDecorationListener(OnOpDecorationListener listener) { + this.listener = listener; + } + + public static abstract class OnOpDecorationListener { + + public void onBuyHeadwearSuccess() { + + } + + public void onSendHeadwearSuccess() { + + } + + public void onBuyCarSuccess() { + + } + + public void onSendCarSuccess() { + + } + + } + +} diff --git a/app/src/main/java/com/chwl/app/decoration/helper/DecorationHelper.java b/app/src/main/java/com/chwl/app/decoration/helper/DecorationHelper.java new file mode 100644 index 0000000..2aabddf --- /dev/null +++ b/app/src/main/java/com/chwl/app/decoration/helper/DecorationHelper.java @@ -0,0 +1,76 @@ +package com.chwl.app.decoration.helper; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.text.TextUtils; + +import com.chwl.app.R; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.core.decoration.bean.DecorationInfo; +import com.chwl.core.decoration.DecorationInfoEvent; +import com.chwl.core.decoration.DecorationModel; +import com.chwl.core.utils.net.RxHelper; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; + +import org.greenrobot.eventbus.EventBus; + +/** + * create by lvzebiao @2019/3/21 + */ +public class DecorationHelper { + + /** + * 超过5位时省略显示 + * + * @param nick + * @return + */ + public static String getSimpleNick(String nick) { + if (TextUtils.isEmpty(nick)) { + return ""; + } + if (nick.length() <= 5) { + return nick; + } + try { + return nick.substring(0, 4) + "…"; + } catch (Exception ex) { + ex.printStackTrace(); + } + return ""; + } + + @SuppressLint("CheckResult") + public static void showBuyDialog(Context context, + DialogManager dialogManager, + String targetNick, + long targetUid) { + DecorationInfo decorationInfo = EventBus.getDefault().getStickyEvent(DecorationInfoEvent.class).getDecorationInfo(); + dialogManager.showOkCancelDialog( + ResUtil.getString(R.string.decoration_helper_decorationhelper_01), + context.getResources().getString( + R.string.donate_decoration_info_text, + decorationInfo.getName(), + targetNick, + String.valueOf(decorationInfo.getDressDay()) + + ), + ResUtil.getString(R.string.decoration_helper_decorationhelper_02), + ResUtil.getString(R.string.decoration_helper_decorationhelper_03), + true, + () -> { + dialogManager.showProgressDialog(context); + DecorationModel.INSTANCE.sendDecoration(decorationInfo.getDressType(), decorationInfo.getId(), targetUid) + .compose(RxHelper.bindContext(context)) + .subscribe(s -> { + dialogManager.dismissDialog(); + SingleToastUtil.showToast(ResUtil.getString(R.string.decoration_helper_decorationhelper_04)); + }, throwable -> { + dialogManager.dismissDialog(); + SingleToastUtil.showToast(throwable.getMessage()); + }); + }); + } + +} diff --git a/app/src/main/java/com/chwl/app/decoration/helper/DecorationSaleType.java b/app/src/main/java/com/chwl/app/decoration/helper/DecorationSaleType.java new file mode 100644 index 0000000..92d65cd --- /dev/null +++ b/app/src/main/java/com/chwl/app/decoration/helper/DecorationSaleType.java @@ -0,0 +1,14 @@ +package com.chwl.app.decoration.helper; + +/** + * 购买 赠送 头饰 座驾的区分 + * create by lvzebiao @2019/3/22 + */ +public interface DecorationSaleType { + + int BUY_HEAD_WEAR = 1;//购买头饰 + int BUY_CAR = 2; //购买座驾 + int SEND_HEAD_WEAR = 3; //赠送头饰 + int SEND_CAR = 4; //赠送座驾 + +} diff --git a/app/src/main/java/com/chwl/app/decoration/ui/DressUpDialog.kt b/app/src/main/java/com/chwl/app/decoration/ui/DressUpDialog.kt new file mode 100644 index 0000000..1ece475 --- /dev/null +++ b/app/src/main/java/com/chwl/app/decoration/ui/DressUpDialog.kt @@ -0,0 +1,182 @@ +package com.chwl.app.decoration.ui + +import android.view.Gravity +import com.chwl.app.R +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.constants.AnyType.ObtainWay +import com.chwl.app.databinding.DialogDressUpBinding +import com.chwl.app.decoration.util.DressUpUtil +import com.chwl.core.bean.response.ServiceResult +import com.chwl.core.decoration.bean.DressUpInfo +import com.chwl.core.user.UserModel +import com.chwl.core.utils.net.RxHelper +import com.chwl.library.common.util.ClickUtils.click +import com.chwl.library.common.util.doToast +import com.chwl.library.common.util.setVis +import com.chwl.library.common.util.toColor +import com.chwl.library.net.rxnet.RxNet +import com.example.lib_utils.ktx.dp +import com.example.lib_utils.ktx.getString +import com.hjq.toast.ToastUtils +import io.reactivex.Single +import retrofit2.http.Field +import retrofit2.http.FormUrlEncoded +import retrofit2.http.POST + +class DressUpDialog : BaseDialogFragment() { + + override var width = 284.dp + override var height = 353.dp + override var dimAmount = 0.3f + override var gravity = Gravity.CENTER + + var isMy = false + var mDressUpInfo : DressUpInfo? = null + var mTargetUid = -1L + + override fun init() { + val cacheLoginUserInfo = UserModel.get().cacheLoginUserInfo + val myVipLevel = cacheLoginUserInfo?.userVipInfoVO?.vipLevel?: 0 + var canBuy = true + + mDressUpInfo?.let { + binding.name.text = it.name + if (it.vipLimit == 0 && it.obtainWay != ObtainWay.ACT){ + //没有等级限定,且装扮不是活动获得 + DressUpUtil.setTextPrice(binding.price,it,false,true) + }else{ + if (it.obtainWay == ObtainWay.ACT) { + //装扮是活动获得 + binding.price.setTextColor("#CCD9E7F7".toColor()) + binding.price.setVis(true) + binding.price.text = R.string.obtainWayAction.getString() + canBuy = false + }else if (it.vipLimit != 0) { + if (myVipLevel >= it.vipLimit) { + DressUpUtil.setTextPrice(binding.price,it,false,true) + } else { + //装扮vip等级限制没达到 + binding.price.setTextColor("#CCD9E7F7".toColor()) + binding.price.setVis(true) + binding.price.text = R.string.vipLimit.getString(it.vipLimit) + canBuy =false + } + } + } + + DressUpUtil.setDialogPic(it,binding.picLayout) + + } + + if (canBuy) { + binding.btnBuy.setVis(true) + if (mTargetUid != -1L) { + binding.btnBuy.text = R.string.fairy_give.getString() + binding.btnBuy.setGradientDrawable( + "#b2fcff".toColor(), + -1, + "#4da2ea".toColor(), + -1,-1f + ) + } else { + binding.btnBuy.text = R.string.buy.getString() + binding.btnBuy.setGradientDrawable( + "#FFE3b2".toColor(), + -1, + "#e9a71d".toColor(), + -1,-1f + ) + } + } else { + binding.btnCancel.text = R.string.ok.getString() + binding.btnBuy.setVis(false) + } + + + + binding.btnBuy.click { + mDressUpInfo?.let { + if (mTargetUid != -1L) { + postShopGive(it.dressType,it.dressId,mTargetUid) + .compose(bindToLifecycle()) + .doOnSuccess{ + ToastUtils.show(R.string.doSuccess) + dismiss() + } + .doOnError { + it?.message?.doToast() + } + .subscribe() + } else { + postShopBuy(it.dressType,it.dressId) + .compose(bindToLifecycle()) + .doOnSuccess{ + ToastUtils.show(R.string.doSuccess) + mActionCallBack?.onAction(0,true) + dismiss() + } + .doOnError { + it?.message?.doToast() + } + .subscribe() + } + } + + } + binding.btnCancel.click { + dismiss() + } + + + + } + + + private fun postShopBuy(dressType: Int,id: Int): Single { + return api.postShopBuy(dressType,id) + .compose(RxHelper.handleStringData()) + .compose(RxHelper.handleSchedulers()) + } + + + private fun postShopGive(dressType: Int,id: Int,targetUid:Long): Single { + return api.postShopGive(dressType,id,targetUid) + .compose(RxHelper.handleStringData()) + .compose(RxHelper.handleSchedulers()) + } + + private val api: Api = RxNet.create(Api::class.java); + interface Api { + + /** + * 购买装扮 + * + * @return + */ + @FormUrlEncoded + @POST("/dress/shop/buy") + fun postShopBuy( + @Field("dressType") dressType: Int, + @Field("id") id: Int + ): Single> + + + + /** + * 赠送装扮 + * + * @return + */ + @FormUrlEncoded + @POST("/dress/shop/give") + fun postShopGive( + @Field("dressType") dressType: Int, + @Field("id") id: Int, + @Field("targetUid") targetUid: Long, + ): Single> + + + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/decoration/ui/activity/DressUpTabActivity.kt b/app/src/main/java/com/chwl/app/decoration/ui/activity/DressUpTabActivity.kt new file mode 100644 index 0000000..b3a71ef --- /dev/null +++ b/app/src/main/java/com/chwl/app/decoration/ui/activity/DressUpTabActivity.kt @@ -0,0 +1,246 @@ +package com.chwl.app.decoration.ui.activity + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import androidx.fragment.app.Fragment +import androidx.viewpager2.widget.ViewPager2 +import com.alibaba.fastjson2.JSON +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.constants.AnyType.ObtainWay +import com.chwl.app.databinding.ActivityDressUpTabBinding +import com.chwl.app.databinding.TabDressUpLayoutBinding +import com.chwl.app.decoration.ui.DressUpDialog +import com.chwl.app.decoration.ui.fragment.DressUpMyFragment +import com.chwl.app.decoration.ui.fragment.DressUpStoreFragment +import com.chwl.app.decoration.util.DressUpUtil +import com.chwl.app.event.DressUpEvent +import com.chwl.app.ui.search.SearchUserActivity +import com.chwl.app.ui.utils.loadAvatar +import com.chwl.app.utils.AvatarHelper.loadAvatarFrame +import com.chwl.core.auth.AuthModel +import com.chwl.core.decoration.bean.DressUpInfo +import com.chwl.core.home.bean.TabInfo +import com.chwl.core.user.UserModel +import com.chwl.library.common.util.ClickUtils.click +import com.chwl.library.common.util.setVis +import com.chwl.library.utils.ResUtil +import com.chwl.library.widget.tab.SmartTabLayout2 +import com.chwl.library.widget.tab.TabTitleProvider +import com.chwl.library.widget.tab.util.FragmentPageAdapter +import com.example.lib_utils.ktx.getString +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode + +class DressUpTabActivity : BaseViewBindingActivity() { + + private var mDressUpInfo : DressUpInfo ? = null + + private val mMyVipLevel = UserModel.get().cacheLoginUserInfo?.userVipInfoVO?.vipLevel?: -1 + + companion object{ + const val TAB_HEAD_WEAR = 0 + const val TAB_CAR = 1 + const val TAB_NAMEPLATE = 2 + const val TAB_USER_CARD = 3 + const val TAB_CHAT_BUBBLE = 4 + const val TAB_USER_INFO_BG = 5 + + fun start(context: Context,isMy:Boolean) { + val intent = Intent(context, DressUpTabActivity::class.java) + intent.putExtra("isMy",isMy) + context.startActivity(intent) + } + } + + private val isMy : Boolean by lazy { intent.getBooleanExtra("isMy",false) } + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + EventBus.getDefault().register(this) + } + + override fun transparencyBar() = true + + override fun init() { + + if (isMy) { + binding.infoLayout.setVis(true) + binding.btnMyDressUp.setVis(false) + binding.avatar.loadAvatar(UserModel.get().cacheLoginUserInfo?.avatar) + initDarkTitleBar(R.string.decoration_view_mydecorationactivity_01.getString()) + } else { + binding.infoLayout.setVis(false) + binding.btnMyDressUp.setVis(true) + initDarkTitleBar(R.string.decoration_view_decorationstoreactivity_01.getString()) + } + + initTab() + initListener() + + if (isMy) { + UserModel.get().getUserInfo(AuthModel.get().currentUid) + .compose(bindToLifecycle()) + .doOnSuccess { + it?.userHeadwear?.let { head-> + loadAvatarFrame( + binding.avatarHead, + head.getFirstUrl(), + head.type + ) + } + }.subscribe() + } + + } + + val fgLists = arrayListOf() + val tabList = arrayListOf() + private fun initTab() { + + tabList.clear() + tabList.add(TabInfo(TAB_CAR, ResUtil.getString(R.string.decoration_view_decorationstoreactivity_04),R.drawable.ic_dress_tab_car)) + tabList.add(TabInfo(TAB_HEAD_WEAR, ResUtil.getString(R.string.decoration_view_decorationstoreactivity_03),R.drawable.ic_dress_tab_head)) + tabList.add(TabInfo(TAB_NAMEPLATE, ResUtil.getString(R.string.decoration_view_decorationstoreactivity_05),R.drawable.ic_dress_tab_nameplate)) + tabList.add(TabInfo(TAB_USER_CARD, ResUtil.getString(R.string.decoration_view_decorationstoreactivity_06),R.drawable.ic_dress_tab_card)) + tabList.add(TabInfo(TAB_CHAT_BUBBLE, ResUtil.getString(R.string.decoration_view_decorationstoreactivity_07),R.drawable.ic_dress_tab_chat)) + tabList.add(TabInfo(TAB_USER_INFO_BG, ResUtil.getString(R.string.userInfoBg),R.drawable.ic_dress_tab_homepage)) + + fgLists.clear() + tabList.forEach { + if (isMy) { + fgLists.add(DressUpMyFragment.newInstance(it.id)) + } else { + fgLists.add(DressUpStoreFragment.newInstance(it.id)) + } + } + + binding.tabLayout.setCustomTabView(SmartTabLayout2.TabProvider { container, position, pageTitle -> + val tabView = TabDressUpLayoutBinding.inflate(this@DressUpTabActivity.layoutInflater,container,false) + tabView.tabText.text = tabList.get(position).name + tabView.tabImg.setImageResource(tabList.get(position).res) +// tabView.root.layoutParams = LinearLayout.LayoutParams( +// LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT +// ) + return@TabProvider tabView.root + }) + + val pageAdapter = FragmentPageAdapter(this,fgLists) + binding.tabLayout.setViewPager(binding.viewPage,pageAdapter,object : TabTitleProvider { + override fun getPageTitle(position: Int): CharSequence? { + return tabList.get(position).name + } + }) + + binding.viewPage.offscreenPageLimit = 6 + binding.viewPage.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { + override fun onPageSelected(position: Int) { + mDressUpInfo = null + selectTab(position) + + if (isMy) { + binding.bottomView.setVis(false) + } else { +// binding.bottomView.visibility = View.INVISIBLE + } + } + }) + + binding.bottomView.setVis(!isMy) + + + } + + private fun initListener() { + binding.btnBuy.click { + mDressUpInfo?.let { + val dressUpDialog = DressUpDialog() + dressUpDialog.mDressUpInfo = it + dressUpDialog.isMy = isMy + dressUpDialog.show(context) + } + + } + + binding.btnGive.click { + mDressUpInfo?.let { + SearchUserActivity.start(context,JSON.toJSONString(it)) + } + } + + binding.btnMyDressUp.click { + DressUpTabActivity.start(context,true) + } + + binding.playLayout.click { + binding.playLayout.setVis(false) + binding.playLayout.removeAllViews() + } + } + + + + + private fun selectTab(pos: Int) { + for (i in 0 until tabList.size) { + val tabAt = binding.tabLayout.getTabAt(i) + val tabView = TabDressUpLayoutBinding.bind(tabAt) + tabView.tabBg.setBackgroundResource(if (pos == i) R.drawable.ic_dress_tab_bg_s else R.drawable.ic_dress_tab_bg_n) + tabView.tabText.alpha = if (pos == i) 1f else 0.5f + } + + if (!isMy) { + val fg = fgLists?.getOrNull(pos) + if (fg != null && fg is DressUpStoreFragment) { + fg.selectOne() + } + } + + + } + + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onDressUpEvent(event: DressUpEvent) { + val data = event.data + when (event.action) { + DressUpEvent.Action.Select -> { + + mDressUpInfo = data + if (isMy) { + if (data.dressType == TAB_HEAD_WEAR) { + binding.avatarHead.loadUrl(data.effect) + } + } else { +// if (data.obtainWay == ObtainWay.ACT) { +// binding.bottomView.setVis(false) +// }else if (data.vipLimit > 0 && mMyVipLevel < data.vipLimit) { +// binding.bottomView.setVis(false) +// }else { +// binding.bottomView.setVis(true) +// DressUpUtil.setTextPrice(binding.price,data) +// } + if (data.obtainWay == ObtainWay.ACT) { + binding.bottomView.setVis(false) + }else { + binding.bottomView.setVis(true) + DressUpUtil.setTextPrice(binding.price,data,false,false) + } + + } + } + + DressUpEvent.Action.Play -> { + DressUpUtil.play(data,binding.playLayout) + } + + else -> {} + } + } + + override fun onDestroy() { + super.onDestroy() + EventBus.getDefault().unregister(this) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/decoration/ui/fragment/DressUpMyFragment.kt b/app/src/main/java/com/chwl/app/decoration/ui/fragment/DressUpMyFragment.kt new file mode 100644 index 0000000..bf29ed1 --- /dev/null +++ b/app/src/main/java/com/chwl/app/decoration/ui/fragment/DressUpMyFragment.kt @@ -0,0 +1,576 @@ +package com.chwl.app.decoration.ui.fragment + +import android.os.Bundle +import android.view.View +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.chwl.app.R +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.base.BaseListFragment +import com.chwl.app.bindadapter.BaseBindingAdapter +import com.chwl.app.common.EmptyViewHelper +import com.chwl.app.decoration.adapter.DressUpAdapter +import com.chwl.app.decoration.ui.DressUpDialog +import com.chwl.app.decoration.ui.activity.DressUpTabActivity +import com.chwl.app.decoration.util.DressUpUtil +import com.chwl.app.event.DressUpEvent +import com.chwl.core.auth.AuthModel +import com.chwl.core.bean.response.ServiceResult +import com.chwl.core.decoration.bean.DressUpInfo +import com.chwl.core.decoration.bean.ShopMine +import com.chwl.core.decoration.car.bean.CarInfo +import com.chwl.core.decoration.headwear.bean.ChatBubbleInfo +import com.chwl.core.decoration.headwear.bean.UserCardWearInfo +import com.chwl.core.decoration.nameplate.bean.NamePlateInfo +import com.chwl.core.user.UserModel +import com.chwl.core.utils.net.RxHelper +import com.chwl.library.common.util.doToast +import com.chwl.library.common.util.isVerify +import com.chwl.library.common.util.setMargin +import com.chwl.library.net.rxnet.RxNet +import com.example.lib_utils.ktx.getString +import io.reactivex.Single +import org.greenrobot.eventbus.EventBus +import retrofit2.http.Field +import retrofit2.http.FormUrlEncoded +import retrofit2.http.GET +import retrofit2.http.POST +import retrofit2.http.Query + +class DressUpMyFragment : BaseListFragment() { + + companion object { + fun newInstance(dressType: Int): DressUpMyFragment { + val args = Bundle() + args.putInt("dressType", dressType) + val fragment = DressUpMyFragment() + fragment.arguments = args + return fragment + } + } + + private val mDressType: Int by lazy { requireArguments().getInt("dressType") } + private var mPosition = -1 + + + override fun initView() { + + mAdapter.setEmptyView( + EmptyViewHelper.createEmptyTextViewHeight( + context, + R.string.empty_data.getString() + ) + ) + binding.rvList.setMargin(start = 10, end = 10) + + mPosition = -1 + mAdapter.setNewData(arrayListOf()) + } + + override fun onResume() { + super.onResume() + if (!mAdapter.data.isVerify()){ + mPosition = -1 + onRefresh() + } + } + + override fun getAdapter(): BaseBindingAdapter<*, DressUpInfo> { + return DressUpAdapter() + } + + override fun getLayoutManager(): RecyclerView.LayoutManager { + return GridLayoutManager(context, 2, RecyclerView.VERTICAL, false) + } + + + override fun onLoad() { + loadDataByType(false) + } + + + + override fun onRefresh() { + loadDataByType(true) + } + + private fun loadDataByType(isRefresh: Boolean) { + + if (isRefresh){ + mPage = 1 + } + + when (mDressType) { + + DressUpTabActivity.TAB_CHAT_BUBBLE -> { + getChatBubbleInfoList() + .compose(bindToLifecycle()) + .doOnSuccess { + it?.let { + val newData = mutableListOf() + if (it.isVerify()) { + it.forEach { + newData.add(DressUpUtil.tranData(it)) + } + } + setData(newData) + } + }.doOnError { + stopAnim() + it?.message?.doToast() + }.subscribe() + } + + DressUpTabActivity.TAB_USER_CARD -> { + getMyUserCardWearList() + .compose(bindToLifecycle()) + .doOnSuccess { + it?.let { + val newData = mutableListOf() + if (it.isVerify()) { + it.forEach { + newData.add(DressUpUtil.tranData(it)) + } + } + setData(newData) + } + }.doOnError { + stopAnim() + it?.message?.doToast() + }.subscribe() + } + + DressUpTabActivity.TAB_NAMEPLATE -> { + getNamePlateList() + .compose(bindToLifecycle()) + .doOnSuccess { + it?.let { + val newData = mutableListOf() + if (it.nameplateList.isVerify()) { + it.nameplateList.forEach { + newData.add(DressUpUtil.tranData(it)) + } + } + setData(newData) + } + }.doOnError { + stopAnim() + it?.message?.doToast() + }.subscribe() + } + + DressUpTabActivity.TAB_HEAD_WEAR , DressUpTabActivity.TAB_USER_INFO_BG -> { + getShopMine() + .compose(bindToLifecycle()) + .doOnSuccess { + it?.let { + val newData = mutableListOf() + if (it.isVerify()) { + it.forEach { + newData.add(DressUpUtil.tranData(it)) + } + } + setData(newData) + } + }.doOnError { + stopAnim() + it?.message?.doToast() + }.subscribe() + } + + DressUpTabActivity.TAB_CAR -> { + getUserCarsV2() + .compose(bindToLifecycle()) + .doOnSuccess { + it?.let { + val newData = mutableListOf() + if (it.isVerify()) { + it.forEach { + newData.add(DressUpUtil.tranData(it)) + } + } + setData(newData) + } + }.doOnError { + stopAnim() + it?.message?.doToast() + }.subscribe() + } + + else -> {} + } + + } + + private fun userByType(data: DressUpInfo, adapter: BaseBindingAdapter<*, DressUpInfo>?, position: Int) { +// when (mDressType) { +// +// DressUpTabActivity.TAB_CHAT_BUBBLE -> { +// userChatBubble(data.id) +// .compose(bindToLifecycle()) +// .doOnSuccess { +// //更新用户信息 +// UserModel.get().updateCurrentUserInfo().subscribe() +// setSelect(adapter, position) +// } +// .doOnError { +// it?.message?.doToast() +// }.subscribe() +// } +// +// DressUpTabActivity.TAB_USER_CARD -> { +// userMyUserCardWear(data.id) +// .compose(bindToLifecycle()) +// .doOnSuccess { +// //更新用户信息 +// UserModel.get().updateCurrentUserInfo().subscribe() +// setSelect(adapter, position) +// } +// .doOnError { +// it?.message?.doToast() +// }.subscribe() +// } +// +// DressUpTabActivity.TAB_NAMEPLATE -> { +// useMyNamePlate(data.id,data.word) +// .compose(bindToLifecycle()) +// .doOnSuccess { +// if (AvRoomDataManager.get().mCurrentRoomInfo != null) { +// // 更新房间信息 +// IMNetEaseManager.get().updateMyRoomRole() +// } +// //更新用户信息 +// UserModel.get().updateCurrentUserInfo().subscribe() +// setSelect(adapter, position) +// } +// .doOnError { +// it?.message?.doToast() +// }.subscribe() +// } +// +// DressUpTabActivity.TAB_HEAD_WEAR , DressUpTabActivity.TAB_USER_INFO_BG-> { +// postOptDress(data.dressType, data.id) +// .compose(bindToLifecycle()) +// .doOnSuccess { +// //更新用户信息 +// UserModel.get().updateCurrentUserInfo().subscribe() +// setSelect(adapter, position) +// } +// .doOnError { +// it?.message?.doToast() +// }.subscribe() +// } +// +// DressUpTabActivity.TAB_CAR -> { +// driveThisCar(data.id) +// .compose(bindToLifecycle()) +// .doOnSuccess { +// //更换座驾状态,需要更新缓存 +// UserModel.get().onlyUpdateLoginUserInfoCache() +// setSelect(adapter, position) +// } +// .doOnError { +// it?.message?.doToast() +// }.subscribe() +// } +// +// else -> {} +// } + + postOptDress(data.dressType, data.id) + .compose(bindToLifecycle()) + .doOnSuccess { + //更新用户信息 + UserModel.get().updateCurrentUserInfo().subscribe() + setSelect(adapter, position) + } + .doOnError { + it?.message?.doToast() + }.subscribe() + } + + private fun setData(newData:MutableList) { + if (mPage == 1) { + //遍历找出是否有选中 + val find = newData.find { it.isSelect() } + //添加首个item , 不使用装扮的item + newData.add(0,DressUpUtil.getEmpty(mDressType,find == null)) + + if (find != null) { + //有选中的装扮移动到前面 + newData.remove(find) + newData.add(1,find) + mPosition = 1 + } else { + mPosition = 0 + } + + mAdapter.setNewData(newData) + } else { + mAdapter.addData(newData) + } + + + if (mDressType == DressUpTabActivity.TAB_CAR) { + binding.srlLayout.setEnableLoadMore(false) + } else { + if (newData.size >= mPageSize) { + mPage++ + binding.srlLayout.setEnableLoadMore(true) + } else { + binding.srlLayout.setEnableLoadMore(false) + } + } + + stopAnim() + } + + private fun setSelect(adapter: BaseBindingAdapter<*, DressUpInfo>?, position: Int) { +// if (mPosition != -1) { +// adapter?.data?.getOrNull(mPosition)?.isSelect = false +// adapter?.notifyItemChanged(mPosition) +// } +// +// mPosition = position +// adapter?.data?.getOrNull(mPosition)?.isSelect = true +// adapter?.notifyItemChanged(mPosition) + + + val data = adapter?.data?.toMutableList() + if (data.isVerify()) { + var oldItem :DressUpInfo?=null + var newItem :DressUpInfo?=null + + //取出 旧选中, 有就取消选中 + if (mPosition != -1) { + if (mPosition.isVerify(data)) { + oldItem = data?.getOrNull(mPosition) + oldItem?.isSelect = false + } + } + + //取出 新选中, 有就设置选中 + if (position.isVerify(data)) { + newItem = data?.getOrNull(position) + newItem?.isSelect = true + } + + //移动旧选中位置 , 0 表示没使用装扮, 就不需要移动 + if (oldItem != null) { + if (mPosition != 0) { + data?.remove(oldItem) + data?.add(1,oldItem) + } + } + //移动新选中位置 , 0 表示没使用装扮, 就不需要移动 + if (newItem != null) { + if (position != 0) { + data?.remove(newItem) + data?.add(1,newItem) + } + } + + //新选中位置被移动到 index : 1 , 0 时等于0 + if (position == 0) { + mPosition = 0 + } else { + mPosition = 1 + } + + adapter?.setNewData(data) + + R.string.doSuccess.doToast() + } + + } + + override fun onItemChildClicks( + adapter: BaseBindingAdapter<*, DressUpInfo>?, + view: View?, + position: Int + ) { + view?.id?.let { + when (it) { + R.id.btnPlay -> { + adapter?.data?.getOrNull(position)?.let { data -> + EventBus.getDefault().post(DressUpEvent(DressUpEvent.Action.Play, data)) + } + } + else -> {} + } + } + } + + override fun onItemClicks( + adapter: BaseBindingAdapter<*, DressUpInfo>?, + view: View?, + position: Int + ) { + adapter?.data?.getOrNull(position)?.let { data -> + if (data.dressId != 0) { + EventBus.getDefault().post(DressUpEvent(DressUpEvent.Action.Select, data)) + } + + if (data.isHasExpired) { + if (data.dressId != 0) { + //弹出购买弹窗 + val dressUpDialog = DressUpDialog() + dressUpDialog.mDressUpInfo = data + dressUpDialog.isMy = true + dressUpDialog.mActionCallBack = object : BaseDialogFragment.Action { + override fun onAction(type: Int, data: Any?) { + onRefresh() + } + } + dressUpDialog.show(context) + } + } else { + if (!data.isSelect() ){ + userByType(data,adapter, position) + } + } + } + } + + + private fun getShopMine(): Single> { + return api.getShopMine(mDressType,mPage,mPageSize) + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()) + } + + private fun postOptDress(dressType: Int,dressId: Int): Single { + return api.postOptDress(dressType,dressId) + .compose(RxHelper.handleStringData()) + .compose(RxHelper.handleSchedulers()) + } + + private fun getUserCarsV2(): Single> { + return api.requestMyCarsV2(AuthModel.get().currentUid) + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()) + } + + private fun driveThisCar(carId: Int): Single { + val ticket = AuthModel.get().ticket + val uid = AuthModel.get().currentUid + return api.driveThisCar(ticket, uid, carId) + .compose(RxHelper.handleStringData()) + .compose(RxHelper.handleSchedulers()) + } + + private fun getNamePlateList(): Single { + return api.getNamePlateList(AuthModel.get().currentUid.toString(), mPage.toString(), mPageSize.toString()) + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()) + } + + private fun useMyNamePlate(id: Int,word: String): Single { + val ticket = AuthModel.get().ticket + val uid = AuthModel.get().currentUid + return api.useMyNamePlate(uid.toString(),ticket, id.toString(),word) + .compose(RxHelper.handleStringData()) + .compose(RxHelper.handleSchedulers()) + } + + private fun getMyUserCardWearList(): Single> { + return api.getMyUserCardWearList(mPage,mPageSize) + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()) + } + + private fun userMyUserCardWear(id: Int): Single { + return api.userMyUserCardWear(id.toString()) + .compose(RxHelper.handleStringData()) + .compose(RxHelper.handleSchedulers()) + } + + private fun getChatBubbleInfoList(): Single> { + return api.getChatBubbleInfoList(mPage,mPageSize) + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()) + } + + private fun userChatBubble(id: Int): Single { + return api.userChatBubble(id.toString()) + .compose(RxHelper.handleStringData()) + .compose(RxHelper.handleSchedulers()) + } + + + private val api: Api = RxNet.create(Api::class.java); + + interface Api { + + /** + * 获取 我的装扮 : dressType : 5-个人主页背景 + */ + @GET("/dress/shop/mine") + fun getShopMine(@Query("dressType") dressType: Int,@Query("page") page: Int,@Query("pageSize") pageSize: Int): Single>> + + /** + * 购买装扮 + */ + @GET("/dress/shop/optDress") + fun postOptDress(@Query("dressType") dressType: Int, @Query("dressId") id: Int): Single> + + /** + * 使用座驾 + * + * @param ticket 用户的ticket + * @param uid 用户的uid + * @param carId 座驾的id,id=0 则表示不使用座驾,id!=0 表示使用该carId的座驾 + */ + @POST("/car/carport/use") + @FormUrlEncoded + fun driveThisCar(@Field("ticket") ticket: String?, @Field("uid") uid: Long, @Field("carId") carId: Int): Single> + + /** + * 获取自己的车库V2 + * + * @param uid - + * @return - + */ + @GET("car/carport/v2/list") + fun requestMyCarsV2(@Query("uid") uid: Long): Single>> + + + /** + * 获取铭牌列表 + */ + @POST("nameplate/userNameplateList") + fun getNamePlateList(@Query("uid") uid: String?, @Query("page") page: String?, @Query("pageSize") pageSize: String?): Single?> + + @POST("nameplate/useNameplate") + fun useMyNamePlate(@Query("uid") uid: String?, @Query("ticket") ticket: String?, @Query("userNameplateId") id: String?, @Query("word") word: String?): Single> + + + /** + * 分页获取用户资料卡装扮列表 + */ + @GET("userInfoCard/listByPage") + fun getMyUserCardWearList(@Query("page") page: Int, @Query("pageSize") pageSize: Int): Single>> + + /** + * 使用资料卡装扮 + */ + @GET("userInfoCard/optUserInfoCard") + fun userMyUserCardWear(@Query("cardId") cardId: String?): Single> + + + /** + * 分页获取用户聊天气泡列表 + */ + @GET("userChatBubble/listByPage") + fun getChatBubbleInfoList(@Query("page") page: Int, @Query("pageSize") pageSize: Int): Single>> + + /** + * 使用聊天气泡 + */ + @FormUrlEncoded + @POST("userChatBubble/optUserChatBubble") + fun userChatBubble(@Field("bubbleId") cardId: String?): Single> + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/decoration/ui/fragment/DressUpStoreFragment.kt b/app/src/main/java/com/chwl/app/decoration/ui/fragment/DressUpStoreFragment.kt new file mode 100644 index 0000000..ba32ecc --- /dev/null +++ b/app/src/main/java/com/chwl/app/decoration/ui/fragment/DressUpStoreFragment.kt @@ -0,0 +1,193 @@ +package com.chwl.app.decoration.ui.fragment + +import android.os.Bundle +import android.view.View +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.chwl.app.R +import com.chwl.app.base.BaseListFragment +import com.chwl.app.bindadapter.BaseBindingAdapter +import com.chwl.app.common.EmptyViewHelper +import com.chwl.app.decoration.adapter.DressUpAdapter +import com.chwl.app.decoration.util.DressUpUtil +import com.chwl.app.event.DressUpEvent +import com.chwl.core.bean.response.ServiceResult +import com.chwl.core.decoration.bean.DecorationInfo +import com.chwl.core.decoration.bean.DressUpInfo +import com.chwl.core.utils.net.RxHelper +import com.chwl.library.common.util.doToast +import com.chwl.library.common.util.isVerify +import com.chwl.library.common.util.setMargin +import com.chwl.library.net.rxnet.RxNet +import com.example.lib_utils.ktx.getString +import io.reactivex.Single +import org.greenrobot.eventbus.EventBus +import retrofit2.http.Field +import retrofit2.http.FormUrlEncoded +import retrofit2.http.GET +import retrofit2.http.POST +import retrofit2.http.Query + +class DressUpStoreFragment: BaseListFragment() { + + private var mPosition = -1 + + companion object { + fun newInstance(dressType: Int): DressUpStoreFragment { + val args = Bundle() + args.putInt("dressType", dressType) + val fragment = DressUpStoreFragment() + fragment.arguments = args + return fragment + } + } + + private val mDressType: Int by lazy { requireArguments().getInt("dressType") } + + override fun initView() { + + binding.srlLayout.setEnableRefresh(false) + binding.srlLayout.setEnableLoadMore(false) + + mAdapter.setEmptyView(EmptyViewHelper.createEmptyTextViewHeight(context, R.string.empty_data.getString())) + binding.rvList.setMargin(start = 10, end = 10) + + } + + override fun onResume() { + super.onResume() + if (!mAdapter.data.isVerify()) { + mPosition = -1 + onLoad() + } + } + + override fun getAdapter(): BaseBindingAdapter<*, DressUpInfo> { + return DressUpAdapter() + } + + override fun getLayoutManager(): RecyclerView.LayoutManager { + return GridLayoutManager(context,2,RecyclerView.VERTICAL,false) + } + + + override fun onLoad() { + getShopList() + .compose(bindToLifecycle()) + .doOnSuccess { + it?.let { + val newData = mutableListOf() + if (it.isVerify()){ + it.forEach { + newData.add(DressUpUtil.tranData(it)) + } + } + mAdapter.setNewData(newData) + + if (newData.isVerify()) { + binding.rvList.post { + setlect(0) + } + } + } + } + .doOnError { + it?.message?.doToast() + } + .subscribe() + } + + override fun onRefresh() { + + } + + override fun onItemChildClicks(adapter: BaseBindingAdapter<*, DressUpInfo>?, view: View?, position: Int) { + view?.id?.let { + when (it) { + R.id.btnPlay -> { + adapter?.data?.getOrNull(position)?.let { data-> + EventBus.getDefault().post(DressUpEvent(DressUpEvent.Action.Play,data)) + } + } + else -> {} + } + } + } + + override fun onItemClicks(adapter: BaseBindingAdapter<*, DressUpInfo>?, view: View?, position: Int) { + setlect(position) + } + + private fun setlect(position: Int) { + mAdapter?.data?.getOrNull(position)?.let { data -> + + if (mPosition != -1) { + mAdapter?.data?.getOrNull(mPosition)?.isSelect = false + mAdapter?.notifyItemChanged(mPosition) + } + + mPosition = position + mAdapter?.data?.getOrNull(position)?.isSelect = true + mAdapter?.notifyItemChanged(position) + + EventBus.getDefault().post(DressUpEvent(DressUpEvent.Action.Select, data)) + } + } + + + fun selectOne() { + if (mPosition != -1) { + mAdapter?.data?.getOrNull(mPosition)?.let { data -> + EventBus.getDefault().post(DressUpEvent(DressUpEvent.Action.Select, data)) + } + } + } + + + private fun getShopList(): Single> { + return api.getShopList(mDressType) + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()) + } + + private val api: Api = RxNet.create(Api::class.java); + interface Api { + /** + * 获取装扮商城列表 + * + * @return + */ + @GET("/dress/shop/list") + fun getShopList(@Query("dressType") dressType: Int): Single>> + + /** + * 购买装扮 + * + * @return + */ + @FormUrlEncoded + @POST("/dress/shop/buy") + fun postShopBuy( + @Field("dressType") dressType: Int, + @Field("id") id: Int + ): Single> + + /** + * 赠送装扮 + * + * @return + */ + @FormUrlEncoded + @POST("/dress/shop/give") + fun postShopGive( + @Field("dressType") dressType: Int, + @Field("id") id: Int, + @Field("targetUid") targetUid: Long, + ): Single> + + } + + + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/decoration/util/DressUpUtil.kt b/app/src/main/java/com/chwl/app/decoration/util/DressUpUtil.kt new file mode 100644 index 0000000..4b86afb --- /dev/null +++ b/app/src/main/java/com/chwl/app/decoration/util/DressUpUtil.kt @@ -0,0 +1,548 @@ +package com.chwl.app.decoration.util + +import android.graphics.Typeface +import android.view.ViewGroup +import android.widget.ImageView +import com.chwl.app.R +import com.chwl.app.avroom.widget.GalleryLayoutManager.LayoutParams +import com.chwl.app.decoration.ui.activity.DressUpTabActivity +import com.chwl.app.decoration.ui.activity.DressUpTabActivity.Companion.TAB_HEAD_WEAR +import com.chwl.app.decoration.ui.activity.DressUpTabActivity.Companion.TAB_USER_CARD +import com.chwl.app.decoration.ui.activity.DressUpTabActivity.Companion.TAB_USER_INFO_BG +import com.chwl.app.ui.utils.loadAnim2 +import com.chwl.app.ui.utils.loadImage +import com.chwl.app.utils.NumberUtils +import com.chwl.core.decoration.bean.DecorationInfo +import com.chwl.core.decoration.bean.DressUpInfo +import com.chwl.core.decoration.bean.ShopMine +import com.chwl.core.decoration.car.bean.CarInfo +import com.chwl.core.decoration.headwear.bean.ChatBubbleInfo +import com.chwl.core.decoration.headwear.bean.UserCardWearInfo +import com.chwl.core.decoration.nameplate.bean.NamePlateInfo +import com.chwl.core.user.bean.EffectType +import com.chwl.library.common.util.isRtl +import com.chwl.library.common.util.isVerify +import com.chwl.library.common.util.setViewWH +import com.chwl.library.common.util.setVis +import com.chwl.library.common.util.toNumString +import com.chwl.library.widget.SVGAView +import com.chwl.library.widget.text.DrawableTextView +import com.example.lib_utils.ktx.getColor +import com.example.lib_utils.ktx.getString +import com.example.lib_utils.spannable.SpannableTextBuilder +import com.opensource.svgaplayer.SVGACallback +import com.tencent.qgame.animplayer.AnimConfig +import com.tencent.qgame.animplayer.AnimView +import com.tencent.qgame.animplayer.inter.IAnimListener +import com.tencent.qgame.animplayer.util.ScaleType + +class DressUpUtil { + companion object { + + fun getEmpty(dressType:Int,use:Boolean): DressUpInfo { + val outData = DressUpInfo() + outData.dressId = 0 + outData.dressType =dressType + outData.isMy = true + outData.isNull = true + outData.isSelect = use + return outData + } + + //商城 + fun tranData(inData: DecorationInfo): DressUpInfo { + + val outData = DressUpInfo() + + outData.dressLimitStatus = inData.dressLimitStatus + outData.discount = inData.discount + outData.originalPrice = inData.dressPrice.toNumString() + outData.buyDay = inData.dressDay + outData.price = inData.discountPrice.toNumString() + outData.name = inData.name + outData.pic = inData.pic + outData.effect = inData.effect + outData.effectType = inData.effectType + outData.dressType = inData.dressType + outData.vipLimit = inData.vipLimit + outData.vipLevel = inData.vipLevel + outData.id = inData.dressId + outData.dressId = inData.id + outData.obtainWay = inData.obtainWay + + return outData + } + + //座驾 + fun tranData(inData: CarInfo): DressUpInfo { + + val outData = DressUpInfo() + outData.isMy = true + outData.isSelect = inData.using == 1 + outData.name = inData.name + outData.pic = inData.pic + if (inData.viewUrl.isVerify()) { + outData.effect = inData.viewUrl + outData.effectType = inData.otherViewType + }else{ + outData.effect = inData.effect + outData.effectType = inData.otherViewType + } + outData.dressType = DressUpTabActivity.TAB_CAR + outData.dressId = inData.dressShopId + outData.id = inData.carId + + outData.price = inData.discountPrice.toNumString() + outData.originalPrice = inData.dressPrice.toNumString() + outData.buyDay = inData.dressDay + + outData.hasExpired = inData.status != CarInfo.STATUS_USER_CAN_USE + +// val cTime = System.currentTimeMillis() +// val dTime = inData.expireDays - cTime +// val dDay = TimeUnit.MICROSECONDS.toDays(dTime) +// if (dDay < TimeUnit.DAYS.toMillis(1)) { +// // < 1 天 +// } else { +// // dDay天后过期 +// } + + outData.expireDays = inData.remainingDay + + return outData + } + + // 个人主页 , 头饰 + fun tranData(inData: ShopMine): DressUpInfo { + + val outData = DressUpInfo() + outData.isMy = true + outData.isSelect = inData.isUsed + outData.name = inData.name + outData.pic = inData.pic + outData.effect = inData.effect + outData.effectType = inData.effectType + outData.dressType = inData.dressType + outData.id = inData.dressId + outData.dressId = inData.id + outData.obtainWay = inData.obtainWay + + outData.hasExpired = inData.hasExpired + outData.expireDays = inData.expireDays + + outData.price = inData.discountPrice.toNumString() + outData.originalPrice = inData.dressPrice.toNumString() + outData.buyDay = inData.dressDay + return outData + } + + //铭牌 + fun tranData(inData: NamePlateInfo.NameplateListBean): DressUpInfo { + + val outData = DressUpInfo() + outData.isMy = true + outData.isSelect = inData.isUsing + outData.name = inData.nameplateName + outData.word = inData.word + outData.pic = inData.nameplateImage + outData.dressType = DressUpTabActivity.TAB_NAMEPLATE + outData.id = inData.id + + outData.dressId = inData.dressShopId + outData.price = inData.discountPrice.toNumString() + outData.originalPrice = inData.dressPrice.toNumString() + outData.buyDay = inData.dressDay + outData.hasExpired = inData.isExpired + outData.expireDays = inData.expireDays + + return outData + } + + //用户弹窗背景 + fun tranData(inData: UserCardWearInfo): DressUpInfo { + + val outData = DressUpInfo() + outData.isMy = true + outData.isSelect = inData.isUsed + outData.name = inData.name + outData.pic = inData.pic + outData.effect = if (inData.effect.isVerify()) inData.effect else inData.pic + outData.effectType = EffectType.MP4 + outData.dressType = DressUpTabActivity.TAB_USER_CARD + if (inData.cardId.isVerify()) { + outData.id = inData.cardId.toInt() + } + + outData.dressId = inData.dressShopId + outData.price = inData.discountPrice.toNumString() + outData.originalPrice = inData.dressPrice.toNumString() + outData.buyDay = inData.dressDay + outData.hasExpired = inData.isHasExpired + outData.expireDays = inData.expireDays + + return outData + } + + //聊天气泡 + fun tranData(inData: ChatBubbleInfo): DressUpInfo { + + val outData = DressUpInfo() + outData.isMy = true + outData.isSelect = inData.isHasUsed + outData.name = inData.name + outData.pic = inData.bubbleUrl + outData.dressType = DressUpTabActivity.TAB_CHAT_BUBBLE + if (inData.bubbleId.isVerify()) { + outData.id = inData.bubbleId.toInt() + } + + outData.dressId = inData.dressShopId + outData.price = inData.discountPrice.toNumString() + outData.originalPrice = inData.dressPrice.toNumString() + outData.buyDay = inData.dressDay + + outData.hasExpired = inData.isHasExpired + outData.expireDays = inData.expireDays + + return outData + } + + fun setTextPrice(textView: DrawableTextView, item: DressUpInfo,isItemView:Boolean = false,isDialog:Boolean = false) { + + var oPrice = "0" + if (!isDialog && !isItemView) { + oPrice = "" + } else { + oPrice = if (isItemView) NumberUtils.format(item.originalPrice.toDouble(),false) else item.originalPrice + } + + val price = if (isItemView) NumberUtils.format(item.price.toDouble(),false) else item.price + val priceSize = if (isItemView) 13 else if(isDialog) 18 else 16 + val oPriceSize = if (isItemView) 10 else if(isDialog) 14 else 12 + + if (price == oPrice) { + val message = R.string.s_sDays_s.getString(price, item.buyDay.toString(), "") + + SpannableTextBuilder(textView).appendText(message) + .addTextStyleList(arrayListOf( + SpannableTextBuilder.TextStyleBean().apply { + text = price + textStyle = Typeface.BOLD + textSize = priceSize + }, + SpannableTextBuilder.TextStyleBean().apply { + text = item.buyDay.toString() + textStyle = Typeface.NORMAL + textSize = oPriceSize + } + )) + .apply() + +// SpannableTextBuilder(textView).appendText(message) +// .setTextStyle( +// text = price, +// textStyle = Typeface.BOLD, +// textSize = priceSize +// ).setTextStyle( +// text = item.buyDay.toString(), +// textStyle = Typeface.NORMAL, +// textSize = oPriceSize, +// ) +// .apply() + + } else { + val message = R.string.s_sDays_s.getString(price, item.buyDay.toString(), oPrice) + if (textView.context.isRtl()) { + + SpannableTextBuilder(textView).appendText(message) + .addTextStyleList(arrayListOf( + SpannableTextBuilder.TextStyleBean().apply { + text = item.buyDay.toString() + textStyle = Typeface.NORMAL + textSize = oPriceSize + }, + SpannableTextBuilder.TextStyleBean().apply { + text = price + textStyle = Typeface.BOLD + textSize = priceSize + }, + SpannableTextBuilder.TextStyleBean().apply { + text = oPrice + textColor = R.color.color_d9e7f7_50.getColor() + textStyle = Typeface.NORMAL + delLine = true + textSize = oPriceSize + } + )).apply() + +// SpannableTextBuilder(textView).appendText(message) +// .setTextStyle( +// text = item.buyDay.toString(), +// textStyle = Typeface.NORMAL, +// textSize = oPriceSize, +// ).setTextStyle( +// text = price, +// textStyle = Typeface.BOLD, +// textSize = priceSize, +// ).setTextStyle( +// text = oPrice, +// textColor = R.color.color_d9e7f7_50.getColor(), +// textStyle = Typeface.NORMAL, +// delLine = true, +// textSize = oPriceSize, +// ).apply() + + } else { + SpannableTextBuilder(textView).appendText(message) + .addTextStyleList(arrayListOf( + SpannableTextBuilder.TextStyleBean().apply { + text = price + textStyle = Typeface.BOLD + textSize = priceSize + }, + SpannableTextBuilder.TextStyleBean().apply { + text = item.buyDay.toString() + textStyle = Typeface.NORMAL + textSize = oPriceSize + }, + SpannableTextBuilder.TextStyleBean().apply { + text = oPrice + textColor = R.color.color_d9e7f7_50.getColor() + textStyle = Typeface.NORMAL + textSize = oPriceSize + delLine = true + } + )).apply() + +// SpannableTextBuilder(textView).appendText(message) +// .setTextStyle( +// text = price, +// textStyle = Typeface.BOLD, +// textSize = priceSize, +// ).setTextStyle( +// text = item.buyDay.toString(), +// textStyle = Typeface.NORMAL, +// textSize = oPriceSize, +// ).setTextStyle( +// text = oPrice, +// textColor = R.color.color_d9e7f7_50.getColor(), +// textStyle = Typeface.NORMAL, +// textSize = oPriceSize, +// delLine = true, +// ).apply() + } + + } + + textView.setVis(true) + } + + fun setItemPic(data:DressUpInfo,layout: ViewGroup) { + if (data.dressType == DressUpTabActivity.TAB_USER_CARD) { + //此时传回的是mp4.. +// layout.setViewWH() + play(data,layout,false) + } else { + layout.removeAllViews() + val pic = ImageView(layout.context) + layout.addView(pic) + if (data.dressType == DressUpTabActivity.TAB_CAR) { + pic.setViewWH(129,129) + }else if (data.dressType == DressUpTabActivity.TAB_HEAD_WEAR) { + pic.setViewWH(117,117) + }else if (data.dressType == DressUpTabActivity.TAB_NAMEPLATE) { + pic.setViewWH(98,28) + }else if (data.dressType == DressUpTabActivity.TAB_CHAT_BUBBLE) { + pic.setViewWH(90,46) + }else if (data.dressType == DressUpTabActivity.TAB_USER_INFO_BG) { + pic.setViewWH(127,125) + } + pic.loadImage(data.pic) + } + } + + fun setDialogPic(data:DressUpInfo,layout: ViewGroup) { + if (data.dressType == DressUpTabActivity.TAB_USER_CARD) { + //此时传回的是mp4.. +// layout.setViewWH() + play(data,layout,true) + } else { + layout.removeAllViews() + val pic = ImageView(layout.context) + layout.addView(pic) + if (data.dressType == DressUpTabActivity.TAB_CAR) { + pic.setViewWH(155,155) + }else if (data.dressType == DressUpTabActivity.TAB_HEAD_WEAR) { + pic.setViewWH(147,147) + }else if (data.dressType == DressUpTabActivity.TAB_USER_CARD) { + pic.setViewWH(182,161) + }else if (data.dressType == DressUpTabActivity.TAB_NAMEPLATE) { + pic.setViewWH(108,30) + }else if (data.dressType == DressUpTabActivity.TAB_CHAT_BUBBLE) { + pic.setViewWH(100,52) + }else if (data.dressType == DressUpTabActivity.TAB_USER_INFO_BG) { + pic.setViewWH(163,161) + } + pic.loadImage(data.pic) + } + } + + fun play(data:DressUpInfo,layout: ViewGroup){ + if (data.effect.isVerify()) { + + var animView : AnimView?=null + var svgaView : SVGAView?=null + + layout.setVis(true) + layout.removeAllViews() + + if (data.effectType == EffectType.MP4) { + animView = AnimView(layout.context) + layout.addView(animView) + animView.setLoop(1) + animView.setScaleType(ScaleType.FIT_XY) + } else { + svgaView = SVGAView(layout.context) + layout.addView(svgaView) + svgaView.loops =1 + svgaView.setScaleType(ImageView.ScaleType.FIT_XY) + } + + + if (data.dressType == TAB_HEAD_WEAR) { + animView?.setViewWH(183, 183, true) + svgaView?.setViewWH(183, 183, true) + } else if (data.dressType == TAB_USER_CARD) { + animView?.setViewWH(285, 250, true) + svgaView?.setViewWH(285, 250, true) + } else if (data.dressType == TAB_USER_INFO_BG) { + animView?.setViewWH(305, 300, true) + svgaView?.setViewWH(305, 300, true) + } else { + animView?.setViewWH(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, false) + svgaView?.setViewWH(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, false) + } + + + animView?.setAnimListener(object : IAnimListener { + override fun onFailed(errorType: Int, errorMsg: String?) { } + override fun onVideoComplete() { + layout?.post { + animView?.stopPlay() + layout?.removeAllViews() + layout?.setVis(false) + } + } + override fun onVideoDestroy() {} + override fun onVideoRender(frameIndex: Int, config: AnimConfig?) {} + override fun onVideoStart() {} + }) + + svgaView?.callback = object : SVGACallback { + override fun onFinished() { + layout?.post { + animView?.stopPlay() + layout?.removeAllViews() + layout?.setVis(false) + } + } + + override fun onPause() {} + + override fun onRepeat() {} + + override fun onStep(frame: Int, percentage: Double) { + + } + } + animView?.loadAnim2(data.effect,false) + svgaView?.loadUrl(data.effect,true) + + }else{ + layout.setVis(false,true) + layout.removeAllViews() + } + } + + + fun play(data:DressUpInfo,layout: ViewGroup,isDialog :Boolean = false){ + if (data.effect.isVerify()) { + + var animView : AnimView?=null + var svgaView : SVGAView?=null + + layout.setVis(true) + layout.removeAllViews() + + if (data.effectType == EffectType.MP4) { + animView = AnimView(layout.context) + layout.addView(animView) + animView.setLoop(Int.MAX_VALUE) + animView.setScaleType(ScaleType.FIT_XY) + } else { + svgaView = SVGAView(layout.context) + layout.addView(svgaView) + svgaView.loops = Int.MAX_VALUE + svgaView.setScaleType(ImageView.ScaleType.FIT_XY) + } + + //item 时占满就行 + if (!isDialog) { + if (data.dressType == TAB_USER_CARD) { + animView?.setViewWH(132, 116, true) + svgaView?.setViewWH(132, 116, true) + } else { + animView?.setViewWH(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, false) + svgaView?.setViewWH(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,false) + } + } else { + if (data.dressType == TAB_USER_CARD) { + animView?.setViewWH(188, 168, true) + svgaView?.setViewWH(188, 168, true) + } else { + animView?.setViewWH(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, false) + svgaView?.setViewWH(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,false) + } + } + +// animView?.setAnimListener(object : IAnimListener { +// override fun onFailed(errorType: Int, errorMsg: String?) { } +// override fun onVideoComplete() { +// layout?.post { +// animView?.stopPlay() +// layout?.removeAllViews() +// layout?.setVis(false) +// } +// } +// override fun onVideoDestroy() {} +// override fun onVideoRender(frameIndex: Int, config: AnimConfig?) {} +// override fun onVideoStart() {} +// }) +// +// svgaView?.callback = object : SVGACallback { +// override fun onFinished() { +// layout?.post { +// animView?.stopPlay() +// layout?.removeAllViews() +// layout?.setVis(false) +// } +// } +// +// override fun onPause() {} +// +// override fun onRepeat() {} +// +// override fun onStep(frame: Int, percentage: Double) { +// +// } +// } + animView?.loadAnim2(data.effect,false) + svgaView?.loadUrl(data.effect,true) + + }else{ + layout.setVis(false,true) + layout.removeAllViews() + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/decoration/view/DecorationCommonFragment.kt b/app/src/main/java/com/chwl/app/decoration/view/DecorationCommonFragment.kt new file mode 100644 index 0000000..e5f7c0f --- /dev/null +++ b/app/src/main/java/com/chwl/app/decoration/view/DecorationCommonFragment.kt @@ -0,0 +1,110 @@ +package com.chwl.app.decoration.view + +import android.os.Bundle +import androidx.fragment.app.viewModels +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.LinearLayoutManager +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingFragment +import com.chwl.app.common.EmptyViewHelper +import com.chwl.app.databinding.FragmentDecorationCommonBinding +import com.chwl.app.decoration.adapter.DecorationCommonAdapter +import com.chwl.app.decoration.viewmodel.DecorationViewModel +import com.chwl.app.ui.relation.FansListActivity +import com.chwl.app.ui.utils.RVDelegate +import com.chwl.core.decoration.DecorationInfoEvent +import com.chwl.core.decoration.bean.DecorationInfo +import com.chwl.library.annatation.ActLayoutRes +import com.chwl.library.utils.ResUtil +import org.greenrobot.eventbus.EventBus + +/** + * Created by huangmeng1 on 2018/5/7. + */ +@ActLayoutRes(R.layout.fragment_decoration_common) +class DecorationCommonFragment : BaseViewBindingFragment() { + + companion object { + fun newInstance(dressType: Int): DecorationCommonFragment { + val args = Bundle() + args.putInt("dressType", dressType) + val fragment = DecorationCommonFragment() + fragment.arguments = args + return fragment + } + } + + private val dressType: Int by lazy { requireArguments().getInt("dressType") } + private lateinit var rvDelegate: RVDelegate + private lateinit var decorationAdapter: DecorationCommonAdapter + private val decorationViewModel: DecorationViewModel by viewModels() + + override fun init() { + + decorationViewModel.loadingLiveData.observe(viewLifecycleOwner) { + if (it) dialogManager.showProgressDialog(mContext) + else dialogManager.dismissDialog() + } + decorationAdapter = if (dressType == DecorationStoreActivity.TAB_USER_CARD) { + DecorationCommonAdapter(R.layout.item_decoration_user_card) + } else { + DecorationCommonAdapter() + } + rvDelegate = RVDelegate.Builder() + .setAdapter(decorationAdapter) + .setRecyclerView(binding.recyclerView) + .setRefreshLayout(binding.swipeRefresh) + .setEmptyView(EmptyViewHelper.createEmptyTextView(mContext, ResUtil.getString(R.string.decoration_view_decorationcommonfragment_01))) + .setLayoutManager( + if (dressType == DecorationStoreActivity.TAB_USER_CARD) { + LinearLayoutManager(mContext) + } else { + GridLayoutManager(mContext, 2, GridLayoutManager.VERTICAL, false) + } + ) + .build() + binding.swipeRefresh.setOnRefreshListener { + decorationViewModel.getDecorationInfoList(dressType) + } + decorationViewModel.getDecorationInfoList(dressType) + decorationViewModel.decorationInfoListLiveData.observe(viewLifecycleOwner) { + rvDelegate.loadData(it) + } + + decorationAdapter.setOnItemChildClickListener { _, view, position -> + val decorationInfo = + decorationAdapter.getItem(position) ?: return@setOnItemChildClickListener + when (view.id) { + R.id.tv_buy -> { + dialogManager.showOkCancelDialog( + ResUtil.getString(R.string.decoration_view_decorationcommonfragment_02), + mContext.resources.getString( + R.string.buy_decoration_info_text, + decorationInfo.name, + decorationInfo.dressDay.toString() + ), + ResUtil.getString(R.string.decoration_view_decorationcommonfragment_03), + ResUtil.getString(R.string.decoration_view_decorationcommonfragment_04), + true + ) { + decorationViewModel.buyDecoration( + decorationInfo.dressType, + decorationInfo.id + ) + } + } + R.id.tv_send -> { + EventBus.getDefault().postSticky(DecorationInfoEvent(decorationInfo)) + FansListActivity.start(mContext, FansListActivity.TYPE_DECORATION) + } + } + } + + } + + override fun onDestroy() { + super.onDestroy() + EventBus.getDefault().removeStickyEvent(DecorationInfoEvent::class.java) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/decoration/view/DecorationStoreActivity.kt b/app/src/main/java/com/chwl/app/decoration/view/DecorationStoreActivity.kt new file mode 100644 index 0000000..9a339d5 --- /dev/null +++ b/app/src/main/java/com/chwl/app/decoration/view/DecorationStoreActivity.kt @@ -0,0 +1,132 @@ +package com.chwl.app.decoration.view + +import android.content.Context +import android.content.Intent +import android.graphics.Color +import android.view.View +import androidx.activity.viewModels +import androidx.fragment.app.Fragment +import androidx.viewpager2.adapter.FragmentStateAdapter +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.base.TitleBar +import com.chwl.app.databinding.ActivityDecorationStoreBinding +import com.chwl.app.decoration.ui.activity.DressUpTabActivity +import com.chwl.app.decoration.view.widgets.CarMagicIndicator +import com.chwl.app.decoration.view.widgets.MyDecorationMagicIndicator +import com.chwl.app.decoration.viewmodel.DecorationViewModel +import com.chwl.app.home.helper.BannerHelper +import com.chwl.app.ui.pay.ChargeActivity +import com.chwl.app.ui.widget.magicindicator.ViewPagerHelper +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.CommonNavigator +import com.chwl.core.Constants +import com.chwl.core.home.bean.TabInfo +import com.chwl.core.pay.PayModel +import com.chwl.core.pay.event.UpdateWalletInfoEvent +import com.chwl.library.annatation.ActLayoutRes +import com.chwl.library.utils.FormatUtils +import com.chwl.library.utils.ResUtil +import com.netease.nim.uikit.StatusBarUtil +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode + +@ActLayoutRes(R.layout.activity_decoration_store) +class DecorationStoreActivity : BaseViewBindingActivity(), + CarMagicIndicator.OnItemSelectListener, MyDecorationMagicIndicator.OnItemSelectListener { + + companion object { + + const val TAB_HEAD_WEAR = 0 + const val TAB_CAR = 1 + const val TAB_NAMEPLATE = 2 + const val TAB_USER_CARD = 3 + const val TAB_CHAT_BUBBLE = 4 + + @JvmStatic + fun start(context: Context, position: Int) { + val intent = Intent(context, DecorationStoreActivity::class.java) + intent.putExtra(Constants.KEY_POSITION, position) + context.startActivity(intent) + } + } + + private var mPosition = 0 + private val decorationViewModel: DecorationViewModel by viewModels() + + override fun init() { + EventBus.getDefault().register(this) + initWhiteTitleBar(ResUtil.getString(R.string.decoration_view_decorationstoreactivity_01)) + mTitleBar?.addAction(object : TitleBar.TextAction( + ResUtil.getString(R.string.decoration_view_decorationstoreactivity_02), Color.parseColor("#999999") + ) { + override fun performAction(view: View) { + DressUpTabActivity.start(this@DecorationStoreActivity,true) + } + }) + mPosition = intent.getIntExtra(Constants.KEY_POSITION, 0) + initViews() + decorationViewModel.bannerLiveData.observe(this) { + BannerHelper.setBanner(binding.rollView, it) + } + binding.tvCharge.setOnClickListener { + ChargeActivity.start(this) + } + } + + private fun initViews() { + onWalletInfoUpdate(null) + val viewPager = binding.viewpager + val mMagicIndicator = binding.viewIndicator + val tabInfoList: MutableList = ArrayList(5) + tabInfoList.add(TabInfo(TAB_HEAD_WEAR, ResUtil.getString(R.string.decoration_view_decorationstoreactivity_03))) + tabInfoList.add(TabInfo(TAB_CAR, ResUtil.getString(R.string.decoration_view_decorationstoreactivity_04))) + tabInfoList.add(TabInfo(TAB_NAMEPLATE, ResUtil.getString(R.string.decoration_view_decorationstoreactivity_05))) + tabInfoList.add(TabInfo(TAB_USER_CARD, ResUtil.getString(R.string.decoration_view_decorationstoreactivity_06))) + tabInfoList.add(TabInfo(TAB_CHAT_BUBBLE, ResUtil.getString(R.string.decoration_view_decorationstoreactivity_07))) + val commonNavigator = CommonNavigator(this) + val indicator = MyDecorationMagicIndicator(this, tabInfoList) + indicator.setOnItemSelectListener(this) + commonNavigator.adapter = indicator + mMagicIndicator.navigator = commonNavigator + ViewPagerHelper.bind(mMagicIndicator, viewPager) + viewPager.adapter = object : FragmentStateAdapter(supportFragmentManager,lifecycle){ + override fun getItemCount(): Int { + return tabInfoList.size + } + + override fun createFragment(position: Int): Fragment { + return DecorationCommonFragment.newInstance(position) + } + } + viewPager.offscreenPageLimit = tabInfoList.size + viewPager.currentItem = mPosition + } + + override fun onItemSelect(position: Int) { + binding.viewpager.currentItem = position + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onWalletInfoUpdate(event: UpdateWalletInfoEvent?) { + binding.tvDiamondNum.text = + FormatUtils.formatBigInteger(PayModel.get().currentWalletInfo?.diamondNum ?: 0.0) + } + + override fun needSteepStateBar(): Boolean { + return true + } + + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } + + override fun onDestroy() { + super.onDestroy() + EventBus.getDefault().unregister(this) + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/decoration/view/ICarView.java b/app/src/main/java/com/chwl/app/decoration/view/ICarView.java new file mode 100644 index 0000000..afd1d05 --- /dev/null +++ b/app/src/main/java/com/chwl/app/decoration/view/ICarView.java @@ -0,0 +1,24 @@ +package com.chwl.app.decoration.view; + +import com.chwl.core.decoration.car.bean.CarInfo; +import com.chwl.library.base.IMvpBaseView; + +/** + * Created by yudi + * on 2018/3/1. + */ + +public interface ICarView extends IMvpBaseView { + + /** + * 点击购买按钮 + * + * @param carInfo - + */ + void showDetail(CarInfo carInfo); + + /** + * 车库需不需要更新 + */ + boolean getCarGarageNeedUpdate(); +} diff --git a/app/src/main/java/com/chwl/app/decoration/view/MyCarFragment.java b/app/src/main/java/com/chwl/app/decoration/view/MyCarFragment.java new file mode 100644 index 0000000..5fcce69 --- /dev/null +++ b/app/src/main/java/com/chwl/app/decoration/view/MyCarFragment.java @@ -0,0 +1,174 @@ +package com.chwl.app.decoration.view; + +import android.annotation.SuppressLint; +import android.os.Bundle; +import android.view.View; + +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.LinearLayoutManager; + +import com.chwl.app.BR; +import com.chwl.app.R; +import com.chwl.app.base.BaseBindingFragment; +import com.chwl.app.common.NoDataFragment; +import com.chwl.app.databinding.FrgMyDecorationCommonBinding; +import com.chwl.app.decoration.adapter.MyCarAdapter; +import com.chwl.app.decoration.viewmodel.MyCarVm; +import com.chwl.app.ui.widget.LoadingDialog; +import com.chwl.core.decoration.car.CarModel; +import com.chwl.core.decoration.car.bean.CarInfo; +import com.chwl.core.user.UserModel; +import com.chwl.library.annatation.ActLayoutRes; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; + +import java.util.List; + +/** + * Created by yudi + * on 2018/3/2. + */ + +@ActLayoutRes(R.layout.frg_my_decoration_common) +public class MyCarFragment extends BaseBindingFragment { + + private ICarView mCarView; + private MyCarAdapter mCarGarageAdapter; + private boolean first = true; + + private MyCarVm myCarVm; + + public static MyCarFragment instance(ICarView carView) { + MyCarFragment fragment = new MyCarFragment(); + fragment.mCarView = carView; + return fragment; + } + + @Override + public void onFindViews() { + } + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + if (first && getUserVisibleHint()) { + first = false; + } + } + + @Override + public void onSetListener() { + } + + @Override + public void initiate() { + myCarVm = new MyCarVm(); + mBinding.setViewmodel(myCarVm); + + mCarGarageAdapter = new MyCarAdapter(R.layout.item_car_garage_normal, BR.carInfo); + mCarGarageAdapter.setOnItemChildClickListener((adapter, view, position) -> { + + switch (view.getId()) { + case R.id.tv_used: + startDriving(mCarGarageAdapter.getItem(position)); + break; + + } + }); + + mBinding.swipeRefresh.setOnRefreshListener(() -> getData()); + + mBinding.recyclerView.setAdapter(mCarGarageAdapter); + mBinding.recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); + + getData(); + } + + public MyCarAdapter getAdapter() { + return mCarGarageAdapter; + } + + @Override + public void setUserVisibleHint(boolean isVisibleToUser) { + super.setUserVisibleHint(isVisibleToUser); + if (isVisibleToUser && mCarView != null && mCarView.getCarGarageNeedUpdate()) { + getData(); + } + } + + @SuppressLint("CheckResult") + private void getData() { + + if (myCarVm == null) + return; + + myCarVm.loadData(false).compose(bindToLifecycle()) + .doAfterTerminate(() -> { + if (ListUtils.isListEmpty(mCarGarageAdapter.getData())) { + showNoData(R.drawable.icon_common_failure, ResUtil.getString(R.string.decoration_view_mycarfragment_01)); + } + + List list = mCarGarageAdapter.getData(); + + for (CarInfo item : list) { + if (item.getCarId() == 0) { + list.remove(item); + break; + } + } + + mCarGarageAdapter.notifyDataSetChanged(); + }) + .subscribe(); + } + + @Override + public void showNoData(View view, int drawable, CharSequence charSequence) { + if (!checkActivityValid()) + return; + + if (view == null) { + return; + } + View status = view.findViewById(R.id.status_layout); + if (status == null || status.getId() == View.NO_ID) { + return; + } + NoDataFragment fragment = NoDataFragment.newInstance(R.layout.fragment_no_data_middle_iv, drawable, charSequence); + fragment.setListener(getLoadListener()); + getChildFragmentManager().beginTransaction().replace(status.getId(), fragment, STATUS_TAG).commitAllowingStateLoss(); + } + + @SuppressLint("CheckResult") + private void startDriving(CarInfo carInfo) { + final int id = carInfo.isUsing() ? 0 : carInfo.getCarId(); + LoadingDialog loadingDialog = new LoadingDialog(mContext); + loadingDialog.show(); + + CarModel.get().driveThisCar(id) + .subscribe((voidServiceResult, throwable) -> { + loadingDialog.dismiss(); + if (voidServiceResult != null && voidServiceResult.isSuccess()) { + //更换座驾状态,需要更新缓存 + UserModel.get().onlyUpdateLoginUserInfoCache(); + List list = mCarGarageAdapter.getData(); + for (CarInfo item : list) { + if (id == item.getCarId()) { + item.setUsing(1); + } else { + item.setUsing(0); + } + } + mCarGarageAdapter.notifyDataSetChanged(); + + } else if (voidServiceResult != null && !voidServiceResult.isSuccess()) { + SingleToastUtil.showToastShort(ResUtil.getString(R.string.decoration_view_mycarfragment_02)); + } else if (throwable != null) { + SingleToastUtil.showToastShort(ResUtil.getString(R.string.decoration_view_mycarfragment_03)); + } else { + SingleToastUtil.showToastShort(ResUtil.getString(R.string.decoration_view_mycarfragment_04)); + } + }); + } +} diff --git a/app/src/main/java/com/chwl/app/decoration/view/MyChatBubbleFragment.java b/app/src/main/java/com/chwl/app/decoration/view/MyChatBubbleFragment.java new file mode 100644 index 0000000..a3d47b1 --- /dev/null +++ b/app/src/main/java/com/chwl/app/decoration/view/MyChatBubbleFragment.java @@ -0,0 +1,108 @@ +package com.chwl.app.decoration.view; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.view.View; + +import androidx.recyclerview.widget.GridLayoutManager; + +import com.trello.rxlifecycle3.android.FragmentEvent; +import com.chwl.app.R; +import com.chwl.app.base.BaseBindingFragment; +import com.chwl.app.common.NoDataFragment; +import com.chwl.app.databinding.FragmentMyChatBubbleBinding; +import com.chwl.app.decoration.adapter.MyChatBubbleAdapter; +import com.chwl.app.decoration.viewmodel.UserChatBubbleVm; +import com.chwl.core.decoration.headwear.bean.ChatBubbleInfo; +import com.chwl.core.user.UserModel; +import com.chwl.library.annatation.ActLayoutRes; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; + +import java.util.Objects; + +/** + * Created by huangmeng1 on 2018/5/7. + */ +@ActLayoutRes(R.layout.fragment_my_chat_bubble) +public class MyChatBubbleFragment extends BaseBindingFragment { + private UserChatBubbleVm wearVm; + private MyChatBubbleAdapter bubbleAdapter; + + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + } + + @Override + public void initiate() { + wearVm = new UserChatBubbleVm(); + mBinding.setViewmodel(wearVm); + bubbleAdapter = new MyChatBubbleAdapter(); + bubbleAdapter.setOnItemChildClickListener((adapter, view, position) -> { + if (view.getId() == R.id.tv_used) { + setUsedStatus(position); + } + }); + + mBinding.swipeRefresh.setOnRefreshListener(() -> loadData(false)); + bubbleAdapter.setOnLoadMoreListener(() -> loadData(true), mBinding.recyclerView); + mBinding.recyclerView.setAdapter(bubbleAdapter); + mBinding.recyclerView.setLayoutManager(new GridLayoutManager(getActivity(),2)); + + loadData(false); + } + + private void loadData(boolean isLode) { + wearVm.loadData(isLode) + .compose(bindToLifecycle()) + .doAfterTerminate(() -> { + if (ListUtils.isListEmpty(bubbleAdapter.getData())) { + showNoData(R.drawable.icon_common_failure, ResUtil.getString(R.string.decoration_view_mychatbubblefragment_01)); + } + }) + .subscribe(); + } + + @Override + public void showNoData(View view, int drawable, CharSequence charSequence) { + if (!checkActivityValid()) + return; + + if (view == null) { + return; + } + View status = view.findViewById(R.id.status_layout); + if (status == null || status.getId() == View.NO_ID) { + return; + } + NoDataFragment fragment = NoDataFragment.newInstance(R.layout.fragment_no_data_large_iv, drawable, charSequence); + fragment.setListener(getLoadListener()); + getChildFragmentManager().beginTransaction().replace(status.getId(), fragment, STATUS_TAG).commitAllowingStateLoss(); + } + + @SuppressLint("CheckResult") + private void setUsedStatus(int position) { + ChatBubbleInfo bubbleInfo = bubbleAdapter.getData().get(position); + + // id == 0标识不使用头饰 + + String cardId = bubbleInfo.isHasUsed() ? null : bubbleInfo.getBubbleId(); + + wearVm.userChatBubble(cardId) + .compose(bindUntilEvent(FragmentEvent.DESTROY)) + .doOnError(throwable -> { + toast(throwable.getMessage()); + }) + .subscribe(s -> { + for (int i = 0; i < bubbleAdapter.getData().size(); i++) { + bubbleAdapter.getData().get(i).setHasUsed(Objects.equals(cardId, bubbleAdapter.getData().get(i).getBubbleId())); + } + bubbleAdapter.notifyDataSetChanged(); + //更新用户信息 + UserModel.get().updateCurrentUserInfo().subscribe(); + }); + } + +} diff --git a/app/src/main/java/com/chwl/app/decoration/view/MyDecorationActivity.java b/app/src/main/java/com/chwl/app/decoration/view/MyDecorationActivity.java new file mode 100644 index 0000000..d3a8858 --- /dev/null +++ b/app/src/main/java/com/chwl/app/decoration/view/MyDecorationActivity.java @@ -0,0 +1,301 @@ +package com.chwl.app.decoration.view; + +import android.content.Context; +import android.content.Intent; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentPagerAdapter; +import androidx.viewpager.widget.ViewPager; +import androidx.viewpager2.adapter.FragmentStateAdapter; +import androidx.viewpager2.widget.ViewPager2; + +import com.netease.nim.uikit.StatusBarUtil; +import com.netease.nim.uikit.common.util.log.LogUtil; +import com.netease.nim.uikit.common.util.sys.ScreenUtil; +import com.trello.rxlifecycle3.android.ActivityEvent; +import com.chwl.app.R; +import com.chwl.app.base.BaseBindingActivity; +import com.chwl.app.databinding.ActivityMyDecorationBinding; +import com.chwl.app.decoration.helper.DecorationDialogHelper; +import com.chwl.app.decoration.helper.DecorationSaleType; +import com.chwl.app.decoration.view.widgets.MyDecorationMagicIndicator; +import com.chwl.app.home.adapter.BannerAdapter; +import com.chwl.app.ui.widget.magicindicator.MagicIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.CommonNavigator; +import com.chwl.app.ui.widget.rollviewpager.Util; +import com.chwl.app.ui.widget.rollviewpager.hintview.ColorPointHintView; +import com.chwl.core.Constants; +import com.chwl.core.decoration.car.CarModel; +import com.chwl.core.decoration.car.bean.CarInfo; +import com.chwl.core.home.bean.BannerInfo; +import com.chwl.core.home.bean.TabInfo; +import com.chwl.core.home.model.GameHomeModel; +import com.chwl.core.market_verify.MarketVerifyModel; +import com.chwl.library.annatation.ActLayoutRes; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import io.reactivex.SingleObserver; +import io.reactivex.disposables.Disposable; + +/** + * Created by yudi + * on 2018/3/1. + */ + +@ActLayoutRes(R.layout.activity_my_decoration) +public class MyDecorationActivity extends BaseBindingActivity + implements ICarView, View.OnClickListener, MyDecorationMagicIndicator.OnItemSelectListener { + + /** + * 我的装饰Banner + */ + private static final String BANNER_TYPE = "3"; + private ViewPager2 viewPager; + private int mPosition; + private boolean carGarageNeedUpdate = true; + private MyHeadWearFragment myHeadWearFragment; + private MyCarFragment mMyCarFragment; + private MyNamePlateFragment mMyNamePlateFragment; + private MyUserCardWearFragment mMyUserCardWearFragment; + private MyChatBubbleFragment mMyChatBubbleFragment; + private MagicIndicator mMagicIndicator; + + public static void start(Context context, int position) { + Intent intent = new Intent(context, MyDecorationActivity.class); + intent.putExtra(Constants.KEY_POSITION, position); + context.startActivity(intent); + } + + @Override + protected void init() { + initWhiteTitleBar(ResUtil.getString(R.string.decoration_view_mydecorationactivity_01)); + mPosition = getIntent().getIntExtra(Constants.KEY_POSITION, 0); + initViews(); + initBanner(BANNER_TYPE); + } + + + private void initViews() { + viewPager = mBinding.viewpager; + mMagicIndicator = mBinding.viewIndicator; + + List tabInfoList = new ArrayList<>(5); + tabInfoList.add(new TabInfo(1, ResUtil.getString(R.string.decoration_view_mydecorationactivity_02))); + tabInfoList.add(new TabInfo(2, ResUtil.getString(R.string.decoration_view_mydecorationactivity_03))); + tabInfoList.add(new TabInfo(3, ResUtil.getString(R.string.decoration_view_mydecorationactivity_04))); + tabInfoList.add(new TabInfo(4, ResUtil.getString(R.string.decoration_view_mydecorationactivity_05))); + tabInfoList.add(new TabInfo(5, ResUtil.getString(R.string.decoration_view_mydecorationactivity_06))); + CommonNavigator commonNavigator = new CommonNavigator(this); + MyDecorationMagicIndicator indicator = new MyDecorationMagicIndicator(this, tabInfoList); + indicator.setOnItemSelectListener(this); + commonNavigator.setAdapter(indicator); + mMagicIndicator.setNavigator(commonNavigator); + + myHeadWearFragment = new MyHeadWearFragment(); + mMyCarFragment = MyCarFragment.instance(this); + mMyNamePlateFragment = new MyNamePlateFragment(); + mMyUserCardWearFragment = new MyUserCardWearFragment(); + mMyChatBubbleFragment = new MyChatBubbleFragment(); + viewPager.setAdapter(new FragmentStateAdapter(getSupportFragmentManager(), getLifecycle()) { + @Override + public int getItemCount() { + return tabInfoList.size(); + } + + @NonNull + @Override + public Fragment createFragment(int position) { + if (position == 0) { + return myHeadWearFragment; + } else if (position == 1) { + return mMyCarFragment; + } else if (position == 2) { + return mMyNamePlateFragment; + } + else if (position == 3) { + return mMyUserCardWearFragment; + } + return mMyChatBubbleFragment; + } + }); + viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() { + @Override + public void onPageSelected(int position) { + super.onPageSelected(position); + if (mMagicIndicator != null) { + mMagicIndicator.onPageSelected(position); +// if (position == 1) { +// mMagicIndicator.findViewById(R.id.car_badge_garage).setVisibility(View.GONE); +// } + } + } + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + super.onPageScrolled(position, positionOffset, positionOffsetPixels); + if (mMagicIndicator != null) { + mMagicIndicator.onPageScrolled(position, positionOffset, positionOffsetPixels); + } + } + + @Override + public void onPageScrollStateChanged(int state) { + super.onPageScrollStateChanged(state); + if (mMagicIndicator != null) { + mMagicIndicator.onPageScrollStateChanged(state); + } + } + }); + viewPager.setCurrentItem(mPosition); + } + + private void showCarDetail(CarInfo carInfo) { + DecorationDialogHelper.Options options = new DecorationDialogHelper.Builder() + .setType(DecorationSaleType.BUY_CAR) + .setDecoration(carInfo) + .setCustomSuccessCallback(true) + .create(); + DecorationDialogHelper helper = new DecorationDialogHelper(context, getDialogManager(), options); + helper.showBuyOrDonateDialog(); + helper.setOnOpDecorationListener(new DecorationDialogHelper.OnOpDecorationListener() { + @Override + public void onBuyCarSuccess() { + super.onBuyCarSuccess(); + // 更新车库中这辆车的使用日期 + if (mMyCarFragment != null && mMyCarFragment.getAdapter() != null) + mMyCarFragment.getAdapter().setCarInfoHasBeenRenew(carInfo); + // 更新商店这辆车的数据 + if (myHeadWearFragment != null && myHeadWearFragment.getShopAdapter() != null) + // 提示是否需要立即驾驶 + getDialogManager().showOkCancelDialog(ResUtil.getString(R.string.decoration_view_mydecorationactivity_07), + true, + () -> CarModel.get().driveThisCar(carInfo.getCarId()) + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .subscribe((voidServiceResult, throwable1) -> { + if (voidServiceResult != null && voidServiceResult.isSuccess()) { + SingleToastUtil.showToastShort(ResUtil.getString(R.string.decoration_view_mydecorationactivity_08)); + // 实时更新座驾被选中 + mMyCarFragment.getAdapter().check(carInfo); + } else if (voidServiceResult != null && !voidServiceResult.isSuccess()) { + SingleToastUtil.showToastShort(ResUtil.getString(R.string.decoration_view_mydecorationactivity_09)); + } else if (throwable1 != null) { + SingleToastUtil.showToastShort(ResUtil.getString(R.string.decoration_view_mydecorationactivity_010)); + } else { + SingleToastUtil.showToastShort(ResUtil.getString(R.string.decoration_view_mydecorationactivity_011)); + } + })); + } + }); + + } + + + private void initBanner(String BANNER_TYPE) { + GameHomeModel.get() + .getHomeBanner(BANNER_TYPE) + .compose(bindToLifecycle()) + .subscribe(new SingleObserver>() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onSuccess(List bannerList) { + if (MarketVerifyModel.get().isMarketChecking()) { + Iterator iterator = bannerList.iterator(); + while (iterator.hasNext()) { + BannerInfo bannerInfo = iterator.next(); + if (bannerInfo.getSkipType() == 2) { + iterator.remove(); + } + } + } + if (ListUtils.isListEmpty(bannerList)) { + mBinding.rollView.setVisibility(View.GONE); + return; + } + mBinding.rollView.setVisibility(View.VISIBLE); + ViewGroup.LayoutParams layoutParams = mBinding.rollView.getLayoutParams(); + int bannerWidth = UIUtil.getScreenWidth(context) - UIUtil.dip2px(context, 40); + layoutParams.width = bannerWidth; + layoutParams.height = bannerWidth * 90 / 345; + mBinding.rollView.setLayoutParams(layoutParams); + + mBinding.rollView.setHintView(new ColorPointHintView(context, Color.WHITE, context.getResources().getColor(R.color.color_66FFFFFF)) { + @Override + public Drawable makeFocusDrawable() { + GradientDrawable dotFocus = new GradientDrawable(); + dotFocus.setColor(Color.WHITE); + dotFocus.setCornerRadius(Util.dip2px(getContext(), 2)); + dotFocus.setSize(Util.dip2px(getContext(), 9), Util.dip2px(getContext(), 4)); + return dotFocus; + } + + @Override + public Drawable makeNormalDrawable() { + GradientDrawable dotNormal = new GradientDrawable(); + dotNormal.setColor(context.getResources().getColor(R.color.color_66FFFFFF)); + dotNormal.setCornerRadius(Util.dip2px(getContext(), 2)); + dotNormal.setSize(Util.dip2px(getContext(), 4), Util.dip2px(getContext(), 4)); + return dotNormal; + } + }); + + BannerAdapter bannerAdapter = new BannerAdapter(bannerList, context); + bannerAdapter.setRoundingRadius(ScreenUtil.dip2px(8)); + mBinding.rollView.setAdapter(bannerAdapter); + mBinding.rollView.setPlayDelay(3000); + //设置透明度 + mBinding.rollView.setAnimationDurtion(500); + mBinding.rollView.setVisibility(View.VISIBLE); + bannerAdapter.notifyDataSetChanged(); + } + + @Override + public void onError(Throwable e) { + LogUtil.e(e.getMessage()); + } + }); + } + + public void showDetail(CarInfo carInfo) { + showCarDetail(carInfo); + } + + public boolean getCarGarageNeedUpdate() { + boolean needUpdate = carGarageNeedUpdate; + carGarageNeedUpdate = false; + return needUpdate; + } + + @Override + public void onItemSelect(int position) { + viewPager.setCurrentItem(position); + } + + @Override + protected boolean needSteepStateBar() { + return true; + } + + @Override + protected void setStatusBar() { + super.setStatusBar(); + StatusBarUtil.transparencyBar(this); + StatusBarUtil.StatusBarLightMode(this); + } +} diff --git a/app/src/main/java/com/chwl/app/decoration/view/MyHeadWearFragment.java b/app/src/main/java/com/chwl/app/decoration/view/MyHeadWearFragment.java new file mode 100644 index 0000000..6fb0416 --- /dev/null +++ b/app/src/main/java/com/chwl/app/decoration/view/MyHeadWearFragment.java @@ -0,0 +1,160 @@ +package com.chwl.app.decoration.view; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.util.Log; +import android.view.View; + +import androidx.recyclerview.widget.LinearLayoutManager; + +import com.trello.rxlifecycle3.android.FragmentEvent; +import com.chwl.app.BR; +import com.chwl.app.R; +import com.chwl.app.base.BaseBindingFragment; +import com.chwl.app.common.NoDataFragment; +import com.chwl.app.databinding.FrgMyDecorationCommonBinding; +import com.chwl.app.decoration.adapter.MyHeadWearAdapter; +import com.chwl.app.decoration.helper.DecorationDialogHelper; +import com.chwl.app.decoration.helper.DecorationSaleType; +import com.chwl.app.decoration.viewmodel.HeadWearVm; +import com.chwl.core.decoration.headwear.bean.HeadWearInfo; +import com.chwl.core.user.UserModel; +import com.chwl.library.annatation.ActLayoutRes; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; + +import java.util.List; + +/** + * Created by huangmeng1 on 2018/5/7. + */ +@ActLayoutRes(R.layout.frg_my_decoration_common) +public class MyHeadWearFragment extends BaseBindingFragment { + private HeadWearVm headWearVm; + private MyHeadWearAdapter shopAdapter; + + public MyHeadWearAdapter getShopAdapter() { + return shopAdapter; + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + } + + @Override + public void initiate() { + headWearVm = new HeadWearVm(); + headWearVm.setMyHeadWear(true); + mBinding.setViewmodel(headWearVm); + + shopAdapter = new MyHeadWearAdapter(R.layout.item_my_head_wear, BR.headWearInfo); + shopAdapter.setOnItemChildClickListener((adapter, view, position) -> { + + switch (view.getId()) { + case R.id.tv_used: + setUsedStatus(position); + break; + } + }); + + mBinding.swipeRefresh.setOnRefreshListener(() -> loadData()); + + mBinding.recyclerView.setAdapter(shopAdapter); + mBinding.recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); + + loadData(); + } + + private void loadData() { + headWearVm.loadData(false).compose(bindToLifecycle()) + .doAfterTerminate(() -> { + if (ListUtils.isListEmpty(shopAdapter.getData())) { + showNoData(R.drawable.icon_common_failure, ResUtil.getString(R.string.decoration_view_myheadwearfragment_01)); + } + + List list = shopAdapter.getData(); + + for (HeadWearInfo item : list) { + if (item.getHeadwearId() == 0) { + list.remove(item); + break; + } + } + + shopAdapter.notifyDataSetChanged(); + }) + .subscribe(); + } + + @Override + public void showNoData(View view, int drawable, CharSequence charSequence) { + if (!checkActivityValid()) + return; + + if (view == null) { + return; + } + View status = view.findViewById(R.id.status_layout); + if (status == null || status.getId() == View.NO_ID) { + return; + } + NoDataFragment fragment = NoDataFragment.newInstance(R.layout.fragment_no_data_large_iv, drawable, charSequence); + fragment.setListener(getLoadListener()); + getChildFragmentManager().beginTransaction().replace(status.getId(), fragment, STATUS_TAG).commitAllowingStateLoss(); + } + + @SuppressLint("CheckResult") + private void setUsedStatus(int position) { + HeadWearInfo headWearInfo = shopAdapter.getData().get(position); + + Log.i("MyHeadWearFragment", "name:" + headWearInfo.getHeadwearName()); + + // id == 0标识不使用头饰 + final int id = headWearInfo.isUsed() ? 0 : headWearInfo.getHeadwearId(); + + headWearVm.userHeadWear(String.valueOf(id)) + .compose(bindUntilEvent(FragmentEvent.DESTROY)) + .doOnError(throwable -> { + toast(throwable.getMessage()); + }) + .subscribe(s -> { + for (int i = 0; i < shopAdapter.getData().size(); i++) { + if (id == shopAdapter.getData().get(i).getHeadwearId()) { + shopAdapter.getData().get(i).setUsed(true); + } else { + shopAdapter.getData().get(i).setUsed(false); + } + } + shopAdapter.notifyDataSetChanged(); + //更新用户信息 + UserModel.get().updateCurrentUserInfo().subscribe(); + }); + } + + private void showSureDialog(int position) { + HeadWearInfo wearInfo = shopAdapter.getItem(position); + if (wearInfo == null) { + return; + } + DecorationDialogHelper.Options options = new DecorationDialogHelper.Builder() + .setDecoration(wearInfo) + .setType(DecorationSaleType.BUY_HEAD_WEAR) + .create(); + DecorationDialogHelper helper = new DecorationDialogHelper(mContext, getDialogManager(), options); + helper.showBuyOrDonateDialog(); + helper.setOnOpDecorationListener(new DecorationDialogHelper.OnOpDecorationListener() { + @Override + public void onBuyHeadwearSuccess() { + if (wearInfo.getExpireDays() > 0) { + wearInfo.setExpireDays(wearInfo.getExpireDays() + wearInfo.getDays()); + } else { + wearInfo.setExpireDays(wearInfo.getDays()); + } + wearInfo.setStatus(HeadWearInfo.STATUS_IN_USED); + shopAdapter.getData().set(position, wearInfo); + shopAdapter.notifyItemChanged(position); + } + }); + } +} diff --git a/app/src/main/java/com/chwl/app/decoration/view/MyNamePlateFragment.java b/app/src/main/java/com/chwl/app/decoration/view/MyNamePlateFragment.java new file mode 100644 index 0000000..c6ca578 --- /dev/null +++ b/app/src/main/java/com/chwl/app/decoration/view/MyNamePlateFragment.java @@ -0,0 +1,156 @@ +package com.chwl.app.decoration.view; + +import android.annotation.SuppressLint; +import android.os.Bundle; +import android.view.View; + +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import com.trello.rxlifecycle3.android.FragmentEvent; +import com.chwl.app.R; +import com.chwl.app.base.BaseFragment; +import com.chwl.app.common.NoDataFragment; +import com.chwl.app.decoration.adapter.MyNamePlateAdapter; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.decoration.nameplate.NamePlateModel; +import com.chwl.core.decoration.nameplate.bean.NamePlateInfo; +import com.chwl.core.user.UserModel; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; + +import java.util.List; + +/** + * Created by yudi + * on 2018/3/2. + */ + + +public class MyNamePlateFragment extends BaseFragment { + + private MyNamePlateAdapter mNamePlateAdapter; + private RecyclerView recyclerView; + private SwipeRefreshLayout swipeRefresh; + + @Override + public int getRootLayoutId() { + return R.layout.frg_my_nameplate_common; + } + + + @Override + public void onFindViews() { + recyclerView = mView.findViewById(R.id.recycler_view); + swipeRefresh = mView.findViewById(R.id.swipe_refresh); + } + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + } + + @Override + public void onSetListener() { + } + + @Override + public void initiate() { + initRecyclerView(); + initSwipRefresh(); + loadData(); + } + + private void initSwipRefresh() { + swipeRefresh.setOnRefreshListener(() -> loadData()); + } + + public MyNamePlateAdapter getAdapter() { + return mNamePlateAdapter; + } + + private boolean isLoading = false; + + @SuppressLint("CheckResult") + private void loadData() { + if (isLoading) { + return; + } + isLoading = true; + NamePlateModel.get().getNamePlateList(AuthModel.get().getCurrentUid()) + .subscribe((serviceResult, throwable) -> { + if (throwable != null) { + + } else { + List info = serviceResult.getNameplateList(); + if (ListUtils.isListEmpty(info)) { + showNoData(R.drawable.icon_common_failure, ResUtil.getString(R.string.decoration_view_mynameplatefragment_01)); + return; + } + + mNamePlateAdapter.setNewData(info); + mNamePlateAdapter.notifyDataSetChanged(); + swipeRefresh.setRefreshing(false); + isLoading = false; + } + }); + } + + private void initRecyclerView() { + recyclerView.setLayoutManager(new LinearLayoutManager(mContext)); + mNamePlateAdapter = new MyNamePlateAdapter(); + mNamePlateAdapter.setOnItemChildClickListener((adapter, view, position) -> { + if (view.getId() == R.id.tv_used) { + setUsedStatus(position); + } + }); + recyclerView.setAdapter(mNamePlateAdapter); + } + + @SuppressLint("CheckResult") + private void setUsedStatus(int position) { + NamePlateInfo.NameplateListBean nameplateInfo = mNamePlateAdapter.getData().get(position); + // id == 0标识不使用头饰 + final int id = nameplateInfo.isUsing() ? 0 : nameplateInfo.getId(); + final String word = nameplateInfo.getWord(); + + NamePlateModel.get().useMyNamePlate(String.valueOf(id), word) + .compose(bindUntilEvent(FragmentEvent.DESTROY)) + .doOnError(throwable -> { + toast(throwable.getMessage()); + }) + .subscribe(s -> { + for (int i = 0; i < mNamePlateAdapter.getData().size(); i++) { + if (id == mNamePlateAdapter.getData().get(i).getId()) { + mNamePlateAdapter.getData().get(i).setUsing(true); + } else { + mNamePlateAdapter.getData().get(i).setUsing(false); + } + } + mNamePlateAdapter.notifyDataSetChanged(); + //更新用户信息 + UserModel.get().updateCurrentUserInfo().subscribe(); + }); + } + + @Override + public void showNoData(View view, int drawable, CharSequence charSequence) { + if (!checkActivityValid()) + return; + + if (view == null) { + return; + } + View status = view.findViewById(R.id.status_layout); + if (status == null || status.getId() == View.NO_ID) { + return; + } + NoDataFragment fragment = NoDataFragment.newInstance(R.layout.fragment_no_data_middle_iv, drawable, charSequence); + fragment.setListener(getLoadListener()); + getChildFragmentManager().beginTransaction().replace(status.getId(), fragment, STATUS_TAG).commitAllowingStateLoss(); + } + +} diff --git a/app/src/main/java/com/chwl/app/decoration/view/MyUserCardWearFragment.java b/app/src/main/java/com/chwl/app/decoration/view/MyUserCardWearFragment.java new file mode 100644 index 0000000..9d8527e --- /dev/null +++ b/app/src/main/java/com/chwl/app/decoration/view/MyUserCardWearFragment.java @@ -0,0 +1,110 @@ +package com.chwl.app.decoration.view; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.view.View; + +import androidx.recyclerview.widget.LinearLayoutManager; + +import com.trello.rxlifecycle3.android.FragmentEvent; +import com.chwl.app.BR; +import com.chwl.app.R; +import com.chwl.app.base.BaseBindingFragment; +import com.chwl.app.common.NoDataFragment; +import com.chwl.app.databinding.FrgMyDecorationCommonBinding; +import com.chwl.app.decoration.adapter.MyUserCardWearAdapter; +import com.chwl.app.decoration.viewmodel.UserCardWearVm; +import com.chwl.core.decoration.headwear.bean.UserCardWearInfo; +import com.chwl.core.user.UserModel; +import com.chwl.library.annatation.ActLayoutRes; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; + +import java.util.Objects; + +/** + * Created by huangmeng1 on 2018/5/7. + */ +@ActLayoutRes(R.layout.frg_my_decoration_common) +public class MyUserCardWearFragment extends BaseBindingFragment { + private UserCardWearVm wearVm; + private MyUserCardWearAdapter shopAdapter; + + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + } + + @Override + public void initiate() { + wearVm = new UserCardWearVm(); + mBinding.setViewmodel(wearVm); + + shopAdapter = new MyUserCardWearAdapter(R.layout.item_my_user_card_wear, BR.headWearInfo); + shopAdapter.setOnItemChildClickListener((adapter, view, position) -> { + if (view.getId() == R.id.tv_used) { + setUsedStatus(position); + } + }); + + mBinding.swipeRefresh.setOnRefreshListener(() -> loadData(false)); + shopAdapter.setOnLoadMoreListener(() -> loadData(true), mBinding.recyclerView); + mBinding.recyclerView.setAdapter(shopAdapter); + mBinding.recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); + + loadData(false); + } + + private void loadData(boolean isLode) { + wearVm.loadData(isLode) + .compose(bindToLifecycle()) + .doAfterTerminate(() -> { + if (ListUtils.isListEmpty(shopAdapter.getData())) { + showNoData(R.drawable.icon_common_failure, ResUtil.getString(R.string.decoration_view_myusercardwearfragment_01)); + } + }) + .subscribe(); + } + + @Override + public void showNoData(View view, int drawable, CharSequence charSequence) { + if (!checkActivityValid()) + return; + + if (view == null) { + return; + } + View status = view.findViewById(R.id.status_layout); + if (status == null || status.getId() == View.NO_ID) { + return; + } + NoDataFragment fragment = NoDataFragment.newInstance(R.layout.fragment_no_data_large_iv, drawable, charSequence); + fragment.setListener(getLoadListener()); + getChildFragmentManager().beginTransaction().replace(status.getId(), fragment, STATUS_TAG).commitAllowingStateLoss(); + } + + @SuppressLint("CheckResult") + private void setUsedStatus(int position) { + UserCardWearInfo headWearInfo = shopAdapter.getData().get(position); + + // id == 0标识不使用头饰 + + String cardId = headWearInfo.isUsed() ? null : headWearInfo.getCardId(); + + wearVm.userHeadWear(cardId) + .compose(bindUntilEvent(FragmentEvent.DESTROY)) + .doOnError(throwable -> { + toast(throwable.getMessage()); + }) + .subscribe(s -> { + for (int i = 0; i < shopAdapter.getData().size(); i++) { + shopAdapter.getData().get(i).setUsed(Objects.equals(cardId,shopAdapter.getData().get(i).getCardId())); + } + shopAdapter.notifyDataSetChanged(); + //更新用户信息 + UserModel.get().updateCurrentUserInfo().subscribe(); + }); + } + +} diff --git a/app/src/main/java/com/chwl/app/decoration/view/widgets/BadgeScaleTransitionPagerTitleView.java b/app/src/main/java/com/chwl/app/decoration/view/widgets/BadgeScaleTransitionPagerTitleView.java new file mode 100644 index 0000000..38942de --- /dev/null +++ b/app/src/main/java/com/chwl/app/decoration/view/widgets/BadgeScaleTransitionPagerTitleView.java @@ -0,0 +1,97 @@ +package com.chwl.app.decoration.view.widgets; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.widget.RelativeLayout; + +import com.chwl.app.R; +import com.chwl.app.ui.widget.XRecyclerView.ScaleTransitionPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerTitleView; + + +/** + * 带颜色渐变和缩放的指示器标题 + * 博客: http://hackware.lucode.net + * + * @author hackware + * @date 2016/6/26 + */ +public class BadgeScaleTransitionPagerTitleView extends RelativeLayout implements IPagerTitleView { + private ScaleTransitionPagerTitleView mPagerTitleView; + private Context mContext; + private View mBadge; + + public BadgeScaleTransitionPagerTitleView(Context context) { + this(context, null); + } + + public BadgeScaleTransitionPagerTitleView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public BadgeScaleTransitionPagerTitleView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context); + } + + private void init(Context context) { + this.mContext = context; + mPagerTitleView = new ScaleTransitionPagerTitleView(context); + mBadge = new View(context); + mBadge.setBackground(context.getResources().getDrawable(R.drawable.bg_car_tab_badge)); + LayoutParams params = new LayoutParams(20, 20); + params.addRule(ALIGN_RIGHT, R.id.car_indicator); + params.leftMargin = 10; + params.addRule(CENTER_VERTICAL, 1); + mBadge.setLayoutParams(params); + mBadge.setId(R.id.car_badge); + mBadge.setVisibility(GONE); + addView(mBadge); + LayoutParams params1 = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + params1.addRule(CENTER_IN_PARENT); + mPagerTitleView.setLayoutParams(params1); + mPagerTitleView.setId(R.id.car_indicator); + addView(mPagerTitleView); + } + + @Override + public void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight) { + mPagerTitleView.onEnter(index, totalCount, enterPercent, leftToRight); + } + + @Override + public void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight) { + mPagerTitleView.onLeave(index, totalCount, leavePercent, leftToRight); + } + + @Override + public void onSelected(int index, int totalCount) { + mPagerTitleView.onSelected(index, totalCount); + } + + @Override + public void onDeselected(int index, int totalCount) { + mPagerTitleView.onDeselected(index, totalCount); + } + + public void setMinScale(float minScale) { + mPagerTitleView.setMinScale(minScale); + } + + public void setNormalColor(int color) { + mPagerTitleView.setNormalColor(color); + } + + public void setSelectedColor(int color) { + mPagerTitleView.setSelectedColor(color); + } + + public void setTextSize(float size) { + mPagerTitleView.setTextSize(size); + } + + public void setText(String text) { + mPagerTitleView.setText(text); + } +} diff --git a/app/src/main/java/com/chwl/app/decoration/view/widgets/CarMagicIndicator.java b/app/src/main/java/com/chwl/app/decoration/view/widgets/CarMagicIndicator.java new file mode 100644 index 0000000..81ec83d --- /dev/null +++ b/app/src/main/java/com/chwl/app/decoration/view/widgets/CarMagicIndicator.java @@ -0,0 +1,73 @@ +package com.chwl.app.decoration.view.widgets; + +import android.content.Context; + +import androidx.core.content.ContextCompat; + +import com.chwl.app.R; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.CommonNavigatorAdapter; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerTitleView; +import com.chwl.core.home.bean.TabInfo; +import com.chwl.library.utils.ResUtil; + +import java.util.List; + +/** + *

公共多个滑动tab样式

+ * + * @author Administrator + * @date 2017/11/15 + */ +public class CarMagicIndicator extends CommonNavigatorAdapter { + + private Context mContext; + private List mTitleList; + private int mBottomMargin; + + public CarMagicIndicator(Context context, List titleList, int bottomMargin) { + mContext = context; + mTitleList = titleList; + mBottomMargin = bottomMargin; + } + + @Override + public int getCount() { + return mTitleList == null ? 0 : mTitleList.size(); + } + + @Override + public IPagerTitleView getTitleView(Context context, final int i) { + BadgeScaleTransitionPagerTitleView scaleTransitionPagerTitleView = new BadgeScaleTransitionPagerTitleView(context); + scaleTransitionPagerTitleView.setNormalColor(ContextCompat.getColor(mContext, R.color.text_secondary_4f516a)); + scaleTransitionPagerTitleView.setSelectedColor(ContextCompat.getColor(mContext, R.color.text_title_color)); + scaleTransitionPagerTitleView.setMinScale(1); + scaleTransitionPagerTitleView.setTextSize(16); + scaleTransitionPagerTitleView.setText(mTitleList.get(i).getName()); + if (mTitleList.get(i).getName().equals(ResUtil.getString(R.string.view_widgets_carmagicindicator_01))) { + scaleTransitionPagerTitleView.findViewById(R.id.car_badge).setId(R.id.car_badge_garage); + } + scaleTransitionPagerTitleView.setOnClickListener(view -> { + if (mOnItemSelectListener != null) { + mOnItemSelectListener.onItemSelect(i); + } + }); + return scaleTransitionPagerTitleView; + } + + + @Override + public IPagerIndicator getIndicator(Context context) { + return null; + } + + private OnItemSelectListener mOnItemSelectListener; + + public void setOnItemSelectListener(OnItemSelectListener onItemSelectListener) { + mOnItemSelectListener = onItemSelectListener; + } + + public interface OnItemSelectListener { + void onItemSelect(int position); + } +} diff --git a/app/src/main/java/com/chwl/app/decoration/view/widgets/MyDecorationMagicIndicator.java b/app/src/main/java/com/chwl/app/decoration/view/widgets/MyDecorationMagicIndicator.java new file mode 100644 index 0000000..a7da8f4 --- /dev/null +++ b/app/src/main/java/com/chwl/app/decoration/view/widgets/MyDecorationMagicIndicator.java @@ -0,0 +1,77 @@ +package com.chwl.app.decoration.view.widgets; + +import android.content.Context; + +import androidx.core.content.ContextCompat; + +import com.chwl.app.R; +import com.chwl.app.ui.widget.XRecyclerView.ScaleTransitionPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.CommonNavigatorAdapter; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerTitleView; +import com.chwl.core.home.bean.TabInfo; +import com.chwl.library.utils.ResUtil; + +import java.util.List; + +/** + *

公共多个滑动tab样式

+ * + * @author Administrator + * @date 2017/11/15 + */ +public class MyDecorationMagicIndicator extends CommonNavigatorAdapter { + + private Context mContext; + private List mTitleList; + private OnItemSelectListener mOnItemSelectListener; + + public MyDecorationMagicIndicator(Context context, List titleList) { + mContext = context; + mTitleList = titleList; + } + + @Override + public int getCount() { + return mTitleList == null ? 0 : mTitleList.size(); + } + + @Override + public IPagerTitleView getTitleView(Context context, final int i) { + ScaleTransitionPagerTitleView scaleTransitionPagerTitleView = new ScaleTransitionPagerTitleView(context); + scaleTransitionPagerTitleView.setNormalColor(ContextCompat.getColor(mContext, R.color.text_secondary_4f516a)); + scaleTransitionPagerTitleView.setSelectedColor(ContextCompat.getColor(mContext, R.color.text_title_color)); + scaleTransitionPagerTitleView.setMinScale(0.9f); + scaleTransitionPagerTitleView.setTextSize(15); + scaleTransitionPagerTitleView.setText(mTitleList.get(i).getName()); +// if (mTitleList.get(i).getName().equals(ResUtil.getString(R.string.view_widgets_mydecorationmagicindicator_01))) { +// scaleTransitionPagerTitleView.findViewById(R.id.car_badge).setId(R.id.car_badge_garage); +// } + scaleTransitionPagerTitleView.setOnClickListener(view -> { + if (mOnItemSelectListener != null) { + mOnItemSelectListener.onItemSelect(i); + } + }); + return scaleTransitionPagerTitleView; + } + + @Override + public float getTitleWeight(Context context, int index) { + if (index == 3) return 1.2f; + if (index == 4) return 1.5f; + return super.getTitleWeight(context, index); + } + + @Override + public IPagerIndicator getIndicator(Context context) { + return null; + } + + public void setOnItemSelectListener(OnItemSelectListener onItemSelectListener) { + mOnItemSelectListener = onItemSelectListener; + } + + public interface OnItemSelectListener { + void onItemSelect(int position); + } +} diff --git a/app/src/main/java/com/chwl/app/decoration/viewmodel/CarShopVm.java b/app/src/main/java/com/chwl/app/decoration/viewmodel/CarShopVm.java new file mode 100644 index 0000000..b12c549 --- /dev/null +++ b/app/src/main/java/com/chwl/app/decoration/viewmodel/CarShopVm.java @@ -0,0 +1,28 @@ +package com.chwl.app.decoration.viewmodel; + +import com.chwl.app.base.BaseListViewModel; +import com.chwl.core.bean.response.ServiceResult; +import com.chwl.core.decoration.car.CarModel; +import com.chwl.core.decoration.car.bean.CarInfo; + +import java.util.List; + +import io.reactivex.Single; + +/** + * Created by huangmeng1 on 2018/5/9. + */ + +public class CarShopVm extends BaseListViewModel { + + private String uid; + public void setUid(String uid) { + this.uid = uid; + } + + @Override + public Single>> getSingle() { + return CarModel.get() + .getStoreCarsV2(Long.parseLong(uid), String.valueOf(page), String.valueOf(pageSize)); + } +} diff --git a/app/src/main/java/com/chwl/app/decoration/viewmodel/DecorationViewModel.kt b/app/src/main/java/com/chwl/app/decoration/viewmodel/DecorationViewModel.kt new file mode 100644 index 0000000..e7785e3 --- /dev/null +++ b/app/src/main/java/com/chwl/app/decoration/viewmodel/DecorationViewModel.kt @@ -0,0 +1,56 @@ +package com.chwl.app.decoration.viewmodel + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import com.chwl.app.R +import com.chwl.app.base.BaseViewModel +import com.chwl.core.bean.response.ListResult +import com.chwl.core.decoration.DecorationModel +import com.chwl.core.decoration.bean.DecorationInfo +import com.chwl.core.home.bean.BannerInfo +import com.chwl.core.home.model.HomeModel +import com.chwl.core.utils.extension.toast +import com.chwl.library.utils.ResUtil + +class DecorationViewModel : BaseViewModel() { + + private val BANNER_TYPE = "3" + + private val _bannerLiveData = MutableLiveData?>() + val bannerLiveData: MutableLiveData?> = _bannerLiveData + + private val _decorationInfoListLiveData = MutableLiveData>() + val decorationInfoListLiveData: LiveData> = + _decorationInfoListLiveData + + + + fun getBannerInfo() { + safeLaunch( + block = { + _bannerLiveData.value = HomeModel.getHomeBanner(BANNER_TYPE) + } + ) + } + + fun getDecorationInfoList(dressType: Int) { + safeLaunch( + block = { + _decorationInfoListLiveData.value = + ListResult.success(DecorationModel.getDecorationInfoList(dressType), 1) + } + ) + } + + fun buyDecoration(dressType: Int, dressId: Int) { + safeLaunch( + true, + block = { + DecorationModel.buyDecoration(dressType, dressId) + ResUtil.getString(R.string.decoration_viewmodel_decorationviewmodel_01).toast() + } + ) + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/decoration/viewmodel/HeadWearVm.java b/app/src/main/java/com/chwl/app/decoration/viewmodel/HeadWearVm.java new file mode 100644 index 0000000..6e1291f --- /dev/null +++ b/app/src/main/java/com/chwl/app/decoration/viewmodel/HeadWearVm.java @@ -0,0 +1,44 @@ +package com.chwl.app.decoration.viewmodel; + +import com.chwl.app.base.BaseListViewModel; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.bean.response.ServiceResult; +import com.chwl.core.decoration.headwear.HeadwearModel; +import com.chwl.core.decoration.headwear.bean.HeadWearInfo; + +import java.util.List; + +import io.reactivex.Single; + +/** + * Created by huangmeng1 on 2018/5/10. + */ + +public class HeadWearVm extends BaseListViewModel { + private boolean isMyHeadWear; + private String uid; + + public void setUid(String uid) { + this.uid = uid; + } + + public void setMyHeadWear(boolean myHeadWear) { + isMyHeadWear = myHeadWear; + } + + public HeadWearVm() { + } + + @Override + public Single>> getSingle() { + if (isMyHeadWear) { + return HeadwearModel.get().getHeadWearListV2(AuthModel.get().getCurrentUid()); + } + return HeadwearModel.get().getStoreHeadWearListV2(Long.parseLong(uid), page + "", pageSize + ""); + } + + public Single userHeadWear(String headWearId) { + return HeadwearModel.get().userMyHeadWear(headWearId); + } + +} diff --git a/app/src/main/java/com/chwl/app/decoration/viewmodel/MyCarVm.java b/app/src/main/java/com/chwl/app/decoration/viewmodel/MyCarVm.java new file mode 100644 index 0000000..6e4850a --- /dev/null +++ b/app/src/main/java/com/chwl/app/decoration/viewmodel/MyCarVm.java @@ -0,0 +1,26 @@ +package com.chwl.app.decoration.viewmodel; + +import com.chwl.app.base.BaseListViewModel; +import com.chwl.core.bean.response.ServiceResult; +import com.chwl.core.decoration.car.CarModel; +import com.chwl.core.decoration.car.bean.CarInfo; + +import java.util.List; + +import io.reactivex.Single; + +public class MyCarVm extends BaseListViewModel { + private String uid; + + public void setUid(String uid) { + this.uid = uid; + } + + public MyCarVm() { + } + + @Override + public Single>> getSingle() { + return CarModel.get().getMyCars(); + } +} diff --git a/app/src/main/java/com/chwl/app/decoration/viewmodel/UserCardWearVm.java b/app/src/main/java/com/chwl/app/decoration/viewmodel/UserCardWearVm.java new file mode 100644 index 0000000..c9b2e83 --- /dev/null +++ b/app/src/main/java/com/chwl/app/decoration/viewmodel/UserCardWearVm.java @@ -0,0 +1,27 @@ +package com.chwl.app.decoration.viewmodel; + +import com.chwl.app.base.BaseListViewModel; +import com.chwl.core.bean.response.ServiceResult; +import com.chwl.core.decoration.headwear.HeadwearModel; +import com.chwl.core.decoration.headwear.bean.UserCardWearInfo; + +import java.util.List; + +import io.reactivex.Single; + +/** + * Created by huangmeng1 on 2018/5/10. + */ + +public class UserCardWearVm extends BaseListViewModel { + + @Override + public Single>> getSingle() { + return HeadwearModel.get().getUserCardWearList(page, pageSize); + } + + public Single userHeadWear(String wearId) { + return HeadwearModel.get().useUserCardWear(wearId); + } + +} diff --git a/app/src/main/java/com/chwl/app/decoration/viewmodel/UserChatBubbleVm.java b/app/src/main/java/com/chwl/app/decoration/viewmodel/UserChatBubbleVm.java new file mode 100644 index 0000000..5c84d31 --- /dev/null +++ b/app/src/main/java/com/chwl/app/decoration/viewmodel/UserChatBubbleVm.java @@ -0,0 +1,27 @@ +package com.chwl.app.decoration.viewmodel; + +import com.chwl.app.base.BaseListViewModel; +import com.chwl.core.bean.response.ServiceResult; +import com.chwl.core.decoration.headwear.HeadwearModel; +import com.chwl.core.decoration.headwear.bean.ChatBubbleInfo; + +import java.util.List; + +import io.reactivex.Single; + +/** + * Created by huangmeng1 on 2018/5/10. + */ + +public class UserChatBubbleVm extends BaseListViewModel { + + @Override + public Single>> getSingle() { + return HeadwearModel.get().getChatBubbleInfoList(page, pageSize); + } + + public Single userChatBubble(String wearId) { + return HeadwearModel.get().userChatBubble(wearId); + } + +} diff --git a/app/src/main/java/com/chwl/app/earn/EarnRecordViewModel.kt b/app/src/main/java/com/chwl/app/earn/EarnRecordViewModel.kt new file mode 100644 index 0000000..293bb65 --- /dev/null +++ b/app/src/main/java/com/chwl/app/earn/EarnRecordViewModel.kt @@ -0,0 +1,176 @@ +package com.chwl.app.earn + +import androidx.lifecycle.MutableLiveData +import com.chwl.app.base.BaseViewModel +import com.chwl.core.earn.bean.* +import com.chwl.core.earn.model.EarnModel +import com.chwl.core.pay.PayModel +import com.chwl.library.utils.TimeUtils +import java.util.* + +class EarnRecordViewModel : BaseViewModel() { + + //是否个播 + private val _queryRoomTypeLiveData = MutableLiveData() + val queryRoomTypeLiveData: MutableLiveData = _queryRoomTypeLiveData + + //收益记录 + private val _earnRecordLiveData = MutableLiveData() + val earnRecordLiveData: MutableLiveData = _earnRecordLiveData + + //金币兑换钻石 + private val _goldToDiamondLiveData = MutableLiveData() + val goldToDiamondLiveData: MutableLiveData = _goldToDiamondLiveData + + //金币兑换钻石-确认 + private val _exchangeConfirmLiveData = MutableLiveData() + val exchangeConfirmLiveData: MutableLiveData = _exchangeConfirmLiveData + + + + + private val _boundLiveData = MutableLiveData() + val boundLiveData: MutableLiveData = _boundLiveData + + //结算明细 + private val _memberSettleLiveData = MutableLiveData() + val memberSettleLiveData: MutableLiveData = + _memberSettleLiveData + + //金幣明細 + private val _goldRecordLiveData = MutableLiveData() + val goldRecordLiveData: MutableLiveData = + _goldRecordLiveData + + private var weekFirstDay: String = "" + private var weekLastDay: String = "" + + /** + * 周范围内选中的日期 + */ + private var mWeekChooseDay: Long = 0 + + fun initCurrentDay() { + mWeekChooseDay = System.currentTimeMillis() + val calendar = Calendar.getInstance() + calendar.timeInMillis = mWeekChooseDay + val curWeekDay = calendar[Calendar.DAY_OF_WEEK] + //周一的时间 + val firstDayTime: Long = if (curWeekDay == 1) { //周日 + calendar.timeInMillis - TimeUtils.MILLIS_OF_A_DAY * (7 - curWeekDay) + } else { + calendar.timeInMillis - TimeUtils.MILLIS_OF_A_DAY * (curWeekDay - 2) + } + //周日 + val lastDayTime = firstDayTime + TimeUtils.MILLIS_OF_A_DAY * 6 + weekFirstDay = TimeUtils.getDateTimeString(firstDayTime, TimeUtils.DATE_FORMAT) + weekLastDay = TimeUtils.getDateTimeString(lastDayTime, TimeUtils.DATE_FORMAT) + } + + fun getWeekFirstDay(): String { + return weekFirstDay + } + + fun setWeekFirstDay(weekFirstDay: String) { + this.weekFirstDay = weekFirstDay + } + + fun getWeekLastDay(): String { + return weekLastDay + } + + fun setWeekLastDay(weekLastDay: String) { + this.weekLastDay = weekLastDay + } + + fun getmWeekChooseDay(): Long { + return mWeekChooseDay + } + + fun setmWeekChooseDay(weekChooseDay: Long) { + mWeekChooseDay = weekChooseDay + } + + /** + * 是否个播 + */ + fun queryWithRoomType() { + safeLaunch( + false, + block = { + _queryRoomTypeLiveData.value = EarnModel.queryWithRoomType() + } + ) + } + + /** + * 收益记录 + */ + fun getEarnRecordInfo() { + safeLaunch( + true, + block = { + _earnRecordLiveData.value = EarnModel.getEarnRecord() + } + ) + } + + /** + * 金币兑换钻石 + */ + fun getGoldToDiamondInfo() { + safeLaunch( + true, + block = { + _goldToDiamondLiveData.value = EarnModel.getGoldToDiamond() + } + ) + } + + /** + * 金币兑换钻石-确认 + */ + fun exchangeConfirm( + goldNum: Long, + diamondNum: Long, + currency: Int + ) { + safeLaunch( + true, + block = { + _exchangeConfirmLiveData.value = + EarnModel.exchangeConfirm(goldNum, diamondNum, currency) + PayModel.get().refreshWalletInfo(true) + } + ) + } + + + + + + /** + * 结算明细 + */ + fun getMemberSettlement(startTime: String, endTime: String) { + safeLaunch( + true, + block = { + _memberSettleLiveData.value = EarnModel.getMemberSettlement(startTime, endTime) + } + ) + } + + /** + * 结算明细 + */ + fun getHallMemberTotalList(startTime: String, endTime: String) { + safeLaunch( + true, + block = { + _goldRecordLiveData.value = EarnModel.getHallMemberTotalList(startTime, endTime) + } + ) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/earn/activity/ConvertDiamondActivity.kt b/app/src/main/java/com/chwl/app/earn/activity/ConvertDiamondActivity.kt new file mode 100644 index 0000000..390c63f --- /dev/null +++ b/app/src/main/java/com/chwl/app/earn/activity/ConvertDiamondActivity.kt @@ -0,0 +1,191 @@ +package com.chwl.app.earn.activity + +import android.content.Context +import android.content.Intent +import android.text.Editable +import android.text.TextWatcher +import androidx.activity.viewModels +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.databinding.ActivityConvertDiamondBinding +import com.chwl.app.earn.EarnRecordViewModel +import com.chwl.app.ui.widget.dialog.ExchangeDiamondTipDialog +import com.chwl.core.earn.bean.GoldToDiamondInfo +import com.chwl.library.common.util.DoubleUtils +import com.netease.nim.uikit.StatusBarUtil +import kotlin.math.ceil +import kotlin.math.floor + +/** + * author: wushaocheng + * time: 2022/11/18 + * desc: 兑换钻石 + */ +class ConvertDiamondActivity : BaseViewBindingActivity() { + + private val earnRecordModel: EarnRecordViewModel by viewModels() + + private var isGold = false + private var isDiamond = false + + companion object { + const val BEAN = "bean" + + @JvmStatic + fun start(context: Context, goldToDiamondInfo: GoldToDiamondInfo) { + val starter = Intent(context, ConvertDiamondActivity::class.java) + starter.putExtra(BEAN, goldToDiamondInfo) + context.startActivity(starter) + } + } + + override fun init() { + initTitleBar(getString(R.string.convert_diamond)) + val bean = intent.getSerializableExtra(BEAN) as? GoldToDiamondInfo + bean?.let { + binding.tvMyGold.text = getString(R.string.my_gold, it.golds?.toPlainString()) + binding.tvMyDiamond.text = getString(R.string.my_diamond, it.diamonds?.toPlainString()) + binding.edGold.setOnFocusChangeListener { view, b -> + isGold = b + } + binding.edDiamond.setOnFocusChangeListener { view, b -> + isDiamond = b + } + binding.edGold.addTextChangedListener(object : TextWatcher { + override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { + + } + + override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { + + } + + override fun afterTextChanged(s: Editable?) { + if (isGold) { + val goldText = s.toString() + if (goldText.isNotEmpty()) { + if ((goldText.toLong() % 1000) == 0L){ + binding.edDiamond.setText( + //去掉小数凑整:不论小数是多少,都不进位 + DoubleUtils.convertDoubleToString( + floor( + DoubleUtils.mul( + goldText.toDouble(), + it.rate + ) + ) + ) + ) + }else{ + binding.edDiamond.setText("") + } + } else { + binding.edDiamond.setText("") + } + } + binding.tvConvert.isEnabled = binding.edGold.text.toString().isNotEmpty() && binding.edDiamond.text.toString().isNotEmpty() + } + + }) + binding.edDiamond.addTextChangedListener(object : TextWatcher { + override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { + + } + + override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { + + } + + override fun afterTextChanged(s: Editable?) { + if (isDiamond) { + val diamondText = s.toString() + if (diamondText.isNotEmpty()) { + binding.edGold.setText( + //去掉小数凑整:不管小数是多少,都进一 + DoubleUtils.convertDoubleToString( + ceil( + DoubleUtils.div( + diamondText.toDouble(), + it.rate + ) + ) + ) + ) + } else { + binding.edGold.setText("") + } + } + binding.tvConvert.isEnabled = binding.edGold.text.toString() + .isNotEmpty() && binding.edDiamond.text.toString().isNotEmpty() + } + + }) + + earnRecordModel.loadingLiveData.observe(this) { loading -> + if (loading) dialogManager.showProgressDialog(this) + else dialogManager.dismissDialog() + } + + earnRecordModel.exchangeConfirmLiveData.observe(this) { + toast(getString(R.string.exchange_success)) + finish() + } + + binding.tvConvert.setOnClickListener { view -> + if (binding.edGold.text.toString().toLong() < it.minDiamonds) { + toast(getString(R.string.convert_diamonds_01).format(it.minDiamonds)) + } else if (binding.edGold.text.toString().toLong() > it.maxDiamonds) { + toast(getString(R.string.convert_diamonds_02).format(it.maxDiamonds)) + } else { + //去掉小数凑整:不管小数是多少,都进一 + val gold = DoubleUtils.convertDoubleToString( + ceil( + DoubleUtils.div( + binding.edDiamond.text.toString().toDouble(), + it.rate + ) + ) + ) + val tipDialog = ExchangeDiamondTipDialog(this@ConvertDiamondActivity) + tipDialog.setTvDiamond(binding.edDiamond.text.toString()) + tipDialog.setTvConsumeGold( + getString( + R.string.consume_gold_num, + gold + ) + ) + tipDialog.setOnActionListener( + object : ExchangeDiamondTipDialog.OnActionListener { + override fun onOk() { + if (isDiamond) { + earnRecordModel.exchangeConfirm( + gold.toLong(), + binding.edDiamond.text.toString().toLong(), + 1 + ) + } else if (isGold) { + earnRecordModel.exchangeConfirm( + gold.toLong(), + binding.edDiamond.text.toString().toLong(), + 3 + ) + } + } + } + ) + tipDialog.show() + } + } + + } + } + + override fun needSteepStateBar() = true + + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/earn/activity/EarnRecordActivity.kt b/app/src/main/java/com/chwl/app/earn/activity/EarnRecordActivity.kt new file mode 100644 index 0000000..ec2023b --- /dev/null +++ b/app/src/main/java/com/chwl/app/earn/activity/EarnRecordActivity.kt @@ -0,0 +1,116 @@ +package com.chwl.app.earn.activity + +import android.content.Context +import android.content.Intent +import android.view.View +import androidx.activity.viewModels +import androidx.core.content.ContextCompat +import com.netease.nim.uikit.StatusBarUtil +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.databinding.ActivityEarnRecordBinding +import com.chwl.app.earn.EarnRecordViewModel +import com.chwl.app.ui.pay.ChargeActivity +import com.chwl.app.ui.webview.CommonWebViewActivity +import com.chwl.core.UriProvider +import com.chwl.core.earn.bean.RoomTypeInfo + +/** + * author: wushaocheng + * time: 2022/11/18 + * desc: 收益记录 + */ +class EarnRecordActivity : BaseViewBindingActivity(), + View.OnClickListener { + + private val earnRecordModel: EarnRecordViewModel by viewModels() + private var roomTypeInfo: RoomTypeInfo ?= null + + companion object { + @JvmStatic + fun start(context: Context) { + val starter = Intent(context, EarnRecordActivity::class.java) + context.startActivity(starter) + } + } + + override fun init() { + initTitleBar(getString(R.string.me_gain_recording)) + initListener() + + earnRecordModel.loadingLiveData.observe(this) { + if (it) dialogManager.showProgressDialog(this) + else dialogManager.dismissDialog() + } + + earnRecordModel.goldToDiamondLiveData.observe(this) { + it?.let { + ConvertDiamondActivity.start(this, it) + } + } + + earnRecordModel.queryRoomTypeLiveData.observe(this) { + it?.let { + roomTypeInfo = it + binding.tvDiamondNum.text = String.format(it.diamonds.toString()) + binding.tvGoldNum.text = String.format(it.golds.toString()) + if (it.isClanElder) { + binding.csGoldBg.background = + ContextCompat.getDrawable(this, R.drawable.bg_earn_diamond) + } else { + binding.csGoldBg.background = + ContextCompat.getDrawable(this, R.drawable.bg_earn_diamond) + } + } + } + + } + + override fun onResume() { + super.onResume() + earnRecordModel.queryWithRoomType() + } + + fun initListener() { + binding.tvCharge.setOnClickListener(this) + binding.tvDiamondDetail.setOnClickListener(this) + binding.tvGoldDetail.setOnClickListener(this) + binding.tvConvertDiamond.setOnClickListener(this) + } + + override fun onClick(view: View?) { + when (view?.id) { + R.id.tvCharge -> {//充值 +// if (AppMetaDataUtil.getChannelID().equals(Constants.GOOGLE)) { + ChargeActivity.start(this) +// } else { +// CommonWebViewActivity.start( +// context, UriProvider.getOfficialPay( +// 4, +// DeviceUtil.getDeviceId(context) +// ) +// ) +// } + } + R.id.tvDiamondDetail -> {//钻石明细 + CommonWebViewActivity.start(context, UriProvider.getDiamondDetail()) + } + + R.id.tvGoldDetail -> {//金币明细 + CommonWebViewActivity.start(context, UriProvider.getGoldDetail()) + } + R.id.tvConvertDiamond -> {//兑换钻石 + earnRecordModel.getGoldToDiamondInfo() + } + } + } + + override fun needSteepStateBar() = true + + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/earn/activity/GoldDetailActivity.kt b/app/src/main/java/com/chwl/app/earn/activity/GoldDetailActivity.kt new file mode 100644 index 0000000..29ee6be --- /dev/null +++ b/app/src/main/java/com/chwl/app/earn/activity/GoldDetailActivity.kt @@ -0,0 +1,349 @@ +package com.chwl.app.earn.activity + +import android.content.Context +import android.content.Intent +import android.text.style.ForegroundColorSpan +import android.view.View +import androidx.activity.viewModels +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.LinearLayoutManager +import com.jzxiang.pickerview.data.Type +import com.netease.nim.uikit.StatusBarUtil +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.common.EmptyViewHelper +import com.chwl.app.databinding.ActivityGoldDetailBinding +import com.chwl.app.earn.EarnRecordViewModel +import com.chwl.app.earn.adapter.GoldDetailAdapter +import com.chwl.app.earn.adapter.GoldRoomAdapter +import com.chwl.app.module_hall.hall.view.dialog.TimePickerGoldDialog +import com.chwl.app.ui.utils.RVDelegate +import com.chwl.app.ui.widget.recyclerview.decoration.ColorDecoration +import com.chwl.app.utils.SpannableBuilder +import com.chwl.core.earn.bean.HallMemberGoldFlowInfo +import com.chwl.core.earn.bean.HallMemberGoldFlowTotalInfo +import com.chwl.library.utils.FormatUtils + +/** + * 金币明细 + */ +class GoldDetailActivity : BaseViewBindingActivity(), + TimePickerGoldDialog.TimePickerListener, View.OnClickListener { + + private val earnRecordModel: EarnRecordViewModel by viewModels() + + private val mGoldDetailAdapter: GoldDetailAdapter by lazy { GoldDetailAdapter() } + private val mGoldRoomAdapter: GoldRoomAdapter by lazy { GoldRoomAdapter() } + + private lateinit var rvDelegate: RVDelegate + + private var settlementList: Map? = null + + private var mDiamondArrow = false + private var mGoldArrow = false + + companion object { + + @JvmStatic + fun start(context: Context) { + val starter = Intent(context, GoldDetailActivity::class.java) + context.startActivity(starter) + } + } + + override fun init() { + initTitleBar(getString(R.string.gold_detail)) + initView() + initListener() + initModel() + } + + private fun initView() { + earnRecordModel.initCurrentDay() + rvDelegate = RVDelegate.Builder() + .setLayoutManager(LinearLayoutManager(context)) + .setRecyclerView(binding.mRecyclerView) + .setEmptyView( + EmptyViewHelper.createEmptyTextView( + context, + getString(R.string.empty_data) + ) + ) + .setAdapter(mGoldDetailAdapter) + .build() + + binding.mRecyclerViewRoom.adapter = mGoldRoomAdapter + binding.mRecyclerViewRoom.addItemDecoration( + ColorDecoration( + ContextCompat.getColor( + this, + R.color.color_F7F7F7 + ), 0, 2, false + ) + ) + } + + private fun initListener() { + + mGoldRoomAdapter.setOnItemSelectListener(object : GoldRoomAdapter.OnItemSelectListener { + override fun onItemSelect(position: Int) { + reverseStatus() + val settlementList: HallMemberGoldFlowTotalInfo? = + settlementList?.get(mGoldRoomAdapter.data[position].hallId) + mGoldDetailAdapter.setNewData(settlementList?.hallMember) + val text = SpannableBuilder() + .append( + getString(R.string.room_diamond_message), + ForegroundColorSpan( + ContextCompat.getColor( + context, + R.color.color_1F1A4E + ) + ) + ) + .append( + getString( + R.string.diamond_string, + FormatUtils.formatToShortDown(settlementList?.total ?: 0.0) + ), + ForegroundColorSpan( + ContextCompat.getColor( + context, + R.color.color_DE9F0C + ) + ) + ) + .append( + getString(R.string.diamond_name), + ForegroundColorSpan( + ContextCompat.getColor( + context, + R.color.color_1F1A4E + ) + ) + ) + binding.tvBottomMessage.text = text.build() + } + + }) + + binding.llDate.setOnClickListener(this) + binding.llDiamondArrow.setOnClickListener(this) + binding.tvDiamondArrow.setOnClickListener(this) + binding.llGoldArrow.setOnClickListener(this) + binding.tvGoldArrow.setOnClickListener(this) + + } + + override fun onClick(view: View?) { + when (view?.id) { + R.id.llDate -> { + val builder = TimePickerGoldDialog.Builder() + .setType(Type.YEAR_MONTH_DAY) + .setTitleStringId("") + .setThemeColor(ContextCompat.getColor(this, R.color.line_color)) + .setWheelItemTextNormalColor( + ContextCompat.getColor( + this, + R.color.timetimepicker_default_text_color + ) + ) + .setWheelItemTextSelectorColor( + ContextCompat.getColor( + this, + R.color.black + ) + ) // 根据上一次选中时间初始化日期控件 + .setCurrentMillseconds(earnRecordModel.getmWeekChooseDay()) + .setmIsWeek(true) + .setIsMonth(false) + + val dialog = builder.build() + dialog.setmTimePickerListener(this) + dialog.show(supportFragmentManager, "year_month_day") + } + R.id.tv_diamond_arrow, R.id.ll_diamond_arrow -> { + if (!mDiamondArrow) { + mDiamondArrow = true + binding.ivDiamondTop.setImageDrawable( + ContextCompat.getDrawable( + context, + R.mipmap.ic_arrow_black_top + ) + ) + binding.ivDiamondBottom.setImageDrawable( + ContextCompat.getDrawable( + context, + R.mipmap.ic_arrow_gray_bottom + ) + ) + val data = mGoldDetailAdapter.data + data.sortBy { it.giftDiamonds } + mGoldDetailAdapter.setNewData(data) + } else { + mDiamondArrow = false + binding.ivDiamondTop.setImageDrawable( + ContextCompat.getDrawable( + context, + R.mipmap.ic_arrow_gray_top + ) + ) + binding.ivDiamondBottom.setImageDrawable( + ContextCompat.getDrawable( + context, + R.mipmap.ic_arrow_black_bottom + ) + ) + val data = mGoldDetailAdapter.data + data.sortByDescending { it.giftDiamonds } + mGoldDetailAdapter.setNewData(data) + } + } + R.id.tv_gold_arrow, R.id.ll_gold_arrow -> { + if (!mGoldArrow) { + mGoldArrow = true + binding.ivGoldTop.setImageDrawable( + ContextCompat.getDrawable( + context, + R.mipmap.ic_arrow_black_top + ) + ) + binding.ivGoldDown.setImageDrawable( + ContextCompat.getDrawable( + context, + R.mipmap.ic_arrow_gray_bottom + ) + ) + val data = mGoldDetailAdapter.data + data.sortBy { it.remainGolds } + mGoldDetailAdapter.setNewData(data) + } else { + mGoldArrow = false + binding.ivGoldTop.setImageDrawable( + ContextCompat.getDrawable( + context, + R.mipmap.ic_arrow_gray_top + ) + ) + binding.ivGoldDown.setImageDrawable( + ContextCompat.getDrawable( + context, + R.mipmap.ic_arrow_black_bottom + ) + ) + val data = mGoldDetailAdapter.data + data.sortByDescending { it.remainGolds } + mGoldDetailAdapter.setNewData(data) + } + } + } + } + + private fun reverseStatus() { + mDiamondArrow = false + mGoldArrow = false + binding.ivDiamondTop.setImageDrawable( + ContextCompat.getDrawable( + context, + R.mipmap.ic_arrow_gray_top + ) + ) + binding.ivDiamondBottom.setImageDrawable( + ContextCompat.getDrawable( + context, + R.mipmap.ic_arrow_black_bottom + ) + ) + binding.ivGoldTop.setImageDrawable( + ContextCompat.getDrawable( + context, + R.mipmap.ic_arrow_gray_top + ) + ) + binding.ivGoldDown.setImageDrawable( + ContextCompat.getDrawable( + context, + R.mipmap.ic_arrow_black_bottom + ) + ) + } + + private fun initModel() { + getWeekIncomeTotal(earnRecordModel.getWeekFirstDay(), earnRecordModel.getWeekLastDay()) + + earnRecordModel.memberSettleLiveData.observe(this) { + it?.let { + binding.tvTotalGold.text = FormatUtils.formatToShortDown(it.totalRemainGolds) + binding.tvGuildRevenueGold.text = FormatUtils.formatToShortDown(it.totalEarnGolds) + binding.tvAllMemberGold.text = FormatUtils.formatToShortDown(it.totalGiftGolds) + binding.tvMemberExchangeGold.text = FormatUtils.formatToShortDown(it.totalExchangeGolds) + settlementList = it.hallMemberMap + mGoldRoomAdapter.setNewData(it.hallVoList) + if (it.hallVoList.isNotEmpty()) { + val settlementList: HallMemberGoldFlowTotalInfo? = + settlementList?.get(it.hallVoList[0].hallId) + rvDelegate.setNewData(settlementList?.hallMember) + val text = SpannableBuilder() + .append( + getString(R.string.room_diamond_message), + ForegroundColorSpan( + ContextCompat.getColor( + context, + R.color.color_1F1A4E + ) + ) + ) + .append( + getString( + R.string.diamond_string, + (settlementList?.total ?: 0).toString() + ), + ForegroundColorSpan( + ContextCompat.getColor( + context, + R.color.color_DE9F0C + ) + ) + ) + .append( + getString(R.string.diamond_name), + ForegroundColorSpan( + ContextCompat.getColor( + context, + R.color.color_1F1A4E + ) + ) + ) + binding.tvBottomMessage.text = text.build() + } + } + } + } + + override fun getTime(chooseTime: Long, weekFirstDay: String?, weekLastDay: String?) { + reverseStatus() + earnRecordModel.setmWeekChooseDay(chooseTime) + weekFirstDay?.let { earnRecordModel.setWeekFirstDay(it) } + weekLastDay?.let { earnRecordModel.setWeekLastDay(it) } + + if (weekFirstDay != null && weekLastDay != null) { + + getWeekIncomeTotal(weekFirstDay, weekLastDay) + } + } + + private fun getWeekIncomeTotal(startTimeStr: String, endTimeStr: String) { + binding.tvDateLeft.text = startTimeStr + binding.tvDateRight.text = endTimeStr + earnRecordModel.getMemberSettlement(startTimeStr, endTimeStr) + } + + override fun needSteepStateBar() = true + + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/earn/adapter/GoldDetailAdapter.kt b/app/src/main/java/com/chwl/app/earn/adapter/GoldDetailAdapter.kt new file mode 100644 index 0000000..a97faaf --- /dev/null +++ b/app/src/main/java/com/chwl/app/earn/adapter/GoldDetailAdapter.kt @@ -0,0 +1,26 @@ +package com.chwl.app.earn.adapter + +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.app.ui.utils.ImageLoadUtilsV2 +import com.chwl.core.earn.bean.HallMemberGoldFlowInfo +import com.chwl.library.utils.FormatUtils + +class GoldDetailAdapter : + BaseQuickAdapter(R.layout.item_gold_detail) { + + override fun convert(helper: BaseViewHolder, item: HallMemberGoldFlowInfo) { + helper.setText(R.id.tv_user_name, item.nick ?: "--") + .setText(R.id.tv_have_exchange, FormatUtils.formatToShortDown(item.giftGolds)) + .setText(R.id.tv_settlement, FormatUtils.formatToShortDown(item.remainGolds)) + .setText(R.id.tv_diamond_pay_record, FormatUtils.formatToShortDown(item.giftDiamonds)) + .setText( + R.id.tv_have_change, + mContext.getString(R.string.have_converted, FormatUtils.formatToShortDown(item.exchangeGolds)) + ) + ImageLoadUtils.loadAvatar(item.avatar,helper.getView(R.id.iv_user_avatar)) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/earn/adapter/GoldRecordAdapter.kt b/app/src/main/java/com/chwl/app/earn/adapter/GoldRecordAdapter.kt new file mode 100644 index 0000000..70368f2 --- /dev/null +++ b/app/src/main/java/com/chwl/app/earn/adapter/GoldRecordAdapter.kt @@ -0,0 +1,27 @@ +package com.chwl.app.earn.adapter + +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.app.ui.utils.ImageLoadUtilsV2 +import com.chwl.core.earn.bean.HallMemberGoldFlowInfo +import com.chwl.library.utils.FormatUtils + +class GoldRecordAdapter : + BaseQuickAdapter(R.layout.item_gold_record) { + + override fun convert(helper: BaseViewHolder, item: HallMemberGoldFlowInfo) { + helper.setText(R.id.tv_user_name, item.nick ?: "--") + .setText(R.id.tv_have_exchange, FormatUtils.formatToShortDown(item.giftGolds)) + .setText(R.id.tv_settlement, FormatUtils.formatToShortDown(item.remainGolds)) + .setText(R.id.tv_diamond_pay_record, FormatUtils.formatToShortDown(item.giftDiamonds)) + .setText( + R.id.tv_have_change, + mContext.getString(R.string.have_converted, FormatUtils.formatToShortDown(item.exchangeGolds)) + ) + .setText(R.id.tv_pos, (helper.layoutPosition + 1).toString()) + ImageLoadUtils.loadAvatar(item.avatar,helper.getView(R.id.iv_user_avatar)) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/earn/adapter/GoldRoomAdapter.kt b/app/src/main/java/com/chwl/app/earn/adapter/GoldRoomAdapter.kt new file mode 100644 index 0000000..972ee6f --- /dev/null +++ b/app/src/main/java/com/chwl/app/earn/adapter/GoldRoomAdapter.kt @@ -0,0 +1,45 @@ +package com.chwl.app.earn.adapter + +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.app.ui.utils.ImageLoadUtilsV2 +import com.chwl.core.earn.bean.HallVo + +class GoldRoomAdapter : BaseQuickAdapter(R.layout.item_gold_room) { + + //选择的位置 + var selPosition = 0 + //临时记录上次选择的位置 + var temp =-1 + + private var mOnItemSelectListener: OnItemSelectListener? = null + + override fun convert(helper: BaseViewHolder, item: HallVo) { + helper.setText(R.id.tv_content, item.hallName) + ImageLoadUtils.loadAvatar(item.ownerAvatar,helper.getView(R.id.iv_hall_avatar)) + + helper.itemView.isSelected = helper.layoutPosition==selPosition + + helper.itemView.setOnClickListener { + helper.itemView.isSelected =true + //将旧的位置保存下来,用于后面把旧的位置颜色变回来 + temp = selPosition + //设置新的位置 + selPosition = helper.layoutPosition + //更新旧位置 + notifyItemChanged(temp) + mOnItemSelectListener?.onItemSelect(helper.layoutPosition) + } + } + + fun setOnItemSelectListener(onItemSelectListener: OnItemSelectListener) { + mOnItemSelectListener = onItemSelectListener + } + + interface OnItemSelectListener { + fun onItemSelect(position: Int) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/event/ChargeEvent.java b/app/src/main/java/com/chwl/app/event/ChargeEvent.java new file mode 100644 index 0000000..10c7713 --- /dev/null +++ b/app/src/main/java/com/chwl/app/event/ChargeEvent.java @@ -0,0 +1,14 @@ +package com.chwl.app.event; + +public class ChargeEvent { + private String message; + + public ChargeEvent(String data) { + this.message = data; + } + + public String getMessage() { + return message; + } + +} diff --git a/app/src/main/java/com/chwl/app/event/DressUpEvent.java b/app/src/main/java/com/chwl/app/event/DressUpEvent.java new file mode 100644 index 0000000..9b40648 --- /dev/null +++ b/app/src/main/java/com/chwl/app/event/DressUpEvent.java @@ -0,0 +1,29 @@ +package com.chwl.app.event; + +import com.chwl.core.decoration.bean.DressUpInfo; + +import lombok.Data; + +@Data +public class DressUpEvent { + public int action; + public DressUpInfo data; + + public DressUpEvent() { + } + + public DressUpEvent(int action) { + this.action = action; + } + + public DressUpEvent(int action, DressUpInfo data) { + this.action = action; + this.data = data; + } + + public @interface Action{ + int Select = 1; + int Play = 2; + } + +} diff --git a/app/src/main/java/com/chwl/app/event/OpenRoomIntroEvent.java b/app/src/main/java/com/chwl/app/event/OpenRoomIntroEvent.java new file mode 100644 index 0000000..cff0e93 --- /dev/null +++ b/app/src/main/java/com/chwl/app/event/OpenRoomIntroEvent.java @@ -0,0 +1,4 @@ +package com.chwl.app.event; + +public class OpenRoomIntroEvent { +} diff --git a/app/src/main/java/com/chwl/app/fansteam/FansTeamJoinActivity.kt b/app/src/main/java/com/chwl/app/fansteam/FansTeamJoinActivity.kt new file mode 100644 index 0000000..6a038ec --- /dev/null +++ b/app/src/main/java/com/chwl/app/fansteam/FansTeamJoinActivity.kt @@ -0,0 +1,108 @@ +package com.chwl.app.fansteam + +import android.annotation.SuppressLint +import android.content.Context +import android.content.Intent +import android.view.Gravity +import android.view.WindowManager +import androidx.activity.viewModels +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.databinding.ActivityFansTeamJoinBinding +import com.chwl.app.ui.utils.load +import com.chwl.app.ui.webview.DialogWebViewActivity +import com.chwl.core.UriProvider +import com.chwl.core.gift.GiftModel +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.utils.extension.subAndReplaceDot +import com.chwl.core.utils.extension.toast +import com.chwl.core.utils.net.handleBeanData +import com.chwl.library.utils.ResUtil + +class FansTeamJoinActivity : BaseViewBindingActivity() { + + companion object { + @JvmStatic + fun start(context: Context) { + val starter = Intent(context, FansTeamJoinActivity::class.java) + context.startActivity(starter) + } + } + + private val fansTeamViewModel: FansTeamViewModel by viewModels() + + @SuppressLint("CheckResult", "SetTextI18n") + override fun init() { + window.setLayout( + WindowManager.LayoutParams.MATCH_PARENT, + WindowManager.LayoutParams.WRAP_CONTENT + ) + window.setGravity(Gravity.BOTTOM) + + binding.ivHelp.setOnClickListener { + DialogWebViewActivity.start(this, UriProvider.getFansTeamRuleUrl()) + } + + binding.llRank.setOnClickListener { + DialogWebViewActivity.start( + this, + UriProvider.getFansTeamRankUrl(AvRoomDataManager.get().roomUid) + ) + } + + fansTeamViewModel.loadTeamJoinInfo() + + fansTeamViewModel.fansTeamJoinInfoLiveData.observe(this) { + it?.let { + binding.ivAvatar.load(it.anchorAvatar) + binding.tvFansTeamName.text = it.anchorNick.subAndReplaceDot(7) + ResUtil.getString(R.string.erban_fansteam_fansteamjoinactivity_01) + binding.tvFansTeamFansNum.text = "${it.teamNum}${getString(R.string.person)}" + binding.ivRank0.load(it.avatarList.getOrNull(0)) + binding.ivRank1.load(it.avatarList.getOrNull(1)) + binding.ivRank2.load(it.avatarList.getOrNull(2)) + + it.privilegeConfigVos.find { configVo -> configVo.type == 1 } + ?.let { privilegeConfig -> + binding.tvNameplateTitle.text = privilegeConfig.name + binding.tvNameplateDesc.text = privilegeConfig.description + binding.ivFansNameplate.load(privilegeConfig.icon) + } + + it.privilegeConfigVos.find { configVo -> configVo.type == 2 } + ?.let { privilegeConfig -> + binding.tvGiftTitle.text = privilegeConfig.name + binding.tvGiftDesc.text = privilegeConfig.description + binding.ivFansGift.load(privilegeConfig.icon) + } + + it.privilegeConfigVos.find { configVo -> configVo.type == 3 } + ?.let { privilegeConfig -> + binding.ivJoinLogo.load(privilegeConfig.icon) + binding.tvJoin.text = privilegeConfig.name + binding.bgJoin.setOnClickListener { + privilegeConfig.giftVo?.let { giftInfo -> + GiftModel.get().sendFansTeamGift( + giftInfo.giftId, + AvRoomDataManager.get().roomUid.toString(), + ) + .compose(bindToLifecycle()) + .handleBeanData() + .subscribe({ + toast(R.string.fans_team_3) + finish() + }, { t -> + t.message.toast() + }) + + } ?: run { + toast(R.string.avroom_firstcharge_selectpaytypedialog_01) + } + } + } + } + } + + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/fansteam/FansTeamJoinedActivity.kt b/app/src/main/java/com/chwl/app/fansteam/FansTeamJoinedActivity.kt new file mode 100644 index 0000000..ff7309e --- /dev/null +++ b/app/src/main/java/com/chwl/app/fansteam/FansTeamJoinedActivity.kt @@ -0,0 +1,135 @@ +package com.chwl.app.fansteam + +import android.annotation.SuppressLint +import android.content.Context +import android.content.Intent +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.view.Gravity +import android.view.LayoutInflater +import android.view.View +import android.view.WindowManager +import android.widget.PopupWindow +import androidx.activity.viewModels +import androidx.recyclerview.widget.LinearLayoutManager +import com.netease.nim.uikit.common.util.sys.ScreenUtil +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.common.EmptyViewHelper +import com.chwl.app.databinding.ActivityFansTeamJoinedBinding +import com.chwl.app.ui.utils.RVDelegate +import com.chwl.app.ui.utils.load +import com.chwl.app.ui.webview.DialogWebViewActivity +import com.chwl.core.UriProvider +import com.chwl.core.fansteam.bean.FansTeamTaskInfo +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.utils.extension.subAndReplaceDot +import com.chwl.core.utils.extension.toast +import com.chwl.library.utils.ResUtil + +class FansTeamJoinedActivity : BaseViewBindingActivity() { + + companion object { + @JvmStatic + fun start(context: Context) { + val starter = Intent(context, FansTeamJoinedActivity::class.java) + context.startActivity(starter) + } + } + + private val fansTeamViewModel: FansTeamViewModel by viewModels() + private lateinit var rvDelegate: RVDelegate + private lateinit var popupWindow: PopupWindow + + @SuppressLint("SetTextI18n") + override fun init() { + window.setLayout( + WindowManager.LayoutParams.MATCH_PARENT, + WindowManager.LayoutParams.WRAP_CONTENT + ) + window.setGravity(Gravity.BOTTOM) + + rvDelegate = RVDelegate.Builder() + .setLayoutManager(LinearLayoutManager(this)) + .setRecyclerView(binding.rvTask) + .setAdapter(FansTeamTaskAdapter()) + .setEmptyView(EmptyViewHelper.createEmptyTextView(this, ResUtil.getString(R.string.erban_fansteam_fansteamjoinedactivity_01))) + .build() + + binding.llRank.setOnClickListener { + DialogWebViewActivity.start( + this, + UriProvider.getFansTeamRankUrl(AvRoomDataManager.get().roomUid) + ) + } + + binding.ivHelp.setOnClickListener { + showMorePopup(binding.ivHelp) + } + + fansTeamViewModel.loadTeamTaskInfo() + + fansTeamViewModel.fansTeamJoinedInfoLiveData.observe(this) { + it?.let { + binding.ivAvatar.load(it.anchorAvatar) + binding.tvFansTeamName.text = it.anchorNick.subAndReplaceDot(7) + ResUtil.getString(R.string.erban_fansteam_fansteamjoinedactivity_02) + binding.tvFansTeamFansNum.text = "${it.teamNum}${context.getString(R.string.person)}" + + binding.ivMeAvatar.load(it.memberAvatar) + binding.tvValue.text = + context.getString(R.string.fans_team_8, it.levelSeq.toString()) + binding.tvCurrValue.text = "${it.levelExper}/${it.nextLevelExper}" + binding.pbValue.max = it.nextLevelExper + binding.pbValue.progress = it.levelExper + + binding.ivRank0.load(it.avatarList.getOrNull(0)) + binding.ivRank1.load(it.avatarList.getOrNull(1)) + binding.ivRank2.load(it.avatarList.getOrNull(2)) + rvDelegate.setNewData(it.taskVos) + } + } + + fansTeamViewModel.exitFansTeamLiveData.observe(this) { + if (it == true) { + toast(R.string.fans_team_9) + finish() + } + } + + } + + private fun showMorePopup(parent: View?) { + if (parent == null) return + + val contentView: View + if (!this::popupWindow.isInitialized) { + contentView = + LayoutInflater.from(this).inflate(R.layout.popup_fans_team_more, null) + popupWindow = + PopupWindow(contentView, ScreenUtil.dip2px(124f), ScreenUtil.dip2px(98f)) + popupWindow.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + popupWindow.isFocusable = true + } else { + contentView = popupWindow.contentView + } + contentView.findViewById(R.id.tv_rule).setOnClickListener { + DialogWebViewActivity.start(this, UriProvider.getFansTeamRuleUrl()) + popupWindow.dismiss() + } + contentView.findViewById(R.id.tv_exit).setOnClickListener { + dialogManager.showOkCancelDialog(context.getString(R.string.fans_team_1), true) { + popupWindow.dismiss() + fansTeamViewModel.exitFansTeam() + } + + } + popupWindow.showAsDropDown( + parent, + 0, + 0, + Gravity.END + ) + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/fansteam/FansTeamListActivity.kt b/app/src/main/java/com/chwl/app/fansteam/FansTeamListActivity.kt new file mode 100644 index 0000000..ef39966 --- /dev/null +++ b/app/src/main/java/com/chwl/app/fansteam/FansTeamListActivity.kt @@ -0,0 +1,70 @@ +package com.chwl.app.fansteam + +import android.annotation.SuppressLint +import android.content.Context +import android.content.Intent +import androidx.activity.viewModels +import androidx.recyclerview.widget.LinearLayoutManager +import com.netease.nim.uikit.StatusBarUtil +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.common.EmptyViewHelper +import com.chwl.app.databinding.ActivityFansTeamListBinding +import com.chwl.app.ui.utils.RVDelegate +import com.chwl.core.fansteam.bean.FansTeamInfo +import com.chwl.library.annatation.ActLayoutRes +import com.chwl.library.utils.ResUtil + +@ActLayoutRes(R.layout.activity_fans_team_list) +class FansTeamListActivity : BaseViewBindingActivity() { + + private lateinit var rvDelegate: RVDelegate + + companion object { + @JvmStatic + fun start(context: Context) { + val starter = Intent(context, FansTeamListActivity::class.java) + context.startActivity(starter) + } + } + + private var pageNum = 1 + private val pageSize = 20 + private val fansTeamViewModel: FansTeamViewModel by viewModels() + + @SuppressLint("CheckResult") + override fun init() { + initTitleBar(ResUtil.getString(R.string.erban_fansteam_fansteamlistactivity_01)) + rvDelegate = RVDelegate.Builder() + .setRefreshLayout(binding.swipeRefresh) + .setLayoutManager(LinearLayoutManager(this)) + .setRecyclerView(binding.recyclerView) + .setAdapter(FansTeamListAdapter()) + .setPageSize(pageSize) + .setEmptyView(EmptyViewHelper.createEmptyTextView(this, ResUtil.getString(R.string.erban_fansteam_fansteamlistactivity_02))) + .build() + + binding.swipeRefresh.setOnRefreshListener { + pageNum = 1 + fansTeamViewModel.loadJoinFansTeamList(pageNum, pageSize) + } + + rvDelegate.adapter.setOnLoadMoreListener({ + pageNum++ + fansTeamViewModel.loadJoinFansTeamList(pageNum, pageSize) + }, binding.recyclerView) + + fansTeamViewModel.loadJoinFansTeamList(pageNum, pageSize) + fansTeamViewModel.joinFansTeamListLiveData.observe(this) { + rvDelegate.loadData(it) + } + } + + override fun needSteepStateBar() = true + + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/fansteam/FansTeamListAdapter.kt b/app/src/main/java/com/chwl/app/fansteam/FansTeamListAdapter.kt new file mode 100644 index 0000000..04b58fb --- /dev/null +++ b/app/src/main/java/com/chwl/app/fansteam/FansTeamListAdapter.kt @@ -0,0 +1,35 @@ +package com.chwl.app.fansteam + +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.ui.user.activity.UserInfoActivity +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.core.fansteam.bean.FansTeamInfo + + +class FansTeamListAdapter : + BaseQuickAdapter(R.layout.item_fans_team_list) { + override fun convert(helper: BaseViewHolder, item: FansTeamInfo?) { + if (item == null) { + return + } + + ImageLoadUtils.loadAvatar( + mContext, + item.anchorAvatar, + helper.getView(R.id.iv_avatar) + ) + + ImageLoadUtils.loadAvatar( + mContext, + item.icon, + helper.getView(R.id.iv_nameplate) + ) + helper.setText(R.id.tv_nickname, item.anchorNick) + + helper.itemView.setOnClickListener { + UserInfoActivity.Companion.start(mContext, item.teamUid) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/fansteam/FansTeamTaskAdapter.kt b/app/src/main/java/com/chwl/app/fansteam/FansTeamTaskAdapter.kt new file mode 100644 index 0000000..faa937b --- /dev/null +++ b/app/src/main/java/com/chwl/app/fansteam/FansTeamTaskAdapter.kt @@ -0,0 +1,34 @@ +package com.chwl.app.fansteam + +import android.graphics.Color +import android.widget.ImageView +import android.widget.TextView +import androidx.core.graphics.toColorInt +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.ui.utils.load +import com.chwl.core.fansteam.bean.FansTeamTaskInfo +import com.chwl.library.utils.ResUtil + +class FansTeamTaskAdapter : + BaseQuickAdapter(R.layout.item_fans_team_task) { + + override fun convert(helper: BaseViewHolder, item: FansTeamTaskInfo) { + + helper.setText(R.id.tv_task_title, item.taskName) + .setText(R.id.tv_task_desc, item.taskDesc) + + val tvTaskStatus = helper.getView(R.id.tv_task_status) + tvTaskStatus.text = if (item.isFinished || item.awardVal == 0) { + tvTaskStatus.setBackgroundResource(R.drawable.shape_f4f4f4_radius_4dp) + tvTaskStatus.setTextColor("#FF999999".toColorInt()) + if (item.isFinished) ResUtil.getString(R.string.erban_fansteam_fansteamtaskadapter_01) else "${item.awardVal}/${item.totalNum}" + } else { + tvTaskStatus.setBackgroundResource(R.drawable.shape_ff4e7f_radius_4dp) + tvTaskStatus.setTextColor(Color.WHITE) + "${item.awardVal}/${item.totalNum}" + } + helper.getView(R.id.iv_task_logo).load(item.icon) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/fansteam/FansTeamViewModel.kt b/app/src/main/java/com/chwl/app/fansteam/FansTeamViewModel.kt new file mode 100644 index 0000000..c6c38e7 --- /dev/null +++ b/app/src/main/java/com/chwl/app/fansteam/FansTeamViewModel.kt @@ -0,0 +1,75 @@ +package com.chwl.app.fansteam + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import com.chwl.app.base.BaseViewModel +import com.chwl.core.fansteam.bean.FansTeamInfo +import com.chwl.core.fansteam.bean.FansTeamInitInfo +import com.chwl.core.fansteam.bean.FansTeamJoinInfo +import com.chwl.core.fansteam.bean.FansTeamJoinedInfo +import com.chwl.core.fansteam.FansTeamModel +import com.chwl.core.bean.response.ListResult +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.utils.extension.toast + +class FansTeamViewModel : BaseViewModel() { + + private val _fansTeamJoinInfoLiveData = MutableLiveData() + val fansTeamJoinInfoLiveData: LiveData = _fansTeamJoinInfoLiveData + + private val _fansTeamInitInfoLiveData = MutableLiveData() + val fansTeamInitInfoLiveData: LiveData = _fansTeamInitInfoLiveData + + private val _fansTeamJoinedInfoLiveData = MutableLiveData() + val fansTeamJoinedInfoLiveData: LiveData = _fansTeamJoinedInfoLiveData + + private val _joinFansTeamListLiveData = MutableLiveData>() + val joinFansTeamListLiveData: LiveData> = _joinFansTeamListLiveData + + private val _exitFansTeamLiveData = MutableLiveData() + val exitFansTeamLiveData: LiveData = _exitFansTeamLiveData + + fun loadTeamJoinInfo() { + safeLaunch { + _fansTeamJoinInfoLiveData.value = FansTeamModel.getFansTeamJoinInfo() + } + } + + fun loadTeamTaskInfo() { + safeLaunch { + _fansTeamJoinedInfoLiveData.value = FansTeamModel.getFansTeamTaskInfo() + } + } + + fun loadFansTeamInitInfo() { + if (AvRoomDataManager.get().roomUid == 0L) { + return + } + safeLaunch { + _fansTeamInitInfoLiveData.value = FansTeamModel.getFansTeamInitInfo() + } + } + + fun exitFansTeam() { + safeLaunch { + FansTeamModel.outFansTeam() + _exitFansTeamLiveData.value = true + } + } + + fun loadJoinFansTeamList(pageNum: Int, pageSize: Int) { + safeLaunch( + onError = { + it.message.toast() + _joinFansTeamListLiveData.value = ListResult.failed(pageNum) + }, + block = { + _joinFansTeamListLiveData.value = + ListResult.success( + FansTeamModel.getJoinFansTeamList(pageNum, pageSize), + pageNum + ) + } + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/friend/Holder.java b/app/src/main/java/com/chwl/app/friend/Holder.java new file mode 100644 index 0000000..ffcd720 --- /dev/null +++ b/app/src/main/java/com/chwl/app/friend/Holder.java @@ -0,0 +1,8 @@ +package com.chwl.app.friend; + +/** + * Created by MadisonRong on 06/06/2018. + */ + +public class Holder { +} diff --git a/app/src/main/java/com/chwl/app/friend/action/AbstractSelectFriendAction.java b/app/src/main/java/com/chwl/app/friend/action/AbstractSelectFriendAction.java new file mode 100644 index 0000000..737e42a --- /dev/null +++ b/app/src/main/java/com/chwl/app/friend/action/AbstractSelectFriendAction.java @@ -0,0 +1,44 @@ +package com.chwl.app.friend.action; + +import android.content.Context; + +import com.chwl.app.common.widget.dialog.DialogManager; + +/** + * Created by MadisonRong on 06/06/2018. + */ + +public abstract class AbstractSelectFriendAction { + + public static final String KEY_TYPE = "key_type"; + public static final int TYPE_NORMAL = 0; + public static final int TYPE_CAR = 1; + public static final int TYPE_WEAR = 2; + public static final int TYPE_INVITE = 3; + public static final int TYPE_SHARE = 4; + public static final int ROOM_MSG = 5; + public static final int TYPE_CP = 7; + public static final int TYPE_SEND_DECORATION = 8; + /** + * 世界动态 + */ + public static final int TYPE_WORLD_DYNAMIC = 6; + /** + * 模厅的搜索 + */ + public static final int TYPE_MODULE_HALL = 9; + + protected Context context; + protected DialogManager dialogManager; + + public AbstractSelectFriendAction() { + dialogManager = new DialogManager(context); + dialogManager.setCanceledOnClickOutside(false); + } + + abstract protected void showSureDialog(T data, String targetName, String targetUid); + + public DialogManager getDialogManager() { + return dialogManager; + } +} diff --git a/app/src/main/java/com/chwl/app/friend/action/DefaultSelectFriendAction.java b/app/src/main/java/com/chwl/app/friend/action/DefaultSelectFriendAction.java new file mode 100644 index 0000000..c4b462a --- /dev/null +++ b/app/src/main/java/com/chwl/app/friend/action/DefaultSelectFriendAction.java @@ -0,0 +1,13 @@ +package com.chwl.app.friend.action; + +/** + * Created by MadisonRong on 06/06/2018. + */ + +public class DefaultSelectFriendAction extends AbstractSelectFriendAction { + + @Override + protected void showSureDialog(T data, String targetName, String targetUid) { + + } +} diff --git a/app/src/main/java/com/chwl/app/friend/action/SelectFriendManager.java b/app/src/main/java/com/chwl/app/friend/action/SelectFriendManager.java new file mode 100644 index 0000000..8682ed9 --- /dev/null +++ b/app/src/main/java/com/chwl/app/friend/action/SelectFriendManager.java @@ -0,0 +1,34 @@ +package com.chwl.app.friend.action; + +/** + * Created by MadisonRong on 07/06/2018. + */ + +public class SelectFriendManager { + + private SelectFriendManager() {} + + public static SelectFriendManager get() { + return SelectFriendManagerHolder.instance; + } + + private static class SelectFriendManagerHolder { + private static SelectFriendManager instance = new SelectFriendManager(); + } + + public void showSureDialog(int type, String targetId, String nick) { + switch (type) { + case AbstractSelectFriendAction.TYPE_CAR: + break; + + case AbstractSelectFriendAction.TYPE_WEAR: + break; + + case AbstractSelectFriendAction.TYPE_INVITE: + break; + + case AbstractSelectFriendAction.TYPE_SHARE: + break; + } + } +} diff --git a/app/src/main/java/com/chwl/app/friend/view/SelectFriendActivity.java b/app/src/main/java/com/chwl/app/friend/view/SelectFriendActivity.java new file mode 100644 index 0000000..4032b60 --- /dev/null +++ b/app/src/main/java/com/chwl/app/friend/view/SelectFriendActivity.java @@ -0,0 +1,318 @@ +package com.chwl.app.friend.view; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.view.View; + +import androidx.fragment.app.Fragment; + +import com.chwl.app.R; +import com.chwl.app.base.BaseBindingActivity; +import com.chwl.app.base.TitleBar; +import com.chwl.app.common.ViewPagerAdapter; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.app.databinding.ActivitySelectFriendBinding; +import com.chwl.app.decoration.view.widgets.CarMagicIndicator; +import com.chwl.app.friend.action.AbstractSelectFriendAction; +import com.chwl.app.home.fragment.AttentionFragment; +import com.chwl.app.team.view.TeamListFragment; +import com.chwl.app.ui.im.friend.FriendListFragment; +import com.chwl.app.ui.relation.FansListFragment; +import com.chwl.app.ui.search.SearchActivity; +import com.chwl.app.ui.widget.magicindicator.ViewPagerHelper; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.CommonNavigator; +import com.chwl.core.community.dynamic.DynamicModel; +import com.chwl.core.community.im.DynamicImMsg; +import com.chwl.core.community.im.WorldDynamicAttachment; +import com.chwl.core.family.model.FamilyModel; +import com.chwl.core.home.bean.TabInfo; +import com.chwl.core.manager.IMNetEaseManager; +import com.chwl.core.share.bean.SessionType; +import com.chwl.core.utils.net.DontWarnObserver; +import com.chwl.library.annatation.ActLayoutRes; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; +import com.netease.nimlib.sdk.msg.model.IMMessage; + +import java.util.ArrayList; +import java.util.List; + +import io.reactivex.android.schedulers.AndroidSchedulers; + +@ActLayoutRes(R.layout.activity_select_friend) +public class SelectFriendActivity extends BaseBindingActivity implements CarMagicIndicator.OnItemSelectListener { + + public static final String EXTRA_TARGET_UID = "EXTRA_TARGET_UID"; + public static final String EXTRA_TARGET_NAME = "EXTRA_TARGET_NAME"; + public static final String EXTRA_SESSION_TYPE = "EXTRA_SESSION_TYPE"; + public static final String KEY_SECOND_OPERATOR = "KEY_SECOND_OPERATOR"; + public static final String EXTRA_DYNAMIC_DATA = "extra_dynamic_data"; + + public static final int CODE_REQUEST_TO_SHARE_ROOM = 100; + public static final int CODE_REQUEST_TO_SHARE_FAMILY = 101; + public static final int CODE_REQUEST_TO_SHARE_TEAM = 102; + public static final int CODE_REQUEST_TO_SHARE_H5 = 103; + public static final int CODE_REQUEST_TO_SHARE_MINI_WORLD = 104; + + private int pageLimitSize = 3; + private String[] titles = {ResUtil.getString(R.string.friend_view_selectfriendactivity_01), ResUtil.getString(R.string.friend_view_selectfriendactivity_02), ResUtil.getString(R.string.friend_view_selectfriendactivity_03)}; + + private int type; + private int secondOperator = 0; + private boolean needShowTeamTab; + + public static void start(Context context) { + Intent intent = new Intent(context, SelectFriendActivity.class); + intent.putExtra(AbstractSelectFriendAction.KEY_TYPE, AbstractSelectFriendAction.TYPE_SHARE); + context.startActivity(intent); + } + + public static void startForSharingRoom(Activity activity) { + Intent intent = new Intent(activity, SelectFriendActivity.class); + intent.putExtra(AbstractSelectFriendAction.KEY_TYPE, AbstractSelectFriendAction.TYPE_SHARE); + intent.putExtra(KEY_SECOND_OPERATOR, CODE_REQUEST_TO_SHARE_ROOM); + activity.startActivityForResult(intent, CODE_REQUEST_TO_SHARE_ROOM); + } + + public static void startForSharingFamily(Activity activity) { + Intent intent = new Intent(activity, SelectFriendActivity.class); + intent.putExtra(AbstractSelectFriendAction.KEY_TYPE, AbstractSelectFriendAction.TYPE_SHARE); + intent.putExtra(KEY_SECOND_OPERATOR, CODE_REQUEST_TO_SHARE_FAMILY); + activity.startActivityForResult(intent, CODE_REQUEST_TO_SHARE_FAMILY); + } + + public static void startForSharingMiniWorld(Activity activity) { + Intent intent = new Intent(activity, SelectFriendActivity.class); + intent.putExtra(AbstractSelectFriendAction.KEY_TYPE, AbstractSelectFriendAction.TYPE_SHARE); + intent.putExtra(KEY_SECOND_OPERATOR, CODE_REQUEST_TO_SHARE_MINI_WORLD); + activity.startActivityForResult(intent, CODE_REQUEST_TO_SHARE_MINI_WORLD); + } + + public static void startForSharingTeam(Activity activity) { + Intent intent = new Intent(activity, SelectFriendActivity.class); + intent.putExtra(AbstractSelectFriendAction.KEY_TYPE, AbstractSelectFriendAction.TYPE_SHARE); + intent.putExtra(KEY_SECOND_OPERATOR, CODE_REQUEST_TO_SHARE_TEAM); + activity.startActivityForResult(intent, CODE_REQUEST_TO_SHARE_TEAM); + } + + public static void startForSharingH5(Activity activity) { + Intent intent = new Intent(activity, SelectFriendActivity.class); + intent.putExtra(AbstractSelectFriendAction.KEY_TYPE, AbstractSelectFriendAction.TYPE_SHARE); + intent.putExtra(KEY_SECOND_OPERATOR, CODE_REQUEST_TO_SHARE_H5); + activity.startActivityForResult(intent, CODE_REQUEST_TO_SHARE_H5); + } + + public static void startForSharingDynamic(Activity activity, DynamicImMsg msg) { + Intent intent = new Intent(activity, SelectFriendActivity.class); + intent.putExtra(AbstractSelectFriendAction.KEY_TYPE, AbstractSelectFriendAction.TYPE_WORLD_DYNAMIC); + intent.putExtra(EXTRA_DYNAMIC_DATA, msg); + activity.startActivity(intent); + } + + @Override + public void init() { + type = getIntent().getIntExtra(AbstractSelectFriendAction.KEY_TYPE, AbstractSelectFriendAction.TYPE_NORMAL); + + secondOperator = getIntent().getIntExtra(KEY_SECOND_OPERATOR, 0); + + initTitleBar(getString(R.string.title_select_friend)); + + mBinding.titleBar.addAction(new TitleBar.Action() { + @Override + public String getText() { + return null; + } + + @Override + public int getDrawable() { + return R.drawable.ic_send_search; + } + + @Override + public int getTextColor() { + return 0; + } + + @Override + public int getTextDrawableLeft() { + return 0; + } + + @Override + public void performAction(View view) { + switch (type) { + case AbstractSelectFriendAction.TYPE_CAR: + + break; + + case AbstractSelectFriendAction.TYPE_WEAR: + + break; + + case AbstractSelectFriendAction.TYPE_SHARE: + SearchActivity.startForSharing(SelectFriendActivity.this, secondOperator); + break; + case AbstractSelectFriendAction.TYPE_WORLD_DYNAMIC: + DynamicImMsg dynamicImMsg = (DynamicImMsg) getIntent().getSerializableExtra(EXTRA_DYNAMIC_DATA); + if (dynamicImMsg == null) { + return; + } + SearchActivity.startForShareDynamic(SelectFriendActivity.this, dynamicImMsg); + break; + } + } + }); + + needShowTeamTab = FamilyModel.Instance().getMyFamily() != null && + type == AbstractSelectFriendAction.TYPE_SHARE && secondOperator != 0; + if (needShowTeamTab) { + pageLimitSize = 4; + titles = new String[]{ResUtil.getString(R.string.friend_view_selectfriendactivity_04), ResUtil.getString(R.string.friend_view_selectfriendactivity_05), ResUtil.getString(R.string.friend_view_selectfriendactivity_06), ResUtil.getString(R.string.friend_view_selectfriendactivity_07)}; + } + mBinding.viewpager.setOffscreenPageLimit(pageLimitSize); + mBinding.viewpager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager(), getFragment(), titles)); + + List tabInfoList = new ArrayList<>(2); + tabInfoList.add(new TabInfo(1, getString(R.string.tab_title_friends))); + + if (secondOperator != CODE_REQUEST_TO_SHARE_ROOM) { + tabInfoList.add(new TabInfo(2, getString(R.string.tab_title_attentions))); + }else { + mBinding.titleBar.removeAllActions(); + } + tabInfoList.add(new TabInfo(3, getString(R.string.tab_title_fans))); + if (needShowTeamTab) { + tabInfoList.add(new TabInfo(4, getString(R.string.tab_title_team))); + } + CommonNavigator commonNavigator = new CommonNavigator(this); + commonNavigator.setAdjustMode(true); + CarMagicIndicator indicator = new CarMagicIndicator(this, tabInfoList, 0); + indicator.setOnItemSelectListener(this); + commonNavigator.setAdapter(indicator); + mBinding.viewIndicator.setNavigator(commonNavigator); + ViewPagerHelper.bind(mBinding.viewIndicator, mBinding.viewpager); + } + + private List getFragment() { + List list = new ArrayList<>(); + list.add(FriendListFragment.newInstance(true, type)); + if (secondOperator != CODE_REQUEST_TO_SHARE_ROOM) { + list.add(AttentionFragment.newInstance(type)); + } + list.add(FansListFragment.newInstanceForSelect(type)); + if (needShowTeamTab) { + list.add(TeamListFragment.newInstanceForSelect(type)); + } + return list; + } + + @Override + public void onItemSelect(int position) { + mBinding.viewpager.setCurrentItem(position); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == SearchActivity.CODE_REQUEST_TO_SEARCH && resultCode == RESULT_OK) { + setResult(RESULT_OK, data); + finish(); + } + } + + public void showSureDialog(String targetId, String avatar, String nick) { + switch (type) { + case AbstractSelectFriendAction.TYPE_CAR: + + break; + + case AbstractSelectFriendAction.TYPE_WEAR: + + break; + + case AbstractSelectFriendAction.TYPE_SHARE: + String msg = ""; + if (CODE_REQUEST_TO_SHARE_FAMILY == secondOperator) { + msg = getResources().getString(R.string.family_invite_friends_slogan); + } + getDialogManager().showInAppSharingConfirmDialog(avatar, nick, msg, new DialogManager.OkCancelDialogListener() { + @Override + public void onCancel() { + } + + @Override + public void onOk() { + Intent intent = new Intent(); + intent.putExtra(EXTRA_TARGET_UID, targetId); + intent.putExtra(EXTRA_TARGET_NAME, nick); + setResult(Activity.RESULT_OK, intent); + intent.putExtra(EXTRA_SESSION_TYPE, SessionType.P2P); + finish(); + } + }); + break; + + case AbstractSelectFriendAction.TYPE_WORLD_DYNAMIC: + if (getIntent() == null) { + return; + } + DynamicImMsg dynamicImMsg = (DynamicImMsg) getIntent().getSerializableExtra(EXTRA_DYNAMIC_DATA); + if (dynamicImMsg == null) { + return; + } + getDialogManager().showOkCancelDialog(ResUtil.getString(R.string.friend_view_selectfriendactivity_08) + nick + "?", () -> { + //发出自定义消息 + IMMessage message = WorldDynamicAttachment.createShareMsg(dynamicImMsg, targetId); + IMNetEaseManager.get().sendMessage(message) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new DontWarnObserver() { + @Override + public void accept(Boolean aBoolean, String error) { + super.accept(aBoolean, error); + if (error != null) { + SingleToastUtil.showToast(error); + } else { + SingleToastUtil.showToast(ResUtil.getString(R.string.friend_view_selectfriendactivity_09)); + DynamicModel.get().reportShare(dynamicImMsg.getPublishUid(), + dynamicImMsg.getWorldId(), dynamicImMsg.getDynamicId()) + .subscribe(); + } + } + }); + finish(); + }); + break; + default: + + break; + } + } + + public void shareToTeam(String sessionId, String avatar, String name) { + switch (type) { + case AbstractSelectFriendAction.TYPE_SHARE: + String msg = ""; + if (CODE_REQUEST_TO_SHARE_FAMILY == secondOperator) { + msg = getResources().getString(R.string.family_invite_friends_slogan); + } + getDialogManager().showInAppSharingConfirmDialog(avatar, name, msg, new DialogManager.OkCancelDialogListener() { + @Override + public void onCancel() { + } + + @Override + public void onOk() { + Intent intent = new Intent(); + intent.putExtra(EXTRA_TARGET_UID, sessionId); + intent.putExtra(EXTRA_TARGET_NAME, name); + intent.putExtra(EXTRA_SESSION_TYPE, SessionType.TEAM); + setResult(Activity.RESULT_OK, intent); + finish(); + } + }); + break; + } + } + +} diff --git a/app/src/main/java/com/chwl/app/guide/GuideActivity.java b/app/src/main/java/com/chwl/app/guide/GuideActivity.java new file mode 100644 index 0000000..1f38717 --- /dev/null +++ b/app/src/main/java/com/chwl/app/guide/GuideActivity.java @@ -0,0 +1,92 @@ +package com.chwl.app.guide; + +import android.content.Context; +import android.content.Intent; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; + +import androidx.annotation.NonNull; +import androidx.viewpager.widget.PagerAdapter; + +import com.chwl.app.R; +import com.chwl.app.base.BaseViewBindingActivity; +import com.chwl.app.databinding.ActivityGuideBinding; +import com.chwl.core.utils.SharedPreferenceUtils; + +public class GuideActivity extends BaseViewBindingActivity { + + public final static String KEY_FIRST_GUIDE = "key_first_guide"; + + private final int[] mTopImages = new int[]{ + R.drawable.ic_guide_top_1, + R.drawable.ic_guide_top_2, + R.drawable.ic_guide_top_3 + }; + + private final int[] mCenterImages = new int[]{ + R.drawable.ic_guide_center_1, + R.drawable.ic_guide_center_2, + R.drawable.ic_guide_center_3 + }; + + private final int[] mBottomImages = new int[]{ + R.drawable.ic_guide_bottom_1, + R.drawable.ic_guide_bottom_2, + R.drawable.ic_guide_bottom_3 + }; + + public static void start(Context context) { + Boolean flag = (Boolean) SharedPreferenceUtils.get(KEY_FIRST_GUIDE, true); + if (flag != null && flag) { + SharedPreferenceUtils.put(KEY_FIRST_GUIDE, false); + context.startActivity(new Intent(context, GuideActivity.class)); + } + } + + @Override + public void init() { + if (mTopImages.length != mCenterImages.length) { + return; + } + if (mTopImages.length != mBottomImages.length) { + return; + } + binding.viewPager.setAdapter(new PagerAdapter() { + + @NonNull + @Override + public Object instantiateItem(@NonNull ViewGroup container, int position) { + View view = View.inflate(GuideActivity.this, R.layout.pager_guide, null); + ImageView ivTop = view.findViewById(R.id.iv_top); + ImageView ivCenter = view.findViewById(R.id.iv_center); + ImageView ivBottom = view.findViewById(R.id.iv_bottom); + + ivTop.setImageResource(mTopImages[position]); + ivCenter.setImageResource(mCenterImages[position]); + ivBottom.setImageResource(mBottomImages[position]); + + ivBottom.setOnClickListener(v -> finish()); + ivBottom.setClickable(position == mBottomImages.length - 1); + container.addView(view); + return view; + } + + @Override + public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { + container.removeView((View) object); + } + + @Override + public int getCount() { + return mTopImages.length; + } + + @Override + public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { + return view == object; + } + }); + } + +} diff --git a/app/src/main/java/com/chwl/app/home/HomeMeViewModel.kt b/app/src/main/java/com/chwl/app/home/HomeMeViewModel.kt new file mode 100644 index 0000000..c760a44 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/HomeMeViewModel.kt @@ -0,0 +1,45 @@ +package com.chwl.app.home + +import androidx.lifecycle.MutableLiveData +import com.chwl.app.base.BaseViewModel +import com.chwl.core.bean.response.ListResult +import com.chwl.core.home.bean.HomeRoomCardInfo +import com.chwl.core.home.bean.HomeRoomInfo +import com.chwl.core.home.model.HomeModel + +class HomeMeViewModel : BaseViewModel() { + + val roomInfoLiveData = MutableLiveData() + val historyRoomListLiveData = MutableLiveData?>() + val collectRoomListLiveData = MutableLiveData?>() + + fun getMyRoomInfo() { + safeLaunch { + roomInfoLiveData.postValue(HomeModel.getMyRoomInfo()) + } + } + + fun getHomeHistoryList(pageNum: Int, pageSize: Int) { + safeLaunch( + onError = { + historyRoomListLiveData.value = ListResult.failed(pageNum) + }, + block = { + val result = HomeModel.getHomeHistoryRoomList(pageNum, pageSize) + historyRoomListLiveData.value = ListResult.success(result, pageNum) + } + ) + } + + fun getHomeCollectList(pageNum: Int, pageSize: Int) { + safeLaunch( + onError = { + collectRoomListLiveData.value = ListResult.failed(pageNum) + }, + block = { + val result = HomeModel.getHomeMyCollectRoomList(pageNum, pageSize) + collectRoomListLiveData.value = ListResult.success(result, pageNum) + } + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/HomeMessageViewModel.kt b/app/src/main/java/com/chwl/app/home/HomeMessageViewModel.kt new file mode 100644 index 0000000..25396fc --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/HomeMessageViewModel.kt @@ -0,0 +1,26 @@ +package com.chwl.app.home + +import androidx.lifecycle.MutableLiveData +import com.chwl.app.base.BaseViewModel +import com.chwl.core.bean.response.BeanResult +import com.chwl.core.public_chat_hall.bean.PublicChatMessageBean +import com.chwl.core.public_chat_hall.model.PublicChatModel + +class HomeMessageViewModel : BaseViewModel() { + val topPublicChatMessageLiveData = MutableLiveData>>() + + fun getTopPublicChatMessage() { + safeLaunch(needLoading = false, onError = { + topPublicChatMessageLiveData.postValue(BeanResult.failed(it)) + }) { +// val value = PublicChatModel.getTopMessage() +// topPublicChatMessageLiveData.postValue(BeanResult.success(value ?: emptyList())) + } + } + + fun getTopPublicChatMessageIfNull() { + if (topPublicChatMessageLiveData.value?.data.isNullOrEmpty()) { + getTopPublicChatMessage() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/HomeViewModel.kt b/app/src/main/java/com/chwl/app/home/HomeViewModel.kt new file mode 100644 index 0000000..8c16ab2 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/HomeViewModel.kt @@ -0,0 +1,106 @@ +package com.chwl.app.home + +import androidx.lifecycle.MutableLiveData +import com.chwl.app.base.BaseViewModel +import com.chwl.core.bean.response.ListResult +import com.chwl.core.home.bean.BannerInfo +import com.chwl.core.home.bean.CurrentResourceInfo +import com.chwl.core.home.bean.HomeRankBean +import com.chwl.core.home.bean.HomeRoomInfo +import com.chwl.core.home.bean.HomeTagInfo +import com.chwl.core.home.model.HomeModel +import com.chwl.core.room.bean.AnchorInfo +import com.chwl.core.utils.extension.toast +import kotlinx.coroutines.flow.MutableSharedFlow + +class HomeViewModel : BaseViewModel() { + + val tabRoomListLiveData = MutableLiveData?>() + val bannerLiveData = MutableLiveData?>() + val secondBannerLiveData = MutableLiveData?>() + + val homeResourceLiveData = MutableLiveData?>() + + val resourceJumpFlow = MutableSharedFlow() + + val pickRoomLiveData = MutableLiveData() + + val openGameRoomLiveData = MutableLiveData() + + val anchorInfoLiveData = MutableLiveData() + + val homeTabLiveData: MutableLiveData> = MutableLiveData>() + + val homeRankListLiveData = MutableLiveData>>() + fun getTabRoomList(tabId: Int, pageNum: Int, pageSize: Int) { + safeLaunch( + onError = { + tabRoomListLiveData.value = ListResult.failed(pageNum) + }, + block = { + val result = HomeModel.getHomeTabHome(tabId, pageNum, pageSize) + tabRoomListLiveData.value = ListResult.success(result, pageNum) + } + ) + } + + /** + * 首页改版资源位 + */ + fun getHomeResourceInfo() { + safeLaunch( + onError = { + homeResourceLiveData.value = null + }, + block = { + homeResourceLiveData.value = HomeModel.getCurrentResource() + } + ) + } + + fun getResourceJumpInfo(id: Int) { + safeLaunch( + onError = { + resourceJumpFlow.emit(null) + it.message.toast() + }, + block = { + resourceJumpFlow.emit(HomeModel.getResourceJumpInfo(id)) + } + ) + } + + fun getBannerInfo() { + safeLaunch( + onError = { + bannerLiveData.value = null + }, + block = { + bannerLiveData.value = HomeModel.getHomeBanner("1") + } + ) + } + + fun getSecondBannerInfo() { + safeLaunch( + onError = { + secondBannerLiveData.value = null + }, + block = { + secondBannerLiveData.value = HomeModel.getHomeSecondBanner("1") + } + ) + } + + fun getHomeTabInfo() { + safeLaunch { + homeTabLiveData.value = HomeModel.getNewHomeTab() + } + } + + fun getHomeRankList() { + safeLaunch { + homeRankListLiveData.value = HomeModel.getHomeRankList() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/MeViewModel.kt b/app/src/main/java/com/chwl/app/home/MeViewModel.kt new file mode 100644 index 0000000..ff09d16 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/MeViewModel.kt @@ -0,0 +1,79 @@ +package com.chwl.app.home + +import androidx.lifecycle.MutableLiveData +import com.chwl.app.R +import com.chwl.app.base.BaseViewModel +import com.chwl.core.home.model.HomeModel +import com.chwl.core.im.custom.bean.RouterType +import com.chwl.core.room.bean.MeCenterInfo +import com.chwl.core.user.UserModel +import com.chwl.library.utils.ResUtil + +class MeViewModel : BaseViewModel() { + + private var menuList: List? = null + + val menuListLiveData = MutableLiveData?>() + + private var donationMenuVisible = false + + fun updateDonationMenuVisible(isVisible: Boolean) { + donationMenuVisible = isVisible + if (!menuList.isNullOrEmpty()) { + menuListLiveData.value = transformMenuList(menuList) + } + } + + fun requestMenuList() { + safeLaunch(onError = { + if (menuListLiveData.value.isNullOrEmpty()) { + menuListLiveData.postValue(transformMenuList(null)) + } + }) { + val value = HomeModel.requestMeCenterInfoList() + menuList = value + menuListLiveData.postValue(transformMenuList(value)) + } + } + + private fun transformMenuList(list: List?): List { + val finalList = ArrayList() + if (list.isNullOrEmpty()) { + finalList.addAll(getDefaultMenuList()) + } else { + finalList.addAll(list) + } + + var needRemoveRecharge = true + if (UserModel.get().cacheLoginUserInfo?.isRechargeUser == true) { + needRemoveRecharge = false + }else{ + if (donationMenuVisible) { + needRemoveRecharge = false + } + } + + if (needRemoveRecharge) { + val donationMenuPosition = finalList.indexOfFirst { + it.skipType == RouterType.MY_DONATION + } + if (donationMenuPosition >= 0) { + finalList.removeAt(donationMenuPosition) + } + } + + return finalList + } + + private fun getDefaultMenuList(): MutableList { + return ArrayList().apply { + add( + MeCenterInfo( + icon = R.drawable.me_ic_menu_setting, + centerName = ResUtil.getString(R.string.me_setting), + skipType = RouterType.MY_SET + ) + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/RoomCommonViewModel.kt b/app/src/main/java/com/chwl/app/home/RoomCommonViewModel.kt new file mode 100644 index 0000000..c1f97ce --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/RoomCommonViewModel.kt @@ -0,0 +1,29 @@ +package com.chwl.app.home + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import com.chwl.app.base.BaseViewModel +import com.chwl.core.bean.response.ListResult +import com.chwl.core.home.bean.HomeRoomInfo +import com.chwl.core.home.model.HomeModel +import com.chwl.core.utils.extension.toast + +class RoomCommonViewModel : BaseViewModel() { + + private val _commonRoomLiveData = MutableLiveData>() + val commonRoomLiveData: LiveData> = _commonRoomLiveData + + fun getCommonRoom(tabId: Int, pageNum: Int, pageSize: Int) { + safeLaunch( + onError = { + it.message.toast() + _commonRoomLiveData.value = ListResult.failed(pageNum) + }, + block = { + val result = HomeModel.getCommonRoom(tabId, pageNum, pageSize) + _commonRoomLiveData.value = ListResult.success(result, pageNum) + } + ) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/RoomSingleViewModel.kt b/app/src/main/java/com/chwl/app/home/RoomSingleViewModel.kt new file mode 100644 index 0000000..e95fc6a --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/RoomSingleViewModel.kt @@ -0,0 +1,27 @@ +package com.chwl.app.home + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import com.chwl.app.base.BaseViewModel +import com.chwl.core.bean.response.ListResult +import com.chwl.core.home.bean.HomeRoomInfo +import com.chwl.core.home.model.HomeModel + +class RoomSingleViewModel : BaseViewModel() { + + private val _singleAnchorMoreLiveData = MutableLiveData>() + val singleAnchorMoreLiveData: LiveData> = _singleAnchorMoreLiveData + + fun getMoreSingleAnchorList(id: Long?) { + safeLaunch( + onError = { + _singleAnchorMoreLiveData.value = ListResult.failed(1) + }, + block = { + val result = HomeModel.getMoreSingleAnchorList(id) + _singleAnchorMoreLiveData.value = ListResult.success(result, 1) + } + ) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/activity/AssociationActivity.kt b/app/src/main/java/com/chwl/app/home/activity/AssociationActivity.kt new file mode 100644 index 0000000..90cd64a --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/activity/AssociationActivity.kt @@ -0,0 +1,95 @@ +package com.chwl.app.home.activity + +import android.content.Context +import android.content.Intent +import android.widget.LinearLayout +import android.widget.TextView +import androidx.fragment.app.Fragment +import androidx.viewpager.widget.ViewPager +import androidx.viewpager2.widget.ViewPager2 +import com.netease.nim.uikit.StatusBarUtil +import com.chwl.app.R +import com.chwl.app.avroom.adapter.CommonVPAdapter +import com.chwl.app.module_hall.hall.fragment.AssociationFragment +import com.chwl.app.module_hall.hall.fragment.AssociationRoomFragment +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.common.CommonPagerAdapter +import com.chwl.app.databinding.ActivityAssociationBinding +import com.chwl.app.ui.user.adapter.CommonWrapIndicatorAdapter +import com.chwl.app.ui.widget.magicindicator.MagicIndicator +import com.chwl.app.ui.widget.magicindicator.ViewPagerHelper +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.CommonNavigator +import com.chwl.library.utils.ResUtil + +/** + * 公会周榜 + */ +class AssociationActivity : BaseViewBindingActivity() { + + companion object { + @JvmStatic + fun start(context: Context) { + val intent = Intent(context, AssociationActivity::class.java) + context.startActivity(intent) + } + } + + override fun init() { + initWhiteTitleBar(ResUtil.getString(R.string.association_list)) + initDetail() + } + + /** + * 公會 + */ + private fun initDetail() { + val viewPager = binding.viewPagerDetail + val magicIndicator: MagicIndicator = binding.magicIndicator + val fragmentList: MutableList = ArrayList() + val tagList: MutableList = ArrayList() + tagList.add(getString(R.string.me_association)) + tagList.add(getString(R.string.me_room)) + fragmentList.add(AssociationFragment.newInstance()) + fragmentList.add(AssociationRoomFragment.newInstance()) + val commonNavigator = CommonNavigator(context) + commonNavigator.isAdjustMode = true//自我调节位置,实现自我平分 + val magicIndicatorAdapter = CommonWrapIndicatorAdapter(context, tagList) + magicIndicatorAdapter.setOnItemSelectListener { position: Int, view: TextView? -> + viewPager.currentItem = position + } + commonNavigator.adapter = magicIndicatorAdapter + magicIndicator.navigator = commonNavigator + commonNavigator.titleContainer.showDividers = LinearLayout.SHOW_DIVIDER_MIDDLE + viewPager.adapter = CommonVPAdapter(supportFragmentManager, lifecycle, fragmentList) + viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { + override fun onPageScrolled( + position: Int, + positionOffset: Float, + positionOffsetPixels: Int + ) { + magicIndicator.onPageScrolled(position, positionOffset, positionOffsetPixels) + } + + override fun onPageSelected(position: Int) { + magicIndicator.onPageSelected(position) + viewPager.requestLayout() + } + + override fun onPageScrollStateChanged(state: Int) { + magicIndicator.onPageScrollStateChanged(state) + } + }) + + } + + override fun needSteepStateBar(): Boolean { + return true + } + + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/activity/CollectionRoomActivity.java b/app/src/main/java/com/chwl/app/home/activity/CollectionRoomActivity.java new file mode 100644 index 0000000..36e15e0 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/activity/CollectionRoomActivity.java @@ -0,0 +1,108 @@ +package com.chwl.app.home.activity; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.Intent; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.netease.nim.uikit.StatusBarUtil; +import com.chwl.app.R; +import com.chwl.app.avroom.activity.AVRoomActivity; +import com.chwl.app.base.BaseViewBindingActivity; +import com.chwl.app.databinding.ActivityCollectionRoomBinding; +import com.chwl.app.home.adapter.CollectionRoomAdapter; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.home.bean.HomeRoomInfo; +import com.chwl.core.home.model.CollectionRoomModel; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; + +import java.util.List; + +public class CollectionRoomActivity extends BaseViewBindingActivity implements SwipeRefreshLayout.OnRefreshListener, BaseQuickAdapter.RequestLoadMoreListener { + + private CollectionRoomAdapter roomAdapter; + private int pageSize = 50; + private int page = 1; + + @Override + public void init() { + initWhiteTitleBar(ResUtil.getString(R.string.home_activity_collectionroomactivity_01)); + initRecyclerView(); + binding.swipeRefresh.setOnRefreshListener(this); + } + + @Override + protected void onResume() { + super.onResume(); + loadData(); + } + + public static void start(Context context) { + Intent intent = new Intent(context, CollectionRoomActivity.class); + context.startActivity(intent); + } + + private void initRecyclerView() { + binding.recyclerView.setLayoutManager(new LinearLayoutManager(this)); + roomAdapter = new CollectionRoomAdapter(); + roomAdapter.setOnItemChildClickListener((adapter, view, position) -> { + HomeRoomInfo fansRoomListBean = (HomeRoomInfo) adapter.getItem(position); + if (view.getId() == R.id.cl_root) { + AVRoomActivity.start(CollectionRoomActivity.this, fansRoomListBean.getRoomUid()); + } + }); + + + binding.recyclerView.setAdapter(roomAdapter); + } + + + @SuppressLint("CheckResult") + private void loadData() { + + CollectionRoomModel.get().getCollectionRoomList(AuthModel.get().getCurrentUid(), page, pageSize) + .subscribe((serviceResult, throwable) -> { + if (throwable != null) { + binding.swipeRefresh.setRefreshing(false); + } else { + binding.swipeRefresh.setRefreshing(false); + List info = serviceResult.getFansRoomList(); + if (ListUtils.isListEmpty(info)) { + showNoData(R.drawable.icon_common_failure, ResUtil.getString(R.string.home_activity_collectionroomactivity_03)); + } else { + hideStatus(); + } + roomAdapter.setNewData(info); + roomAdapter.notifyDataSetChanged(); + } + }); + } + + + @Override + public void onLoadMoreRequested() { + + } + + @Override + public void onRefresh() { + loadData(); + } + + @Override + protected boolean needSteepStateBar() { + return true; + } + + @Override + protected void setStatusBar() { + super.setStatusBar(); + StatusBarUtil.transparencyBar(this); + StatusBarUtil.StatusBarLightMode(this); + } + +} diff --git a/app/src/main/java/com/chwl/app/home/activity/CommunityNoticeAct.java b/app/src/main/java/com/chwl/app/home/activity/CommunityNoticeAct.java new file mode 100644 index 0000000..319ccb2 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/activity/CommunityNoticeAct.java @@ -0,0 +1,152 @@ +package com.chwl.app.home.activity; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import com.netease.nim.uikit.StatusBarUtil; +import com.chwl.app.R; +import com.chwl.app.base.BaseMvpActivity; +import com.chwl.app.base.TitleBar; +import com.chwl.app.home.adapter.CommunityNoticeAdapter; +import com.chwl.app.home.presenter.CommunityNoticePresenter; +import com.chwl.app.home.view.ICommunityNoticeAct; +import com.chwl.app.ui.user.activity.UserInfoActivity; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.community.bean.CommunityNoticeInfo; +import com.chwl.library.base.factory.CreatePresenter; +import com.chwl.library.utils.ResUtil; + +import java.util.List; + +@CreatePresenter(CommunityNoticePresenter.class) +public class CommunityNoticeAct extends BaseMvpActivity + implements ICommunityNoticeAct { + + private SwipeRefreshLayout swipeRefreshLayout; + private RecyclerView recyclerView; + + private CommunityNoticeAdapter mCommunityNoticeAdapter; + + public static void start(Context context) { + context.startActivity(new Intent(context, CommunityNoticeAct.class)); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.act_community_notice); + findView(); + initWhiteTitleBar(ResUtil.getString(R.string.home_activity_communitynoticeact_01)); + mTitleBar.addAction(new TitleBar.TextAction(ResUtil.getString(R.string.home_activity_communitynoticeact_02), getResources().getColor(R.color.text_normal_c6c6e9)) { + @Override + public void performAction(View view) { + getDialogManager().showOkCancelWithTitleDialog(ResUtil.getString(R.string.home_activity_communitynoticeact_03), ResUtil.getString(R.string.home_activity_communitynoticeact_04), + () -> getMvpPresenter().delete(AuthModel.get().getCurrentUid())); + } + }); + + swipeRefreshLayout.setOnRefreshListener(() -> getMvpPresenter().refresh(AuthModel.get().getCurrentUid())); + + mCommunityNoticeAdapter = new CommunityNoticeAdapter(); + mCommunityNoticeAdapter.setOnLoadMoreListener(() -> getMvpPresenter().loadMore(AuthModel.get().getCurrentUid()), recyclerView); + mCommunityNoticeAdapter.setOnItemChildClickListener((adapter, view, position) -> { + }); + recyclerView.setAdapter(mCommunityNoticeAdapter); + recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)); + + getMvpPresenter().refresh(AuthModel.get().getCurrentUid()); + } + + private void findView() { + swipeRefreshLayout = findViewById(R.id.swipe_refresh); + recyclerView = findViewById(R.id.recycler_view); + } + + @Override + public void getMsgListSuccess(List list) { + hideStatus(); + int page = getMvpPresenter().getPage(); + if (page == 1 && swipeRefreshLayout != null) { + swipeRefreshLayout.setRefreshing(false); + } else if (page > 1 && mCommunityNoticeAdapter != null) { + mCommunityNoticeAdapter.loadMoreComplete(); + } + + if (mCommunityNoticeAdapter != null) { + if (getMvpPresenter().getPage() > 1) { + mCommunityNoticeAdapter.addData(list); + } else { + mCommunityNoticeAdapter.setNewData(list); + } + + } + + } + + @Override + public void getMsgListFail(String error) { + + if (getMvpPresenter().getPage() == 1) { + showNoData(); + } + + swipeRefreshLayout.setRefreshing(false); + if (!TextUtils.isEmpty(error)) { + if (error.equals(ResUtil.getString(R.string.home_activity_communitynoticeact_05))) { + if (mCommunityNoticeAdapter != null) { + mCommunityNoticeAdapter.loadMoreEnd(); + } + } else { + if (mCommunityNoticeAdapter != null) { + mCommunityNoticeAdapter.loadMoreFail(); + } + + } + } + + } + + @Override + public View.OnClickListener getLoadListener() { + return v -> { + showLoading(); + getMvpPresenter().refresh(AuthModel.get().getCurrentUid()); + }; + } + + @Override + public void clearSuccess() { + showNoData(); + swipeRefreshLayout.setRefreshing(false); + if (mCommunityNoticeAdapter != null) { + mCommunityNoticeAdapter.setNewData(null); + mCommunityNoticeAdapter.loadMoreEnd(); + } + + } + + @Override + public void clearFail(String error) { + toast(error); + } + + @Override + protected boolean needSteepStateBar() { + return true; + } + + @Override + protected void setStatusBar() { + super.setStatusBar(); + StatusBarUtil.transparencyBar(this); + StatusBarUtil.StatusBarLightMode(this); + } +} diff --git a/app/src/main/java/com/chwl/app/home/activity/EventCenterActivity.kt b/app/src/main/java/com/chwl/app/home/activity/EventCenterActivity.kt new file mode 100644 index 0000000..3b62b85 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/activity/EventCenterActivity.kt @@ -0,0 +1,77 @@ +package com.chwl.app.home.activity + +import android.content.Context +import android.content.Intent +import androidx.viewpager2.widget.ViewPager2 +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.databinding.ActivityEventCenterBinding +import com.chwl.app.databinding.TabEventCenterBinding +import com.chwl.app.home.fragment.EventMyFragment +import com.chwl.app.home.fragment.EventOfficialFragment +import com.chwl.app.home.fragment.EventSquareFragment +import com.chwl.library.common.util.setVis +import com.chwl.library.widget.tab.BaseTabTitleProvider +import com.chwl.library.widget.tab.util.FragmentPageAdapter +import com.example.lib_utils.ktx.getString + + +class EventCenterActivity : BaseViewBindingActivity() { + + + override fun init() { + initTab() + + } + + private fun initTab() { + initLightTitleBar(R.string.v_27_Event_Content.getString()) + + + + val fragmets = listOf( + EventOfficialFragment(), + EventSquareFragment(), + EventMyFragment(), + ) + val tabTitles = listOf( + R.string.v_27_Official.getString(), + R.string.v_27_Event_Square.getString(), + R.string.v_27_My_Event.getString(), + ) + + binding.tabLayout.setViewPager(binding.viewPage,FragmentPageAdapter(this,fragmets),BaseTabTitleProvider(tabTitles)) + binding.tabLayout.setOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { + override fun onPageSelected(position: Int) { + for (i in 0 until binding.tabLayout.tabCount) { + val binding = TabEventCenterBinding.bind(binding.tabLayout.getTabAt(i)) + binding.select.setVis(i == position) + binding.title.paint.isFakeBoldText = i == position + } +// fragmets.getOrNull(position)?.onHiddenChanged(false) + } + }) +// binding.tabLayout.post { +// binding.tabLayout.setc +// } + +// try { +// val touchSlopField: Field = ViewPager2::class.java.getDeclaredField("mTouchSlop") +// touchSlopField.isAccessible = true +// touchSlopField.setInt(binding.viewPage, 50) // 增大这个值 +// } catch (e: Exception) { +// e.printStackTrace() +// } + + } + + + + companion object{ + @JvmStatic + fun start(context: Context) { + val starter = Intent(context, EventCenterActivity::class.java) + context.startActivity(starter) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/activity/EventCreateActivity.kt b/app/src/main/java/com/chwl/app/home/activity/EventCreateActivity.kt new file mode 100644 index 0000000..28cf868 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/activity/EventCreateActivity.kt @@ -0,0 +1,562 @@ +package com.chwl.app.home.activity + +import android.annotation.SuppressLint +import android.content.Context +import android.content.Intent +import android.graphics.Bitmap +import android.graphics.Rect +import android.net.Uri +import android.text.Spannable +import android.text.SpannableString +import android.text.style.ImageSpan +import android.view.View +import androidx.activity.result.contract.ActivityResultContracts +import androidx.core.content.ContextCompat +import androidx.core.widget.doOnTextChanged +import com.chwl.app.R +import com.chwl.app.application.App +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.base.PhotoPickActivity +import com.chwl.app.common.util.BitmapUtil +import com.chwl.app.databinding.ActivityEventCreateBinding +import com.chwl.app.home.dialog.EventDurationDialog +import com.chwl.app.home.helper.EventCenterUtil +import com.chwl.app.module_hall.hall.view.dialog.TimePickerDialog +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.app.utils.KeyBoardUtils +import com.chwl.core.auth.AuthModel +import com.chwl.core.bean.response.ServiceResult +import com.chwl.core.file.FileModel +import com.chwl.core.gift.bean.EventUserConfig +import com.chwl.core.utils.myutil.MyTimeUtils +import com.chwl.core.utils.myutil.MyUriUtils +import com.chwl.core.utils.myutil.MyUtil +import com.chwl.core.utils.net.RxHelper +import com.chwl.library.common.file.FileHelper +import com.chwl.library.common.util.ClickUtils.click +import com.chwl.library.common.util.PhotoCompressCallback +import com.chwl.library.common.util.PhotoCompressUtil +import com.chwl.library.common.util.doLog +import com.chwl.library.common.util.doToast +import com.chwl.library.common.util.isRtl +import com.chwl.library.common.util.isVerify +import com.chwl.library.common.util.setVis +import com.chwl.library.net.rxnet.RxNet +import com.example.lib_utils.ktx.getDrawable +import com.example.lib_utils.ktx.getString +import com.google.gson.JsonElement +import com.hjq.toast.ToastUtils +import com.jzxiang.pickerview.data.Type +import com.yalantis.ucrop.UCrop +import io.reactivex.Single +import kotlinx.coroutines.Job +import razerdp.util.KeyboardUtils +import retrofit2.http.GET +import retrofit2.http.POST +import retrofit2.http.Query +import java.io.FileNotFoundException +import java.text.SimpleDateFormat +import java.util.Calendar +import java.util.Locale + +class EventCreateActivity : BaseViewBindingActivity() { + + + companion object { + @JvmStatic + fun start(context: Context) { + val starter = Intent(context, EventCreateActivity::class.java) + context.startActivity(starter) + } + } + + private val PICK_IMG = 1111111 + private var mSelectImg: Uri? = null + private var mIsShowHomePage: Boolean? = null + private var mIsShowHomePageDialogConfirm = false + private val mSelectRoomLauncher = registerForActivityResult( + ActivityResultContracts.StartActivityForResult() + ) { result -> + if (result.resultCode == RESULT_OK) { + val data = result.data + // 处理返回的数据 + val roomId = data?.getLongExtra("roomId", -1) + val erbanNo = data?.getLongExtra("erbanNo", -1) + erbanNo?.takeIf { it != -1L }?.let { + binding.tvSelectRoom.text = erbanNo.toString() + } + roomId?.takeIf { it != -1L }?.let { + mSelectRoomId = roomId + } + checkInput() + } + } + + private val mPhotoPickerLauncher = registerForActivityResult( + ActivityResultContracts.StartActivityForResult() + ) { result -> + if (result.resultCode == RESULT_OK) { + val uri = result.data?.data + if (uri != null) { + if (MyUriUtils.isGif(this, uri)) { + ToastUtils.show(R.string.error_file_type) + return@registerForActivityResult + } + mUri = Uri.parse("file://${FileHelper.getRootCacheDir()?.path}/banner_${System.currentTimeMillis()}.jpg") + val copyFileToUrl = MyUriUtils.copyFileToUrl(this, uri, mUri!!) + if (copyFileToUrl) { + crop(mUri, 1, mUri) + } else { + ToastUtils.show(R.string.exception_try_again) + } + } + } + } + private var mSelectRoomId:Long?=null + private var mStartTime: Long? = null + private var mIsNotifyFans = false + private var mDuration: Int? = null + private var mPayGoldNum : Int?=null + private var mConfig:EventUserConfig? = null + + + private var mUri: Uri? = null + private var mJob: Job? = null + private val MAX_BITMAP_SIZE = 100 * 1024 * 1024 // 剪切的图片最大为100 MB + + override fun init() { + + initLightTitleBar(R.string.v_27_Create_Event.getString()) + + binding.etTitle.doOnTextChanged { text, start, before, count -> + binding.tvTitleNum.text = "${text?.length ?: 0}/50" + checkInput() + } + + binding.pic.click { + val intent = PhotoPickActivity.getIntent( + this, + PhotoPickActivity.IMG, + PICK_IMG + ) // 假设你有静态方法 getIntent + mPhotoPickerLauncher.launch(intent) + } + + + //rgHomePage + binding.rgHomePage.setOnCheckedChangeListener { group, checkedId -> + if (checkedId != View.NO_ID) { + + if (binding.rgHomePageYes.id == checkedId && !mIsShowHomePageDialogConfirm) { + group.clearCheck() + if (mConfig==null) return@setOnCheckedChangeListener + val desc = StringBuilder() + desc.appendLine(R.string.v_27_banner_cost_1.getString(mConfig?.goldNum?.toString()?:0)) + desc.appendLine(R.string.v_27_banner_cost_2.getString()) + desc.appendLine(R.string.v_27_banner_cost_3.getString()) + dialogManager?.let { + it.showOkCancelDialog( + R.string.Confirmation.getString(), + desc.toString(), + R.string.confirm.getString(), + R.string.cancel.getString(), + true, + ){ + mIsShowHomePageDialogConfirm = true + binding.rgHomePageYes.isChecked = true + mIsShowHomePage = binding.rgHomePageYes.isChecked + } + } + } + mIsShowHomePage = binding.rgHomePageYes.isChecked + mIsShowHomePageDialogConfirm = false + } + checkInput() + } + + binding.rgHomePageNo.isChecked = true + + //tvSelectRoom + binding.tvSelectRoom.click { + val intent = Intent(this, EventSelectRoomActivity::class.java) + mSelectRoomLauncher.launch(intent) + } + + //tvStartTime + binding.tvStartTime.click { + showStartTimePick() + } + //tvDuration + binding.tvDuration.click { + showDurationPick() + } + + binding.etContent.doOnTextChanged { text, start, before, count -> + binding.tvContentNum.text = "${text?.length ?: 0}/1000" + checkInput() + } + + //swNotifyFans + binding.swNotifyFans.click { + mIsNotifyFans = !mIsNotifyFans + binding.swNotifyFans.setImageResource(if (mIsNotifyFans) R.drawable.icon_room_set_lock_true else R.drawable.icon_room_set_lock_false) + } + + //btnNext + binding.btnNext.click { + if (MyUtil.isDoubleClick()) return@click + startPublic() + } + + mSelectImg?.let { + ImageLoadUtils.loadImage(binding.pic.context, it.path, binding.pic) + checkInput() + } + + getConfig().doOnSuccess { + mConfig = it + try { + val iconStr = "-icon63-" + val value = if (context.isRtl()) "$iconStr ${it.goldNum}" else "${it.goldNum} $iconStr" + val str = R.string.v_27_Banner_Costs.getString(value) + val iconStrStar = str.indexOf(iconStr) + val spannable = SpannableString(str) + R.drawable.ic_coin_63.getDrawable()?.let { icon-> + icon?.setBounds(0, 0, icon.intrinsicWidth, icon.intrinsicHeight) + spannable.setSpan(ImageSpan(icon,ImageSpan.ALIGN_BOTTOM), iconStrStar, iconStrStar+(iconStr.length), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) + } + binding.payBanner.text = spannable + } catch (e: Exception) { + binding.payBanner.text = R.string.v_27_Banner_Costs.getString(it.goldNum) + } + + }.doOnError { + it?.message?.doToast() + finish() + }.subscribe() + + checkInput() + + binding.keyboardMarks.click { + binding.keyboardMarks.setVis(false) + KeyBoardUtils.hideDialogSoftInput(this) + } + + KeyboardUtils.observerKeyboardChange(this,object : KeyboardUtils.OnKeyboardChangeListener { + override fun onKeyboardChange(p0: Rect?, p1: Boolean) { +// "键盘 $p1".doLog() + binding.keyboardMarks.setVis(p1) + } + }) + + + + + } + + private fun showStartTimePick() { + val now = Calendar.getInstance() + + // 最小时间:当前时间 + 25 小时 + val minCalendar = now.clone() as Calendar + minCalendar.add(Calendar.HOUR_OF_DAY, 25) + + // 最大时间:当前时间 + 25 小时 + 1 个月 + val maxCalendar = now.clone() as Calendar + maxCalendar.add(Calendar.HOUR_OF_DAY, 25) + maxCalendar.add(Calendar.MONTH, 1) + maxCalendar.set(Calendar.HOUR_OF_DAY, 23) + maxCalendar.set(Calendar.MINUTE, 59) + maxCalendar.set(Calendar.SECOND, 59) + maxCalendar.set(Calendar.MILLISECOND, 999) + + val builder = TimePickerDialog.Builder() + .setType(Type.MONTH_DAY_HOUR_MIN) + .setMinMillseconds(minCalendar.timeInMillis) + .setMaxMillseconds(maxCalendar.timeInMillis) + .setCancelStringId(R.string.cancel.getString()) + .setSureStringId(R.string.confirm.getString()) + .setCyclic(false) + .setMonthText("") + .setDayText("") + .setHourText(":00") + .setTitleStringId(R.string.v_27_Start_Time.getString()) + .setThemeColor(resources.getColor(R.color.line_color)) + .setWheelItemTextNormalColor( + resources.getColor(R.color.timetimepicker_default_text_color) + ) + .setWheelItemTextSelectorColor(resources.getColor(R.color.black)) + + val dialog = builder.build() + dialog.mTestSize = 15f + dialog.setmTimePickerListener { chooseTime, weekFirstDay, weekLastDay -> + mStartTime = chooseTime + binding.tvStartTime.text = MyTimeUtils.millis2String(chooseTime, SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH)) + } + dialog.show(supportFragmentManager, "StartTime") + } + + private fun showDurationPick() { + val eventDurationDialog = EventDurationDialog() + eventDurationDialog.setData(mConfig) + eventDurationDialog.mActionCallBack = object : BaseDialogFragment.Action { + override fun onAction(type: Int, data: Any?) { + if (type != -1 && data is Int) { + mDuration = type + binding.tvDuration.text = EventCenterUtil.formatDuration(type.toLong()) + mPayGoldNum = data + } + checkInput() + } + } + eventDurationDialog?.show(context) + } + + + /** + * 第三方图片裁剪框架Ucrop + */ + private fun crop(sourceUri: Uri?, sourceSize: Long, destinationUri: Uri?) { + if (sourceUri == null || destinationUri == null) { + return + } + //防止too large导致oom,大于100m不处理,内存大小 + if (BitmapUtil.getSdBitmapSize(sourceUri) >= MAX_BITMAP_SIZE) { + toast(R.string.text_bitmap_too_large) + return + } + + val options = UCrop.Options().apply { + setCompressionQuality(100) + setShowCropGrid(false) + setToolbarColor( + ContextCompat.getColor( + App.gContext, + android.R.color.black + ) + ) + setStatusBarColor( + ContextCompat.getColor( + App.gContext, + android.R.color.black + ) + ) + setHideBottomControls(true) + setCompressionFormat(Bitmap.CompressFormat.JPEG) + setToolbarCancelDrawable(R.drawable.user_ucrop_ic_closs) + setToolbarCropDrawable(R.drawable.user_ucrop_ic_sure) + setToolbarWidgetColor( + ContextCompat.getColor( + App.gContext, + R.color.color_white + ) + ) + } + + UCrop.of(sourceUri, destinationUri) + .withOptions(options) + .withAspectRatio(690f, 236f) // 设置裁剪比例为 690:236 + .withMaxResultSize(690, 236) // 最终输出图片尺寸为 690x236 像素 + .start(this) + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (resultCode == RESULT_OK) { + when (requestCode) { + UCrop.REQUEST_CROP -> { + mSelectImg = mUri + mSelectImg?.let { + ImageLoadUtils.loadImage(binding.pic.context,it.path,binding.pic) + binding.picIcon.setVis(true) + checkInput() + } + } + } + } + } + + + + private fun startPublic() { + if (mSelectImg != null) { + mSelectImg?.path?.let { + try { + dialogManager.showProgressDialog( + this@EventCreateActivity, + R.string.ui_user_userinfomodifyactivity_09.getString() + ) + mJob?.cancel() + mJob = PhotoCompressUtil.compress( + this@EventCreateActivity, + it, + PhotoCompressUtil.getCompressCachePath(), + object : PhotoCompressCallback { + @SuppressLint("CheckResult") + override fun onSuccess(compressedImg: String) { + FileModel.get() + .uploadFile(compressedImg) + .compose(bindToLifecycle()) + .doOnSuccess { ossUrl -> + if (ossUrl.isVerify()) { + val uid = AuthModel.get().currentUid + val eventTopic = binding.etTitle.text?.toString() ?: "" + val eventBanner = ossUrl + val payBanner = if (mIsShowHomePage == true) 1 else 0 + val roomUid = mSelectRoomId + val eventStartTimeStr = mStartTime + val eventDuration = mDuration + val eventDetail = + binding.etContent.text?.toString() ?: "" + val noticeFans = if (mIsNotifyFans) 1 else 0 + var payGoldNum = mPayGoldNum + + + if (eventStartTimeStr != null + && eventDuration != null + && payGoldNum != null + && eventTopic.isVerify() + && roomUid != null + && eventDetail.isVerify() + ) { + val millis2String = MyTimeUtils.millis2String( + eventStartTimeStr, + SimpleDateFormat( + "yyyy-MM-dd HH:mm:ss", + Locale.ENGLISH + ) + ) + "打印上传参数 uid=$uid eventTopic=$eventTopic eventBanner=$eventBanner payBanner=$payBanner roomUid=$roomUid eventStartTimeStr=$eventStartTimeStr eventDuration=$eventDuration eventDetail=$eventDetail noticeFans=$noticeFans payGoldNum=$payGoldNum timeStr=$millis2String".doLog() + postPublish( + uid, + eventTopic, + eventBanner, + payBanner, + roomUid, + millis2String, + eventDuration, + eventDetail, + noticeFans, + payGoldNum + ) + .compose(bindToLifecycle()) + .doOnSuccess { + dialogManager?.dismissDialog() + ToastUtils.show(R.string.doSuccess) + finish() + } + .doOnError { er -> + dialogManager?.dismissDialog() + er?.message?.let { msg -> + ToastUtils.show(msg) + } + } + .subscribe() + } else { + R.string.exception_try_again.doToast() + dialogManager?.dismissDialog() + } + } else { + R.string.exception_try_again.doToast() + dialogManager?.dismissDialog() + } + } + .doOnError { + dialogManager?.dismissDialog() + it?.message?.let { msg -> + ToastUtils.show(msg) + } + } + .subscribe() + } + + override fun onFail(e: Throwable) { + e?.message?.doToast() + dialogManager?.dismissDialog() + } + }, + leastCompressSize = (1024 * 2), + mostCompressSize = (1024 * 6) + ) + } catch (e: FileNotFoundException) { + R.string.exception_try_again.doToast() + dialogManager?.dismissDialog() + } + } + } else { + R.string.exception_try_again.doToast() + dialogManager?.dismissDialog() + } + } + + private fun checkInput() { + var canPublic = true + if (binding.etTitle.text?.toString()?.isVerify() == false) canPublic = false + if (mSelectImg == null) canPublic = false + if (mIsShowHomePage == null) canPublic = false + if (mSelectRoomId == null) canPublic = false + if (mStartTime == null) canPublic = false + if (mDuration == null) canPublic = false + if (binding.etContent.text?.toString()?.isVerify() == false) canPublic = false + binding.btnNext.alpha = if (canPublic) 1f else 0.5f + binding.btnNext.isEnabled = canPublic + } + + override fun onDestroy() { + super.onDestroy() + dialogManager.dismissDialog() + mJob?.cancel() + } + + private fun postPublish( + uid: Long, + eventTopic: String, + eventBanner: String, + payBanner: Int, + roomUid: Long, + eventStartTimeStr: String, + eventDuration: Int, + eventDetail: String, + noticeFans: Int, + payGoldNum: Int + ): Single { + return api.postPublish(uid, eventTopic, eventBanner, payBanner, roomUid, eventStartTimeStr, eventDuration, eventDetail, noticeFans, payGoldNum) + .compose(RxHelper.handleIgnoreData()) + .compose(RxHelper.handleSchedulers()) + } + + + private fun getConfig(): Single { + return api.getConfig(AuthModel.get().currentUid) + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()) + } + + + private val api: Api = RxNet.create(Api::class.java); + + interface Api { + + @POST("/userevent/publish") + fun postPublish( + @Query("uid") uid: Long, + @Query("eventTopic") eventTopic: String, + @Query("eventBanner") eventBanner: String, + @Query("payBanner") payBanner: Int, + @Query("roomUid") roomUid: Long, + @Query("eventStartTimeStr") eventStartTimeStr: String, + @Query("eventDuration") eventDuration: Int, + @Query("eventDetail") eventDetail: String, + @Query("noticeFans") noticeFans: Int, + @Query("payGoldNum") payGoldNum: Int + ): Single> + + + @GET("/userevent/goldConfig") + fun getConfig( @Query("uid") uid: Long): Single> + } + + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/activity/EventMyAllActivity.kt b/app/src/main/java/com/chwl/app/home/activity/EventMyAllActivity.kt new file mode 100644 index 0000000..fb3c51c --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/activity/EventMyAllActivity.kt @@ -0,0 +1,208 @@ +package com.chwl.app.home.activity + +import android.content.Context +import android.content.Intent +import android.view.ViewGroup +import com.chwl.app.R +import com.chwl.app.avroom.activity.AVRoomActivity +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.common.EmptyViewHelper +import com.chwl.app.databinding.ActivityEventMyAllBinding +import com.chwl.app.home.adapter.EventSquareAdapter +import com.chwl.app.ui.webview.CommonWebViewActivity +import com.chwl.core.UriProvider +import com.chwl.core.auth.AuthModel +import com.chwl.core.bean.EventOfficialBean +import com.chwl.core.bean.response.ServiceResult +import com.chwl.core.utils.net.RxHelper +import com.chwl.library.common.util.doToast +import com.chwl.library.common.util.isVerify +import com.chwl.library.common.util.setVis +import com.chwl.library.net.rxnet.RxNet +import com.example.lib_utils.ktx.getString +import com.google.gson.JsonElement +import com.scwang.smart.refresh.layout.api.RefreshLayout +import com.scwang.smart.refresh.layout.listener.OnRefreshLoadMoreListener + + +import io.reactivex.Single +import retrofit2.http.GET +import retrofit2.http.POST +import retrofit2.http.Query + +class EventMyAllActivity : BaseViewBindingActivity() { + + + private lateinit var mAdapter: EventSquareAdapter + private var mPage = 1; + override fun init() { + initLightTitleBar(R.string.v_27_My_Event.getString()) + + + mAdapter = EventSquareAdapter(true) + val emptyView = EmptyViewHelper.createEmptyView( + context, R.drawable.base_status_empty, R.string.empty_data.getString(), + ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ) + ) + mAdapter.emptyView = emptyView + mAdapter.setOnItemClickListener { baseQuickAdapter, view, i -> + mAdapter.data.isVerify(i){ + CommonWebViewActivity.start(context, UriProvider.getEventDetail(it.id)) + } + } + mAdapter.setOnItemChildClickListener { baseQuickAdapter, view, i -> + when (view.id) { + R.id.btnNext -> { + mAdapter.data?.isVerify(i){ + when (it.btnStatus) { + EventSquareAdapter.B_IN_ROOM-> { + AVRoomActivity.start(context,it.roomUid) + + } + EventSquareAdapter.B_SUB->{ + doEventSub(mAdapter,it,i) + } + EventSquareAdapter.B_DEL->{ + doEventDel(mAdapter,it,i) + } + } + } + } + } + } + binding.rvList.adapter = mAdapter + + binding.srlList.setOnRefreshLoadMoreListener(object : OnRefreshLoadMoreListener { + override fun onRefresh(p0: RefreshLayout) { + mPage = 1 + getData() + } + + override fun onLoadMore(p0: RefreshLayout) { + getData() + } + }) + binding.srlList.autoRefresh() + + + } + + private fun getData() { + getEventMySquare() + .compose(bindToLifecycle()) + .doOnSuccess { + if (mPage == 1) { + mAdapter.setNewData(it) + } else { + mAdapter.addData(it) + } + + if (it.size == 20) { + mPage++ + } + + binding.srlList.setEnableLoadMore(it.size == 20) + binding.end.setVis(it.size != 20) + binding.srlList.finishRefresh() + binding.srlList.finishLoadMore() + } + .doOnError { + binding.srlList.finishRefresh() + binding.srlList.finishLoadMore() + it?.message?.doToast() + }.subscribe() + + } + + + private fun doEventSub( + adapter: EventSquareAdapter, + eventOfficialBean: EventOfficialBean, + pos: Int + ) { + val status = !eventOfficialBean.isSubStatus + val statusInt = if (status) 1 else 0 + postSub(eventOfficialBean.id, statusInt) + .compose(bindToLifecycle()) + .doOnSuccess { + adapter.data.isVerify(pos) { + it.subStatus = status + adapter.notifyItemChanged(pos) + } + } + .doOnError { + it?.message?.doToast() + }.subscribe() + } + + private fun doEventDel( + adapter: EventSquareAdapter, + eventOfficialBean: EventOfficialBean, + pos: Int + ) { + postDel(eventOfficialBean.id) + .compose(bindToLifecycle()) + .doOnSuccess { + adapter.data.isVerify(pos) { + adapter.remove(pos) + } + } + .doOnError { + it?.message?.doToast() + }.subscribe() + } + + + private fun getEventMySquare(): Single> { + return api.getEventMySquare(AuthModel.get().currentUid,mPage,20) + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()) + } + + + + private fun postSub(eventId: Long,subStatus:Int): Single { + return api.postSub(AuthModel.get().currentUid,eventId,subStatus) + .compose(RxHelper.handleIgnoreData()) + .compose(RxHelper.handleSchedulers()) + } + + private fun postDel(eventId: Long): Single { + return api.postDel(eventId) + .compose(RxHelper.handleIgnoreData()) + .compose(RxHelper.handleSchedulers()) + } + + + private val api: Api = RxNet.create(Api::class.java); + interface Api { + @GET("/userevent/mysquare") + fun getEventMySquare( @Query("uid") uid: Long,@Query("page") page: Int, @Query("pageSize") pageSize: Int): Single>> + + @POST("/userevent/sub") + fun postSub( + @Query("uid") uid: Long, + @Query("eventId") eventId: Long, + @Query("subStatus") subStatus: Int + ): Single> + + @POST("/userevent/del") + fun postDel( + @Query("eventId") eventId: Long, + ): Single> + + } + + companion object{ + @JvmStatic + fun start(context: Context) { + val starter = Intent(context, EventMyAllActivity::class.java) + context.startActivity(starter) + } + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/activity/EventSelectRoomActivity.kt b/app/src/main/java/com/chwl/app/home/activity/EventSelectRoomActivity.kt new file mode 100644 index 0000000..10ca8c4 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/activity/EventSelectRoomActivity.kt @@ -0,0 +1,126 @@ +package com.chwl.app.home.activity + +import android.content.Context +import android.content.Intent +import android.view.View +import android.view.ViewGroup +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.common.EmptyViewHelper +import com.chwl.app.databinding.ActivityEventSelectRoomBinding +import com.chwl.app.home.adapter.EventSelectRoomAdapter +import com.chwl.app.ui.utils.loadImage +import com.chwl.core.auth.AuthModel +import com.chwl.core.bean.EventRoomBean +import com.chwl.core.bean.EventRoomEntity +import com.chwl.core.bean.response.ServiceResult +import com.chwl.core.utils.net.RxHelper +import com.chwl.library.common.util.ClickUtils.click +import com.chwl.library.common.util.doToast +import com.chwl.library.common.util.isVerify +import com.chwl.library.common.util.setVis +import com.chwl.library.net.rxnet.RxNet +import com.example.lib_utils.ktx.getString +import io.reactivex.Single +import retrofit2.http.GET + +class EventSelectRoomActivity : BaseViewBindingActivity() { + + companion object{ + @JvmStatic + fun start(context: Context) { + val starter = Intent(context, EventSelectRoomActivity::class.java) + context.startActivity(starter) + } + } + + private lateinit var mAdapter: EventSelectRoomAdapter + private lateinit var mEmptyView : View + private var mMyRoom: EventRoomBean?=null + + + + override fun init() { + initLightTitleBar(R.string.v_27_Select_Room.getString()) + + binding.myRoom.click { + if (mMyRoom== null) return@click + val data = Intent() + data.putExtra("roomId",mMyRoom?.roomUid) + data.putExtra("erbanNo",mMyRoom?.erbanNo) + setResult(RESULT_OK,data) + finish() + } + + mEmptyView = EmptyViewHelper.createEmptyView( + context, R.drawable.base_status_empty, R.string.v_27_No_rooms_available.getString(), + ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ) + ) + + val emptyView = EmptyViewHelper.createEmptyView( + context, R.drawable.base_status_empty, R.string.v_27_No_rooms_available.getString(), + ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ) + ) + mAdapter = EventSelectRoomAdapter() + mAdapter.emptyView = emptyView + mAdapter.onItemClickListener = object : BaseQuickAdapter.OnItemClickListener { + override fun onItemClick(p0: BaseQuickAdapter<*, *>?, p1: View?, p2: Int) { + mAdapter.data.isVerify(p2){ bean-> + val data = Intent() + data.putExtra("roomId",bean.roomUid) + data.putExtra("erbanNo",bean.erbanNo) + setResult(RESULT_OK,data) + finish() + } + } + } + binding.rvList.adapter = mAdapter + + + binding.emptyLayout.addView(mEmptyView.rootView) + + getListRoom() + .compose(bindToLifecycle()) + .doOnSuccess { + it?.selfRoom?.let{ room -> + if (room.roomUid == AuthModel.get().currentUid) { + mMyRoom = room + binding.emptyLayout.setVis(false) + binding.roomUid.text = R.string.text_user_id.getString(room.erbanNo) + binding.name.text = room.roomName + binding.avatar.loadImage(room.avatar) + } + } + mAdapter.setNewData(it.manageRooms) + } + .doOnError { + it?.message?.doToast() + }.subscribe() + + } + + + + + private fun getListRoom(): Single { + return api.getListRoom() + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()) + } + + + private val api: Api = RxNet.create(Api::class.java); + interface Api { + @GET("/roomrole/listroom") + fun getListRoom(): Single> + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/activity/NewUserListActivity.java b/app/src/main/java/com/chwl/app/home/activity/NewUserListActivity.java new file mode 100644 index 0000000..3c0d4b4 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/activity/NewUserListActivity.java @@ -0,0 +1,139 @@ +package com.chwl.app.home.activity; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; + +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chwl.app.R; +import com.chwl.app.base.BaseMvpActivity; +import com.chwl.app.home.adapter.FindNewUserListAdapter; +import com.chwl.app.home.presenter.NewUserListPresenter; +import com.chwl.app.home.view.INewUserListActivityView; +import com.chwl.library.common.util.Utils; +import com.chwl.app.ui.widget.recyclerview.decoration.SpacingDecoration; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.library.base.factory.CreatePresenter; +import com.chwl.library.utils.ListUtils; + +import java.util.List; + +import io.reactivex.SingleObserver; +import io.reactivex.disposables.Disposable; +import io.reactivex.functions.Action; + +@CreatePresenter(NewUserListPresenter.class) +public class NewUserListActivity extends BaseMvpActivity + implements INewUserListActivityView, SwipeRefreshLayout.OnRefreshListener, BaseQuickAdapter.RequestLoadMoreListener { + + private SwipeRefreshLayout srlRefreshContainer; + private RecyclerView rvList; + private FindNewUserListAdapter adapter; + + public static void start(Context context) { + Intent intent = new Intent(context, NewUserListActivity.class); + context.startActivity(intent); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_new_user_list); + initTitleBar(getString(R.string.find_newer_list_title)); + + srlRefreshContainer = (SwipeRefreshLayout) findViewById(R.id.srl_refresh_container); + rvList = (RecyclerView) findViewById(R.id.rv_list); + + rvList.setLayoutManager(new GridLayoutManager(this, 3)); + rvList.addItemDecoration(new SpacingDecoration( + Utils.dip2px(this, 10), + Utils.dip2px(this, 20), + false)); + + adapter = new FindNewUserListAdapter(this, null); + adapter.setEnableLoadMore(true); + adapter.setOnLoadMoreListener(this, rvList); + rvList.setAdapter(adapter); + + srlRefreshContainer.setOnRefreshListener(this); + } + + + @Override + protected void onResume() { + super.onResume(); + if (ListUtils.isListEmpty(adapter.getData())) { + srlRefreshContainer.setRefreshing(true); + onRefresh(); + } + } + + @Override + public void onReloadDate() { + super.onReloadDate(); + srlRefreshContainer.setRefreshing(true); + onRefresh(); + } + + @Override + public void onRefresh() { + getMvpPresenter().refreshData() + .doAfterTerminate(new Action() { + @Override + public void run() throws Exception { + srlRefreshContainer.setRefreshing(false); + } + }) + .subscribe(new SingleObserver>() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onSuccess(List userInfos) { + if (ListUtils.isListEmpty(userInfos)) { + showNoData(); + return; + } + adapter.setNewData(userInfos); + } + + @Override + public void onError(Throwable e) { + showNetworkErr(); + toast(e.getMessage()); + } + }); + } + + @Override + public void onLoadMoreRequested() { + getMvpPresenter().loadMoreData() + .subscribe(new SingleObserver>() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onSuccess(List userInfos) { + if (ListUtils.isListEmpty(userInfos)) { + adapter.loadMoreEnd(true); + return; + } + adapter.addData(userInfos); + adapter.loadMoreComplete(); + } + + @Override + public void onError(Throwable e) { + toast(e.getMessage()); + } + }); + } +} diff --git a/app/src/main/java/com/chwl/app/home/activity/RoomHistoryListActivity.kt b/app/src/main/java/com/chwl/app/home/activity/RoomHistoryListActivity.kt new file mode 100644 index 0000000..8959e50 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/activity/RoomHistoryListActivity.kt @@ -0,0 +1,97 @@ +package com.chwl.app.home.activity + +import android.annotation.SuppressLint +import android.content.Context +import android.content.Intent +import android.graphics.Color +import android.view.View +import androidx.recyclerview.widget.LinearLayoutManager +import com.netease.nim.uikit.StatusBarUtil +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.base.TitleBar +import com.chwl.app.common.EmptyViewHelper +import com.chwl.app.databinding.ActivityRoomHistoryListBinding +import com.chwl.app.home.adapter.RoomHistoryListAdapter +import com.chwl.app.ui.utils.RVDelegate +import com.chwl.core.bean.RoomHistoryInfo +import com.chwl.core.user.UserModel +import com.chwl.library.annatation.ActLayoutRes +import com.chwl.library.utils.ResUtil +import com.chwl.library.utils.SingleToastUtil + +@ActLayoutRes(R.layout.activity_room_history_list) +class RoomHistoryListActivity : BaseViewBindingActivity() { + + private lateinit var rvDelegate: RVDelegate + + companion object { + @JvmStatic + fun start(context: Context) { + val starter = Intent(context, RoomHistoryListActivity::class.java) + context.startActivity(starter) + } + } + + @SuppressLint("CheckResult") + override fun init() { + initTitleBar(ResUtil.getString(R.string.home_activity_roomhistorylistactivity_01)) + mTitleBar?.addAction(object : TitleBar.TextAction( + ResUtil.getString(R.string.home_activity_roomhistorylistactivity_02), Color.parseColor("#999999") + ) { + override fun performAction(view: View) { + dialogManager.showOkCancelDialog( + ResUtil.getString(R.string.home_activity_roomhistorylistactivity_03), ResUtil.getString(R.string.home_activity_roomhistorylistactivity_04), ResUtil.getString(R.string.home_activity_roomhistorylistactivity_05) + ) { clearHistory() } + } + }) + rvDelegate = RVDelegate.Builder() + .setRefreshLayout(binding.swipeRefresh) + .setLayoutManager(LinearLayoutManager(this)) + .setRecyclerView(binding.recyclerView) + .setAdapter(RoomHistoryListAdapter()) + .setEmptyView(EmptyViewHelper.createEmptyTextView(this, ResUtil.getString(R.string.home_activity_roomhistorylistactivity_06))) + .build() + + binding.swipeRefresh.setOnRefreshListener { + loadData() + } + loadData() + } + + @SuppressLint("CheckResult") + private fun clearHistory() { + UserModel.get() + .deleteInRoomRecord() + .compose(bindToLifecycle()) + .flatMap { UserModel.get().updateCurrentUserInfo() } + .subscribe({ + rvDelegate.setNewData(null) + }, { + SingleToastUtil.showToast(ResUtil.getString(R.string.home_activity_roomhistorylistactivity_07)) + }) + } + + @SuppressLint("CheckResult") + private fun loadData() { + UserModel.get() + .inRoomRecord + .compose(bindToLifecycle()) + .subscribe( + { + rvDelegate.loadData(it, true) + }, + { + rvDelegate.loadErr(true) + } + ) + } + + override fun needSteepStateBar() = true + + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/activity/VisitorListActivity.kt b/app/src/main/java/com/chwl/app/home/activity/VisitorListActivity.kt new file mode 100644 index 0000000..e65f0e0 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/activity/VisitorListActivity.kt @@ -0,0 +1,101 @@ +package com.chwl.app.home.activity + +import android.annotation.SuppressLint +import android.content.Context +import android.content.Intent +import androidx.recyclerview.widget.LinearLayoutManager +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.common.EmptyViewHelper +import com.chwl.app.databinding.ActivityVisitorListBinding +import com.chwl.app.home.adapter.VisitorListAdapter +import com.chwl.app.ui.utils.RVDelegate +import com.chwl.app.vip.VipCenterActivity +import com.chwl.core.home.bean.VisitorInfo +import com.chwl.core.home.event.VisitorUnreadCountEvent +import com.chwl.core.user.UserModel +import com.chwl.library.annatation.ActLayoutRes +import com.chwl.library.common.util.ClickUtils.click +import com.chwl.library.common.util.setVis +import com.chwl.library.utils.ResUtil +import com.netease.nim.uikit.StatusBarUtil +import org.greenrobot.eventbus.EventBus + +@ActLayoutRes(R.layout.activity_visitor_list) +class VisitorListActivity : BaseViewBindingActivity() { + + private lateinit var rvDelegate: RVDelegate + + companion object { + @JvmStatic + fun start(context: Context) { + val starter = Intent(context, VisitorListActivity::class.java) + context.startActivity(starter) + } + } + + private var pageNum = 1 + private val pageSize = 20 + private var mVisitListVipLimit = -1 + @SuppressLint("CheckResult") + override fun init() { + EventBus.getDefault().postSticky(VisitorUnreadCountEvent(0)) + initTitleBar(ResUtil.getString(R.string._ver_24_visitor)) + rvDelegate = RVDelegate.Builder() + .setRefreshLayout(binding.swipeRefresh) + .setLayoutManager(LinearLayoutManager(this)) + .setRecyclerView(binding.recyclerView) + .setAdapter(VisitorListAdapter()) + .setPageSize(pageSize) + .setEmptyView(EmptyViewHelper.createEmptyTextView(this, ResUtil.getString(R.string.home_activity_visitorlistactivity_02))) + .build() + + rvDelegate.adapter.setOnLoadMoreListener({ loadData(false) }, binding.recyclerView) + + binding.swipeRefresh.setOnRefreshListener { + loadData(true) + } + + loadData(true) + + + + UserModel.get().cacheLoginUserInfo?.let { + binding.vipLayout.setVis(!(it?.userVipInfoVO?.visitHide ?: false)) + } + + //xxx vip等级设置为 visitListVipLimit + UserModel.get().userMineInfo.compose(bindToLifecycle()).doOnSuccess { + mVisitListVipLimit = it.visitListVipLimit + + binding.vipLayout.click { + VipCenterActivity.start(context,mVisitListVipLimit) + } + + }.subscribe() + + } + + @SuppressLint("CheckResult") + private fun loadData(refresh: Boolean) { + pageNum = if (refresh) 1 else pageNum + 1 + UserModel.get().getVisitorUserList(pageNum, pageSize) + .compose(bindToLifecycle()) + .subscribe( + { + rvDelegate.loadData(it, refresh) + }, + { + rvDelegate.loadErr(true) + } + ) + } + + override fun needSteepStateBar() = true + + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/adapter/BannerAdapter.java b/app/src/main/java/com/chwl/app/home/adapter/BannerAdapter.java new file mode 100644 index 0000000..a11c756 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/adapter/BannerAdapter.java @@ -0,0 +1,86 @@ +package com.chwl.app.home.adapter; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; + +import com.chwl.app.R; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.app.ui.widget.rollviewpager.adapter.StaticPagerAdapter; +import com.chwl.app.utils.CommonJumpHelper; +import com.chwl.core.home.bean.BannerInfo; + +import java.util.List; + +/** + * @author Administrator + * @date 2017/8/7 + */ + +public class BannerAdapter extends StaticPagerAdapter { + private Context context; + private List bannerInfoList; + private LayoutInflater mInflater; + private int roundingRadius = -1; + private OnItemClickListener mOnItemClickListener; + + public BannerAdapter(List bannerInfoList, Context context) { + this.context = context; + this.bannerInfoList = bannerInfoList; + mInflater = LayoutInflater.from(context); + } + + public void setBannerInfoList(List bannerInfoList) { + this.bannerInfoList = bannerInfoList; + } + + public void setOnItemClickListener(OnItemClickListener onItemClickListener) { + this.mOnItemClickListener = onItemClickListener; + } + + @Override + public View getView(ViewGroup container, int position) { + BannerInfo bannerInfo = bannerInfoList.get(position); + ImageView imgBanner = (ImageView) mInflater.inflate(R.layout.banner_page_item, container, false); + if (bannerInfo == null) return imgBanner; + ImageLoadUtils.loadRectImage(context, + bannerInfo.getBannerPic(), + imgBanner, + R.drawable.default_banner, + roundingRadius); + imgBanner.setOnClickListener(v -> { + CommonJumpHelper.bannerJump(context, bannerInfo); + if (mOnItemClickListener != null) { + mOnItemClickListener.onItemClick(position, bannerInfo); + } + }); + return imgBanner; + } + + public void setRoundingRadius(int roundingRadius) { + this.roundingRadius = roundingRadius; + } + + @Override + public int getCount() { + return bannerInfoList == null ? 0 : bannerInfoList.size(); + + } + + public void setData(List bannerInfos) { + this.bannerInfoList = bannerInfos; + } + + + public interface OnItemClickListener { + /** + * item点击事件,用于做banner点击埋点 + * + * @param position + * @param bannerInfo + */ + void onItemClick(int position, BannerInfo bannerInfo); + } +} diff --git a/app/src/main/java/com/chwl/app/home/adapter/CollectionRoomAdapter.java b/app/src/main/java/com/chwl/app/home/adapter/CollectionRoomAdapter.java new file mode 100644 index 0000000..9f43116 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/adapter/CollectionRoomAdapter.java @@ -0,0 +1,35 @@ +package com.chwl.app.home.adapter; + +import android.widget.ImageView; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.app.ui.utils.ImageLoadUtilsV2; +import com.chwl.core.home.bean.HomeRoomInfo; + +/** + * Created by yudi + * on 2018/3/2. + */ +public class CollectionRoomAdapter extends BaseQuickAdapter { + + public CollectionRoomAdapter() { + super(R.layout.item_room_collection); + + } + + @Override + protected void convert(BaseViewHolder helper, HomeRoomInfo item) { + + helper.setText(R.id.tv_room_name,item.getRoomName()) + .setText(R.id.tv_room_id,"ID:"+item.getErbanNo()) + .setText(R.id.tv_room_online_num,item.getRoomOnlineNum() +""); + ImageView imageView = helper.getView(R.id.rriv_room_img); + ImageLoadUtilsV2.loadImage(imageView, item.getRoomAvatar()); + + helper.addOnClickListener(R.id.cl_root); + + + } +} diff --git a/app/src/main/java/com/chwl/app/home/adapter/CommunityNoticeAdapter.java b/app/src/main/java/com/chwl/app/home/adapter/CommunityNoticeAdapter.java new file mode 100644 index 0000000..254ce43 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/adapter/CommunityNoticeAdapter.java @@ -0,0 +1,88 @@ +package com.chwl.app.home.adapter; + + +import android.text.TextUtils; +import android.widget.TextView; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.app.common.widget.CircleImageView; +import com.chwl.app.common.widget.RectRoundImageView; +import com.chwl.app.ui.utils.ImageLoadUtilsV2; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.community.bean.CommunityNoticeInfo; +import com.chwl.core.community.bean.DynamicMedia; +import com.chwl.library.utils.TimeUtils; + +public class CommunityNoticeAdapter extends BaseQuickAdapter { + + public CommunityNoticeAdapter() { + super(R.layout.item_community_notice_list); + } + + @Override + protected void convert(BaseViewHolder helper, CommunityNoticeInfo item) { + + if (item == null) { + return; + } + + CircleImageView circleImageView = helper.getView(R.id.civ_avatar_community_notice_list); + ImageLoadUtilsV2.loadImage(circleImageView, item.getAvatar()); + + String worldName = item.getWorldName(); + helper.setText(R.id.tv_name_mini_world, "#" + worldName) + .setGone(R.id.tv_name_mini_world, !TextUtils.isEmpty(worldName)); + helper.setText(R.id.tv_name_community_notice_list, item.getNick()); + + helper.setGone(R.id.iv_gender, true) + .setImageResource(R.id.iv_gender, item.isMale() ? R.drawable.ic_gender_male : R.drawable.ic_gender_female); + + helper.setGone(R.id.tv_right_content, false) + .setGone(R.id.rriv_right_content, false); + DynamicMedia dynamicMedia = item.getDynamicRes(); + switch (item.getType()) { + case 0: // 纯文本 + helper.setGone(R.id.tv_right_content, true) + .setText(R.id.tv_right_content, item.getContent()); + break; + case 1: // 语音 + break; + case 2: // 图片 + case 3: // 视频 + helper.setGone(R.id.rriv_right_content, true); + if (dynamicMedia != null) { + RectRoundImageView rectRoundImageView = helper.getView(R.id.rriv_right_content); + ImageLoadUtilsV2.loadImage(rectRoundImageView, dynamicMedia.getResUrl()); + } + break; + + } + + helper.setGone(R.id.tv_label_community_notice_list, false); + TextView textView = helper.getView(R.id.tv_content_community_notice_list); + textView.setText(item.getMessage()); + switch (item.getActionType()) { + case 1: // 评论 + if (item.getTargetUid() == AuthModel.get().getCurrentUid()) { + helper.setGone(R.id.tv_label_community_notice_list, true); + } else { + helper.setGone(R.id.tv_label_community_notice_list, false); + } + break; + case 2: // 回复 + // TODO 区分动态/评论 + break; + case 3: // 点赞 + // TODO 区分动态/评论 + break; + } + + helper.setText(R.id.tv_time_community_notice_list, TimeUtils.getTimeStringFromMillis(item.getPublishTime())); + + helper.addOnClickListener(R.id.cl_community_notice_list); + helper.addOnClickListener(R.id.civ_avatar_community_notice_list); + + } +} diff --git a/app/src/main/java/com/chwl/app/home/adapter/ContactsIndicatorAdapter.java b/app/src/main/java/com/chwl/app/home/adapter/ContactsIndicatorAdapter.java new file mode 100644 index 0000000..5378776 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/adapter/ContactsIndicatorAdapter.java @@ -0,0 +1,117 @@ +package com.chwl.app.home.adapter; + +import android.content.Context; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import androidx.appcompat.widget.AppCompatTextView; + +import com.chwl.app.R; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.CommonNavigatorAdapter; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.indicators.LinePagerIndicator; +import com.chwl.library.common.util.Utils; + +import java.util.List; + +/** + * @author jack + * @Description + * @Date 2018/11/1 + */ +public class ContactsIndicatorAdapter extends CommonNavigatorAdapter { + private List mTitleList; + private Context mContext; + private int mBottomMargin; + + public ContactsIndicatorAdapter(Context mContext, List mTitleList, int bottomMargin) { + this.mTitleList = mTitleList; + this.mContext = mContext; + mBottomMargin = bottomMargin; + } + + @Override + public int getCount() { + return mTitleList == null ? 0 : mTitleList.size(); + } + + @Override + public IPagerTitleView getTitleView(Context context, int index) { + ContactsPagerTitleView categoryPagerTitleView = new ContactsPagerTitleView(context, mTitleList.get(index)); + categoryPagerTitleView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (null != mOnItemSelectListener) { + mOnItemSelectListener.onItemSelect(index); + } + } + }); + return categoryPagerTitleView; + } + + @Override + public IPagerIndicator getIndicator(Context context) { + LinePagerIndicator indicator = new LinePagerIndicator(context); + indicator.setMode(LinePagerIndicator.MODE_EXACTLY); + indicator.setLineHeight(UIUtil.dip2px(mContext, 5)); + indicator.setRoundRadius(UIUtil.dip2px(mContext, 5)); + indicator.setLineWidth(UIUtil.dip2px(mContext, 9)); + indicator.setColors(context.getResources().getColor(R.color.app_248cfe)); + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + lp.bottomMargin = mBottomMargin; + indicator.setLayoutParams(lp); + return indicator; + } + + private OnItemSelectListener mOnItemSelectListener; + + public void setOnItemSelectListener(OnItemSelectListener onItemSelectListener) { + mOnItemSelectListener = onItemSelectListener; + } + + public interface OnItemSelectListener { + void onItemSelect(int position); + } + + class ContactsPagerTitleView extends AppCompatTextView implements IPagerTitleView { + + + public ContactsPagerTitleView(Context context, String tabInfo) { + super(context); + setHeight(Utils.dip2px(getContext(), 30)); + setTextSize(16); + setText(tabInfo); + setGravity(Gravity.CENTER); + + } + + + @Override + public void onSelected(int index, int totalCount) { +// setBackgroundResource(R.drawable.shape_bg_contact_indicator_item); + setTextColor(getResources().getColor(R.color.color_333333)); + } + + @Override + public void onDeselected(int index, int totalCount) { +// setBackgroundDrawable(null); + setTextColor(getResources().getColor(R.color.color_666666)); + } + + @Override + public void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight) { + + } + + @Override + public void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight) { + + } + } + + +} diff --git a/app/src/main/java/com/chwl/app/home/adapter/EventOfficialAdapter.kt b/app/src/main/java/com/chwl/app/home/adapter/EventOfficialAdapter.kt new file mode 100644 index 0000000..270aec2 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/adapter/EventOfficialAdapter.kt @@ -0,0 +1,90 @@ +package com.chwl.app.home.adapter + +import com.bumptech.glide.load.DataSource +import com.bumptech.glide.load.engine.GlideException +import com.bumptech.glide.request.RequestListener +import com.bumptech.glide.request.target.Target +import com.chwl.app.bindadapter.BaseBindingAdapter +import com.chwl.app.databinding.ItemEventOfficialBinding +import com.chwl.app.ui.utils.loadImage +import com.chwl.app.utils.AnimLoadUtil +import com.chwl.core.home.bean.BannerInfo +import com.chwl.core.home.bean.BannerInfo.SKIP_TYP_H5_CP +import com.chwl.core.home.bean.BannerInfo.SKIP_TYP_H5_CUSTOM +import com.chwl.core.home.bean.BannerInfo.SKIP_TYP_H5_WEE_STAR +import com.chwl.library.common.glide.GlideUtils +import com.chwl.library.common.util.isVerify +import com.chwl.library.common.util.postSafe +import com.opensource.svgaplayer.SVGAVideoEntity +import java.io.File + +class EventOfficialAdapter : BaseBindingAdapter() { + + val entityMap = hashMapOf() + + private fun isSVGA(type:Int): Boolean{ + return type == SKIP_TYP_H5_CUSTOM || type == SKIP_TYP_H5_WEE_STAR ||type == SKIP_TYP_H5_CP + } + + override fun onBindView( + viewBinding: ItemEventOfficialBinding, + data: BannerInfo, + pos: Int + ) { +// +// viewBinding.pic.loadImage(data.bannerPic) + viewBinding.name.text = data.bannerName + + + try { + data?.let { + if (isSVGA(it.getSkipType())) { + val effectView = viewBinding.pic + val bannerPic = it.bannerPic + if (!bannerPic.isVerify()) return + GlideUtils.instance().downloadFromUrl2(effectView.context,it?.bannerPic?:"",object : RequestListener { + override fun onLoadFailed( + p0: GlideException?, + p1: Any?, + p2: Target?, + p3: Boolean + ): Boolean { + return true + } + + override fun onResourceReady( + p0: File?, + p1: Any?, + p2: Target?, + p3: DataSource?, + p4: Boolean + ): Boolean { + p0?.let { + effectView.postSafe{ + try { + effectView.stopAnimation() + effectView.clear() + AnimLoadUtil.loadSvgaGetCache(effectView,it.path ?: "", data?.fillVo?.imgMap, data?.fillVo?.textMap){ entity-> + if (entity != null) { + effectView.postSafe { + effectView.requestLayout() + } + } + } + } catch (e: Exception) { + } + } + } + return true + } + }) + } else { + val effectView = viewBinding.pic + effectView.loadImage(data?.bannerPic ?: "") + } + } + } catch (e: Exception) { + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/adapter/EventSelectRoomAdapter.kt b/app/src/main/java/com/chwl/app/home/adapter/EventSelectRoomAdapter.kt new file mode 100644 index 0000000..a0330ed --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/adapter/EventSelectRoomAdapter.kt @@ -0,0 +1,22 @@ +package com.chwl.app.home.adapter + +import com.chwl.app.R +import com.chwl.app.bindadapter.BaseBindingAdapter +import com.chwl.app.databinding.ItemEventSelectRoomBinding +import com.chwl.app.ui.utils.loadImage +import com.chwl.core.bean.EventRoomBean +import com.example.lib_utils.ktx.getString + +class EventSelectRoomAdapter : BaseBindingAdapter() { + + override fun onBindView( + viewBinding: ItemEventSelectRoomBinding, + data: EventRoomBean, + pos: Int + ) { + viewBinding.roomUid.text = R.string.text_user_id.getString(data.erbanNo) + viewBinding.name.text = data.roomName + viewBinding.avatar.loadImage(data.avatar) + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/adapter/EventSquareAdapter.kt b/app/src/main/java/com/chwl/app/home/adapter/EventSquareAdapter.kt new file mode 100644 index 0000000..7538cba --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/adapter/EventSquareAdapter.kt @@ -0,0 +1,110 @@ +package com.chwl.app.home.adapter + +import com.chwl.app.R +import com.chwl.app.bindadapter.BaseBindingAdapter +import com.chwl.app.bindadapter.BaseBindingViewHolder +import com.chwl.app.databinding.ItemEventSquareBinding +import com.chwl.app.home.helper.EventCenterUtil +import com.chwl.app.ui.utils.loadAvatar +import com.chwl.app.ui.utils.loadImage +import com.chwl.core.auth.AuthModel +import com.chwl.core.bean.EventOfficialBean +import com.chwl.library.common.util.setVis +import com.example.lib_utils.ktx.dp +import com.example.lib_utils.ktx.getColor +import com.example.lib_utils.ktx.getDrawable +import com.example.lib_utils.ktx.getString + +class EventSquareAdapter(var isMy :Boolean) : BaseBindingAdapter() { + + + + companion object{ + const val B_DEL = 1 + const val B_IN_ROOM = 2 + const val B_SUB = 3 + } + + override fun convert( + helper: BaseBindingViewHolder, + data: EventOfficialBean + ) { + + val viewBinding = helper.binding as ItemEventSquareBinding + + //avatar + viewBinding.avatar.loadAvatar(data.avatar) + //name R.drawable.base_ic_male R.drawable.base_ic_female + viewBinding.name.text = data.nick + viewBinding.name.setDrawableEmpty(null,null,(if (data.gender == 1) R.drawable.base_ic_male else R.drawable.base_ic_female).getDrawable(),null) + //id + viewBinding.id.text = R.string.text_user_id.getString(data.erbanNo) + //title + viewBinding.title.text = data.eventTopic + //count + viewBinding.count.text = data.subNum.toString() + + viewBinding.pic.loadImage(data.eventBanner) + + + //btnNext + viewBinding.btnNext.alpha = 1f + viewBinding.btnNext.isEnabled = true + viewBinding.btnNext.setVis(true) + if (data.isEventStart) { + viewBinding.btnNext.text = R.string.v_27_Participate.getString() + viewBinding.btnNext.drawableLeftPadding = 4.dp + viewBinding.btnNext.setDrawableEmpty(R.drawable.ic_event_home.getDrawable(),null,null,null) + data.btnStatus = B_IN_ROOM + } else { + if (data.uid == AuthModel.get().currentUid && isMy) { + viewBinding.btnNext.text = "" + viewBinding.btnNext.drawableLeftPadding = 0 + viewBinding.btnNext.setDrawableEmpty(R.drawable.ic_event_del.getDrawable(),null,null,null) + data.btnStatus = B_DEL + } else { + viewBinding.btnNext.text = if (data.isSubStatus) R.string.v_27_UnSub.getString() else R.string.v_27_Sub.getString() + viewBinding.btnNext.drawableLeftPadding = 4.dp + viewBinding.btnNext.setDrawableEmpty((if (data.isSubStatus) R.drawable.ic_event_sub_n else R.drawable.ic_event_sub_s).getDrawable(),null,null,null) + data.btnStatus = B_SUB + + if (data.isEventEnd) { + viewBinding.btnNext.alpha = 0.5f + viewBinding.btnNext.isEnabled = false + } + } + } + + //status eventStatus->liveStatus->eventStartTimeStr->offectTimes + viewBinding.status.setTextColor(R.color.white_transparent_60.getColor()) + if (data.isReview) { + viewBinding.status.setDrawableEmpty(R.drawable.ic_event_time.getDrawable(),null,null,null) + if (data.isEventStart) { + viewBinding.status.text = R.string.v_27_Event_starting.getString() + viewBinding.status.setTextColor(R.color.color_ff8c03.getColor()) + viewBinding.status.setDrawableEmpty(R.drawable.ic_event_time_s.getDrawable(),null,null,null) + }else if (data.isEventReady) { + if (data.offectTimes > 24 * 60 * 60 * 1000) { + viewBinding.status.text = R.string.v_27_Start_Time_s.getString(data.eventStartTimeStr) + } else { + viewBinding.status.text = EventCenterUtil.formatDuration(data.offectTimes / (60 * 1000)) + } + }else if (data.isEventEnd) { + viewBinding.status.text = R.string.v_27_Event_ended.getString() + } + } else { + viewBinding.status.setDrawableEmpty(R.drawable.ic_event_review.getDrawable(),null,null,null) + if (data.isUnderReview) { + viewBinding.status.text = R.string.v_27_Under_Review.getString() + viewBinding.btnNext.setVis(false) + } else { + viewBinding.status.text = R.string.v_27_Review_Failed.getString() + } + } + + helper.addOnClickListener(viewBinding.btnNext.id) + } + + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/adapter/FindNewUserListAdapter.java b/app/src/main/java/com/chwl/app/home/adapter/FindNewUserListAdapter.java new file mode 100644 index 0000000..3e3e637 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/adapter/FindNewUserListAdapter.java @@ -0,0 +1,56 @@ +package com.chwl.app.home.adapter; + +import android.content.Context; +import android.view.View; +import android.widget.ImageView; + +import androidx.annotation.Nullable; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.netease.nim.uikit.support.glide.GlideApp; +import com.chwl.app.R; +import com.chwl.app.ui.user.activity.UserInfoActivity; +import com.chwl.core.user.bean.UserInfo; + +import java.util.List; + +/** + * @author jack + * @Description + * @Date 2018/10/30 + */ +public class FindNewUserListAdapter extends BaseQuickAdapter { + private Context context; + + public FindNewUserListAdapter(Context context, @Nullable List data) { + super(R.layout.item_home_find_new_user_list, data); + this.context = context; + } + + @Override + protected void convert(BaseViewHolder helper, UserInfo item) { + helper.setText(R.id.tv_name, item.getNick()) + .setText(R.id.tv_tutu_id, "ID:" + item.getErbanNo() + ""); + + ImageView ivAvatar = helper.getView(R.id.civ_avatar); + GlideApp.with(context) + .load(item.getAvatar()) + .dontAnimate() + .into(ivAvatar); + + if (item.getGender() == 1) { + helper.setImageResource(R.id.iv_sex, R.drawable.ic_gender_male); + } else { + helper.setImageResource(R.id.iv_sex, R.drawable.ic_gender_female); + } + + helper.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + UserInfoActivity.Companion.start(context, item.getUid()); + } + }); + + } +} diff --git a/app/src/main/java/com/chwl/app/home/adapter/FragmentViewPagerAdapter.java b/app/src/main/java/com/chwl/app/home/adapter/FragmentViewPagerAdapter.java new file mode 100644 index 0000000..f9bfb68 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/adapter/FragmentViewPagerAdapter.java @@ -0,0 +1,34 @@ +package com.chwl.app.home.adapter; + +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentPagerAdapter; + +import java.util.List; + +/** + * + */ +public class FragmentViewPagerAdapter extends FragmentPagerAdapter { + private List mFragmentList; + + + public FragmentViewPagerAdapter(FragmentManager fm, List fragmentList) { + super(fm); + this.mFragmentList = fragmentList; + } + + @Override + public Fragment getItem(int position) { + return mFragmentList.get(position); + } + + @Override + public int getCount() { + return mFragmentList == null ? 0 : mFragmentList.size(); + } + + public void setmFragmentList(List mFragmentList) { + this.mFragmentList = mFragmentList; + } +} diff --git a/app/src/main/java/com/chwl/app/home/adapter/HomeBannerAdapter.kt b/app/src/main/java/com/chwl/app/home/adapter/HomeBannerAdapter.kt new file mode 100644 index 0000000..62d7725 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/adapter/HomeBannerAdapter.kt @@ -0,0 +1,100 @@ +package com.chwl.app.home.adapter + +import com.bumptech.glide.load.DataSource +import com.bumptech.glide.load.engine.GlideException +import com.bumptech.glide.request.RequestListener +import com.bumptech.glide.request.target.Target +import com.chwl.app.R +import com.chwl.app.ui.utils.loadImage +import com.chwl.app.utils.AnimLoadUtil +import com.chwl.core.home.bean.BannerInfo +import com.chwl.core.home.bean.BannerInfo.SKIP_TYP_H5_CP +import com.chwl.core.home.bean.BannerInfo.SKIP_TYP_H5_CUSTOM +import com.chwl.core.home.bean.BannerInfo.SKIP_TYP_H5_WEE_STAR +import com.chwl.library.common.glide.GlideUtils +import com.chwl.library.common.util.isVerify +import com.chwl.library.common.util.postSafe +import com.chwl.library.widget.SVGAView +import com.makeramen.roundedimageview.RoundedImageView +import com.zhpan.bannerview.BaseBannerAdapter +import com.zhpan.bannerview.BaseViewHolder +import java.io.File + +class HomeBannerAdapter : BaseBannerAdapter() { + + + private fun isSVGA(type:Int): Boolean{ + return type == SKIP_TYP_H5_CUSTOM || type == SKIP_TYP_H5_WEE_STAR ||type == SKIP_TYP_H5_CP + } + + override fun getLayoutId(viewType: Int): Int { + if (isSVGA(viewType)) { + return R.layout.activity_home_banner_svga + } else { + return R.layout.activity_home_banner + } + } + + override fun getViewType(position: Int): Int { + return mList?.getOrNull(position)?.getSkipType() ?: 0 + } + + override fun bindData( + helper: BaseViewHolder, + item: BannerInfo?, + position: Int, + pageSize: Int + ) { + try { + item?.let { + if (isSVGA(it.getSkipType())) { + val effectView = helper.findViewById(R.id.iv_cover) + val bannerPic = it.bannerPic + if (!bannerPic.isVerify()) return + GlideUtils.instance().downloadFromUrl2(effectView.context,it?.bannerPic?:"",object : RequestListener { + override fun onLoadFailed( + p0: GlideException?, + p1: Any?, + p2: Target?, + p3: Boolean + ): Boolean { + return true + } + + override fun onResourceReady( + p0: File?, + p1: Any?, + p2: Target?, + p3: DataSource?, + p4: Boolean + ): Boolean { + p0?.let { + effectView.postSafe{ + try { + effectView.stopAnimation() + effectView.clear() + AnimLoadUtil.loadSvgaGetCache(effectView,it.path ?: "", item?.fillVo?.imgMap, item?.fillVo?.textMap){ entity-> + if (entity != null) { + effectView.postSafe { + effectView.requestLayout() + } + } + } + } catch (e: Exception) { + } + } + } + return true + } + }) + } else { + val effectView = helper.findViewById(R.id.iv_cover) + effectView.loadImage(item?.bannerPic ?: "") + } + } + } catch (e: Exception) { + } + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/adapter/HomeChatAdapter.kt b/app/src/main/java/com/chwl/app/home/adapter/HomeChatAdapter.kt new file mode 100644 index 0000000..97f965c --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/adapter/HomeChatAdapter.kt @@ -0,0 +1,39 @@ +package com.chwl.app.home.adapter + +import android.view.View +import androidx.constraintlayout.widget.Group +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.opensource.svgaplayer.SVGAImageView +import com.chwl.app.R +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.app.ui.utils.ImageLoadUtilsV2 +import com.chwl.app.ui.utils.loadFromAssets +import com.chwl.core.home.bean.HomeRoomInfo +import com.chwl.core.utils.extension.subAndReplaceDot + +/** + * create by lvzebiao @2019/11/13 + */ +class HomeChatAdapter : + BaseQuickAdapter(R.layout.item_home_chat) { + + override fun convert(helper: BaseViewHolder, item: HomeRoomInfo) { + val svgaLiving = helper.getView(R.id.svga_living) + ImageLoadUtils.loadAvatar( item.avatar,helper.getView(R.id.iv_avatar)) + helper.setText(R.id.tv_name, item.title.subAndReplaceDot(6)) + if (item.mgId == 0L) { + helper.getView(R.id.group_game).visibility = View.INVISIBLE + } else { + helper.getView(R.id.group_game).visibility = View.VISIBLE + } + svgaLiving.loadFromAssets("svga/home_living.svga") + } + + override fun onViewAttachedToWindow(holder: BaseViewHolder) { + super.onViewAttachedToWindow(holder) + val svgaLiving = holder.getView(R.id.svga_living) + svgaLiving?.loadFromAssets("svga/home_living.svga") + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/adapter/HomeConcernsAdapter.java b/app/src/main/java/com/chwl/app/home/adapter/HomeConcernsAdapter.java new file mode 100644 index 0000000..fb75b91 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/adapter/HomeConcernsAdapter.java @@ -0,0 +1,54 @@ +package com.chwl.app.home.adapter; + +import android.graphics.drawable.AnimationDrawable; + +import androidx.annotation.NonNull; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.app.avroom.activity.AVRoomActivity; +import com.chwl.app.common.widget.CircleImageView; +import com.chwl.app.ui.user.activity.UserInfoActivity; +import com.chwl.app.ui.utils.ImageLoadUtilsV2; +import com.chwl.core.home.bean.HomeRoomInfo; +import com.chwl.core.utils.extension.StringExtensionKt; + +public class HomeConcernsAdapter extends BaseQuickAdapter { + + public HomeConcernsAdapter() { + super(R.layout.item_home_concerns, null); + } + + @Override + protected void convert(@NonNull BaseViewHolder helper, HomeRoomInfo item) { + if (item == null) { + return; + } + CircleImageView circleImageView = helper.getView(R.id.civ_room_avatar); + ImageLoadUtilsV2.loadImage(circleImageView, item.getAvatar()); + helper.setText(R.id.tv_room_name, StringExtensionKt.subAndReplaceDot(item.getNick(), 4)); + + if (item.getRoomUid() > 0) { + helper.setVisible(R.id.view_avatar_bg, true); + helper.setVisible(R.id.view_living, true); + helper.setVisible(R.id.tv_live, true); + if (helper.getView(R.id.view_living).getBackground() instanceof AnimationDrawable) { + ((AnimationDrawable) helper.getView(R.id.view_living).getBackground()).start(); + } + helper.itemView.setOnClickListener(v -> { + AVRoomActivity.startForFromType(mContext, + item.getRoomUid(), + AVRoomActivity.FROM_TYPE_USER, + item.getNick(), + String.valueOf(item.getUid())); + }); + } else { + helper.setVisible(R.id.view_avatar_bg, false); + helper.setVisible(R.id.tv_live, false); + helper.setVisible(R.id.view_living, false); + helper.itemView.setOnClickListener(v -> UserInfoActivity.Companion.start(mContext, item.getUid())); + } + + } +} diff --git a/app/src/main/java/com/chwl/app/home/adapter/HomeIndicatorAdapter.java b/app/src/main/java/com/chwl/app/home/adapter/HomeIndicatorAdapter.java new file mode 100644 index 0000000..0447bd6 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/adapter/HomeIndicatorAdapter.java @@ -0,0 +1,103 @@ +package com.chwl.app.home.adapter; + +import android.content.Context; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.TextView; + +import androidx.core.content.ContextCompat; + +import com.chwl.app.R; +import com.chwl.app.ui.widget.XRecyclerView.ScaleTransitionPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.CommonNavigatorAdapter; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.indicators.LinePagerIndicator; + +import java.util.List; + +public class HomeIndicatorAdapter extends CommonNavigatorAdapter { + private final Context mContext; + private final List mTitleList; + + private int textSize = 20; + private float minScale = 0.8f; + private boolean showIndicator = true; + private OnItemSelectListener mOnItemSelectListener; + + public HomeIndicatorAdapter(Context context, List charSequences) { + this.mContext = context; + this.mTitleList = charSequences; + } + + @Override + public int getCount() { + return mTitleList == null ? 0 : mTitleList.size(); + } + + @Override + public IPagerTitleView getTitleView(Context context, final int i) { + ScaleTransitionPagerTitleView scaleTransitionPagerTitleView = new ScaleTransitionPagerTitleView(context, true); + scaleTransitionPagerTitleView.setNormalColor(ContextCompat.getColor(context, R.color.color_313131)); + scaleTransitionPagerTitleView.setSelectedColor(ContextCompat.getColor(context, R.color.color_313131)); + scaleTransitionPagerTitleView.setMinScale(minScale); + scaleTransitionPagerTitleView.setTextSize(textSize); + int padding = UIUtil.dip2px(context, 13); + scaleTransitionPagerTitleView.setPadding(padding, 0, padding, 0); + scaleTransitionPagerTitleView.setText(mTitleList.get(i)); + scaleTransitionPagerTitleView.setOnClickListener(view -> { + if (mOnItemSelectListener != null) { + mOnItemSelectListener.onItemSelect(i, scaleTransitionPagerTitleView); + } + + }); + return scaleTransitionPagerTitleView; + } + + @Override + public IPagerIndicator getIndicator(Context context) { + LinePagerIndicator indicator = new LinePagerIndicator(context); + indicator.setMode(LinePagerIndicator.MODE_EXACTLY); + indicator.setLineHeight(context.getResources().getDimensionPixelOffset(R.dimen.dp_4)); + indicator.setRoundRadius(context.getResources().getDimensionPixelOffset(R.dimen.dp_2)); + indicator.setLineWidth(context.getResources().getDimensionPixelOffset(R.dimen.dp_13)); + indicator.setColors(context.getResources().getColor(R.color.transparent)); + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); +// lp.bottomMargin = mBottomMargin; + indicator.setLayoutParams(lp); + return indicator; + } + + public int getTextSize() { + return textSize; + } + + public void setTextSize(int textSize) { + this.textSize = textSize; + } + + public float getMinScale() { + return minScale; + } + + public void setMinScale(float minScale) { + this.minScale = minScale; + } + + public boolean isShowIndicator() { + return showIndicator; + } + + public void setShowIndicator(boolean showIndicator) { + this.showIndicator = showIndicator; + } + + public void setOnItemSelectListener(OnItemSelectListener onItemSelectListener) { + mOnItemSelectListener = onItemSelectListener; + } + + public interface OnItemSelectListener { + void onItemSelect(int position, TextView view); + } +} diff --git a/app/src/main/java/com/chwl/app/home/adapter/HomeLiveTopAdapter.kt b/app/src/main/java/com/chwl/app/home/adapter/HomeLiveTopAdapter.kt new file mode 100644 index 0000000..1305079 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/adapter/HomeLiveTopAdapter.kt @@ -0,0 +1,34 @@ +package com.chwl.app.home.adapter + +import android.widget.ImageView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.avroom.activity.AVRoomActivity +import com.chwl.app.ui.utils.load +import com.chwl.core.room.bean.HomeLiveTopInfo + + +class HomeLiveTopAdapter : + BaseQuickAdapter(R.layout.item_home_live_top) { + + private var onceLookStatus: Boolean = false + + fun setOnceLookStatus(onceLookStatus: Boolean) { + this.onceLookStatus = onceLookStatus + } + + override fun convert(helper: BaseViewHolder, item: HomeLiveTopInfo.SingleRoom) { + helper.apply { + getView(R.id.iv_room_image).load(item.avatar) + setText(R.id.tv_room_title, item.title) + setGone(R.id.iv_room_tag, item.isRecommend && onceLookStatus) + } + + helper.itemView.setOnClickListener { + AVRoomActivity.start(mContext, item.uid) + } + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/adapter/HomeRankViewFlipperAdapter.kt b/app/src/main/java/com/chwl/app/home/adapter/HomeRankViewFlipperAdapter.kt new file mode 100644 index 0000000..221d793 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/adapter/HomeRankViewFlipperAdapter.kt @@ -0,0 +1,62 @@ +package com.chwl.app.home.adapter + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.BaseAdapter +import android.widget.ImageView +import androidx.core.view.isVisible +import com.chwl.app.R +import com.chwl.app.ui.utils.loadAvatar +import com.chwl.core.home.bean.HomeRankBean + +class HomeRankViewFlipperAdapter : BaseAdapter() { + + private val list = ArrayList>() + + fun setNewData(newList: List>) { + list.clear() + list.addAll(newList) + notifyDataSetChanged() + } + + override fun getCount(): Int { + return list.size + } + + override fun getItem(position: Int): List? { + return list.getOrNull(position) + } + + override fun getItemId(position: Int): Long { + return position.toLong() + } + + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { + val view = convertView ?: LayoutInflater.from(parent.context) + .inflate(R.layout.home_recommend_item_rank, parent, false) + view.layoutDirection = View.LAYOUT_DIRECTION_LTR + val rankView1 = view.findViewById(R.id.iv_rank_1) + val rankView2 = view.findViewById(R.id.iv_rank_2) + val rankView3 = view.findViewById(R.id.iv_rank_3) + val rankBorderView1 = view.findViewById(R.id.iv_rank_border_1) + val rankBorderView2 = view.findViewById(R.id.iv_rank_border_2) + val rankBorderView3 = view.findViewById(R.id.iv_rank_border_3) + val list = getItem(position) + loadRankData(rankView1, rankBorderView1, list?.getOrNull(0)) + loadRankData(rankView2, rankBorderView2, list?.getOrNull(1)) + loadRankData(rankView3, rankBorderView3, list?.getOrNull(2)) + return view + } + + private fun loadRankData(view: ImageView, borderView: View, data: HomeRankBean?) { + if (data == null) { + view.isVisible = false + borderView.isVisible = false + } else { + view.isVisible = true + borderView.isVisible = true + view.loadAvatar(data.avatar) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/adapter/HomeRoomAdapter.kt b/app/src/main/java/com/chwl/app/home/adapter/HomeRoomAdapter.kt new file mode 100644 index 0000000..f65afc5 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/adapter/HomeRoomAdapter.kt @@ -0,0 +1,192 @@ +package com.chwl.app.home.adapter + +import android.graphics.Rect +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.core.view.isVisible +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import androidx.recyclerview.widget.RecyclerView.RecycledViewPool +import com.chad.library.adapter.base.BaseMultiItemQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.app.ui.utils.load +import com.chwl.app.ui.utils.loadAnim +import com.chwl.app.ui.utils.loadFromAssets +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil +import com.chwl.app.utils.CommonJumpHelper +import com.chwl.core.home.bean.BannerInfo +import com.chwl.core.home.bean.HomeRoomInfo +import com.chwl.library.common.util.isVerify +import com.chwl.library.common.util.setVis +import com.chwl.library.widget.text.DrawableTextView +import com.example.lib_utils.AppUtils +import com.example.lib_utils.UiUtils +import com.example.lib_utils.ktx.getDrawable +import com.opensource.svgaplayer.SVGADrawable +import com.opensource.svgaplayer.SVGAImageView +import com.tencent.qgame.animplayer.AnimView +import com.zhpan.bannerview.BannerViewPager + +/** + * create by lvzebiao @2019/11/13 + */ +class HomeRoomAdapter : BaseMultiItemQuickAdapter { + private var micUserItemViewPool = RecycledViewPool().apply { + setMaxRecycledViews(0, 50) + } + + + + private val isRTL = UiUtils.isRtl(AppUtils.getApp()) + + constructor(data: MutableList?) : super(data){ + addItemType(HomeRoomInfo.TYPE_ROOM,R.layout.home_item_room) + addItemType(HomeRoomInfo.TYPE_BANNER,R.layout.home_item_banner) + } + + override fun onCreateDefViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder { + return super.onCreateDefViewHolder(parent, viewType).apply { + if (viewType == HomeRoomInfo.TYPE_ROOM) { + val micUserRecyclerView = this.getView(R.id.recycler_view_users) + micUserRecyclerView.setOnTouchListener { v, event -> true } + micUserRecyclerView.setRecycledViewPool(micUserItemViewPool) + micUserRecyclerView.setHasFixedSize(true) + micUserRecyclerView.layoutManager = + LinearLayoutManager(parent.context, RecyclerView.HORIZONTAL, false).apply { + this.recycleChildrenOnDetach = true + this.isSmoothScrollbarEnabled + } + micUserRecyclerView.addItemDecoration(object : RecyclerView.ItemDecoration() { + val offset = AppUtils.getApp().resources.getDimensionPixelOffset(R.dimen.dp_4) * -1 + + override fun getItemOffsets( + outRect: Rect, + view: View, + parent: RecyclerView, + state: RecyclerView.State + ) { + super.getItemOffsets(outRect, view, parent, state) + val position = parent.getChildAdapterPosition(view) + if (position != 0) { + if (isRTL) { + outRect.right = offset + } else { + outRect.left = offset + } + } + } + }) + micUserRecyclerView.adapter = HomeRoomUserAdapter() + } else if(viewType == HomeRoomInfo.TYPE_BANNER) { + val banner = this.getView>(R.id.banner_view) + banner.adapter = HomeBannerAdapter() + } + } + } + + override fun convert(helper: BaseViewHolder, item: HomeRoomInfo) { + if (!item.isBanner) { + helper.apply { + getView(R.id.iv_room_image).load(item.avatar) + setText(R.id.tv_online_number, item.hotValue.toInt().toString()) + setText(R.id.tv_room_title, item.title) + setText(R.id.tv_desc, item.roomDesc) + } + + val flag = helper.getView(R.id.flag) + if (item.regionFlag.isVerify()) { + flag.load(item.regionFlag) + } + flag.setVis(item.regionFlag.isVerify()) + + val micUserRecyclerView = helper.getView(R.id.recycler_view_users) + val userAdapter = micUserRecyclerView.adapter as HomeRoomUserAdapter + userAdapter.setNewData(item.micUsers) + + + val topView = helper.getView(R.id.iv_top) + topView.visibility = View.VISIBLE + if (item.hourTop == 1) { + topView.setImageResource(R.drawable.ic_home_room_bg_top_1) + } else if (item.hourTop == 2) { + topView.setImageResource(R.drawable.ic_home_room_bg_top_2) + }else if (item.hourTop == 3) { + topView.setImageResource(R.drawable.ic_home_room_bg_top_3) + } else { + topView.visibility = View.INVISIBLE + } + + val tagPict = item.tagPict + val tagView = helper.getView(R.id.iv_tag) + if (tagPict.isNullOrEmpty()) { + tagView.isVisible = false + } else { + ImageLoadUtils.loadImage(tagView, tagPict) + tagView.isVisible = true + } + val pkView = helper.getView(R.id.svga_pk) + if (item.isCrossPking) { + pkView.isVisible = true + if (pkView.drawable !is SVGADrawable) { + pkView.loadFromAssets("svga/home_pk.svga") + } + pkView.startAnimation() + } else { + pkView.isVisible = false + pkView.stopAnimation() + } + + + val boomIcon = helper.getView(R.id.boomIcon) + val boomAnim = helper.getView(R.id.boomAnim) + boomIcon.setVis(isVis = false, isInVis = true) + boomAnim.setVis(isVis = false, isInVis = true) + if (item.isRoomBoom) { + if (item.roomBoomPic.isVerify()) { + boomIcon.load(item.roomBoomPic) + boomIcon.setVis(isVis = true, isInVis = true) + }else if (item.roomBoomVapUrl.isVerify()){ + boomAnim.loadAnim(item.roomBoomVapUrl) + boomAnim.setVis(isVis = true, isInVis = true) + } + } + + // 1 = 热门 2=客服 + val title = helper.getView(R.id.tv_room_title) + if (item.homeRoomType == 0) { + title.setDrawableEmpty(null,null,R.drawable.transparent_draw.getDrawable(),null) + }else if (item.homeRoomType == 1) { + title.setDrawableEmpty(null,null,R.drawable.ic_home_room_icon_hot.getDrawable(),null) + }else if (item.homeRoomType == 2) { + title.setDrawableEmpty(null,null,R.drawable.ic_home_room_icon_service.getDrawable(),null) + } + + + helper.getView(R.id.roomLevelIcon).load(item.roomLevelIcon) + helper.setVisible(R.id.roomLevelIcon,item.roomLevelIcon.isVerify()) + + } else { + + if (item.bannerVoList.isVerify()){ + val banner = helper.getView>(R.id.banner_view) + banner.setPageMargin(UIUtil.dip2px(mContext, 8.0)) + .setScrollDuration(800) + .setOnPageClickListener { clickedView, position -> + CommonJumpHelper.bannerJump(banner.context, item.bannerVoList[position]) + } + .create(item.bannerVoList) +// +// val clickView = helper.getView(R.id.banner_view_click) +// clickView.click { +// val position = banner.currentItem +// CommonJumpHelper.bannerJump(banner.context, item.bannerVoList[position]) +// } + } + + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/adapter/HomeRoomFragmentAdapter.java b/app/src/main/java/com/chwl/app/home/adapter/HomeRoomFragmentAdapter.java new file mode 100644 index 0000000..b617ffa --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/adapter/HomeRoomFragmentAdapter.java @@ -0,0 +1,85 @@ +package com.chwl.app.home.adapter; + +import android.content.Context; +import android.text.TextUtils; +import android.view.View; +import android.widget.ImageView; + +import androidx.annotation.NonNull; + +import com.chad.library.adapter.base.BaseMultiItemQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.netease.nim.uikit.support.glide.GlideApp; +import com.chwl.app.R; +import com.chwl.app.avroom.activity.AVRoomActivity; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.home.bean.HomeTabMapInfo; + +/** + *

首页热门adapter

+ * + * @author Administrator + * @date 2017/11/16 + */ +public class HomeRoomFragmentAdapter extends BaseMultiItemQuickAdapter { + + private Context mContext; + + /** + * 校验跳转房间的频率 + */ + public HomeRoomFragmentAdapter(Context context) { + super(null); + addItemType(HomeTabMapInfo.TYPE_NORMAL, R.layout.item_home_tab_map); + addItemType(HomeTabMapInfo.TYPE_EMPTY, R.layout.item_erban_grid_empty); + this.mContext = context; + } + + protected void convert(@NonNull BaseViewHolder helper, HomeTabMapInfo item) { + if (item == null) { + return; + } + switch (helper.getItemViewType()) { + + case HomeTabMapInfo.TYPE_NORMAL: + helper.itemView.setOnClickListener(v -> { + AVRoomActivity.startForFromType(mContext, item.getRoomUid(), AVRoomActivity.FROM_TYPE_RECOMMEND); + }); + helper.setText(R.id.tv_online_number, item.getOnlineNum() + "") + .setText(R.id.tv_title, item.getTitle()); + + + //注意这里有三个标签,展示优先级 PK中>自定义>房间标签 + helper.setGone(R.id.tv_tag_in_pk, item.isCrossPking()); + + helper.setGone(R.id.tv_tag_content, !TextUtils.isEmpty(item.getIconContent()) && !item.isCrossPking()) + .setText(R.id.tv_tag_content, item.getIconContent()); + + ImageView mIvTabLabel = helper.getView(R.id.iv_tab_label); + if (!TextUtils.isEmpty(item.getTagPict()) && !item.isCrossPking() && TextUtils.isEmpty(item.getIconContent())) { + mIvTabLabel.setVisibility(View.VISIBLE); + ImageLoadUtils.loadAvatarBig(item.getTagPict(), mIvTabLabel); + } else { + mIvTabLabel.setVisibility(View.GONE); + } + + ImageView ivCover = helper.getView(R.id.iv_cover); + if (!TextUtils.isEmpty(item.getAvatar())) { + ImageLoadUtils.loadAvatarBig(item.getAvatar(), ivCover); + } else { + GlideApp.with(mContext) + .load(R.drawable.default_cover) + .placeholder(R.drawable.default_cover) + .into(ivCover); + } + break; + + case HomeTabMapInfo.TYPE_EMPTY: + + break; + } + + + } + +} diff --git a/app/src/main/java/com/chwl/app/home/adapter/HomeRoomUserAdapter.kt b/app/src/main/java/com/chwl/app/home/adapter/HomeRoomUserAdapter.kt new file mode 100644 index 0000000..3deff22 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/adapter/HomeRoomUserAdapter.kt @@ -0,0 +1,16 @@ +package com.chwl.app.home.adapter + +import android.widget.ImageView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.ui.utils.loadAvatar +import com.chwl.core.home.bean.MicUsersBean + +class HomeRoomUserAdapter : + BaseQuickAdapter(R.layout.home_item_room_user) { + override fun convert(helper: BaseViewHolder, item: MicUsersBean?) { + val avatarView = helper.getView(R.id.iv_avatar) + avatarView.loadAvatar(item?.avatar) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/adapter/HomeTopAdapter.java b/app/src/main/java/com/chwl/app/home/adapter/HomeTopAdapter.java new file mode 100644 index 0000000..cc5350e --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/adapter/HomeTopAdapter.java @@ -0,0 +1,60 @@ +package com.chwl.app.home.adapter; + +import android.text.TextUtils; +import android.view.View; +import android.widget.ImageView; + +import com.netease.nim.uikit.support.glide.GlideApp; +import com.chwl.app.R; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.home.bean.HomeTabMapInfo; +import com.chwl.library.common.application.BaseApp; +import com.zhpan.bannerview.BaseBannerAdapter; +import com.zhpan.bannerview.BaseViewHolder; + +public class HomeTopAdapter extends BaseBannerAdapter { + + @Override + public int getLayoutId(int viewType) { + return R.layout.activity_home_top_banner; + } + + @Override + protected void bindData(BaseViewHolder helper, HomeTabMapInfo item, int position, int pageSize) { + helper.setText(R.id.tv_title, item.getTitle()); + + + //注意这里有三个标签,展示优先级 PK中>自定义>房间标签 + if (item.isCrossPking()) { + helper.findViewById(R.id.tv_tag_in_pk).setVisibility(View.VISIBLE); + } else { + helper.findViewById(R.id.tv_tag_in_pk).setVisibility(View.GONE); + } + + if (!TextUtils.isEmpty(item.getIconContent()) && !item.isCrossPking()) { + helper.findViewById(R.id.tv_tag_content).setVisibility(View.VISIBLE); + } else { + helper.findViewById(R.id.tv_tag_content).setVisibility(View.GONE); + } + helper.setText(R.id.tv_tag_content, item.getIconContent()); + + ImageView mIvTabLabel = helper.findViewById(R.id.iv_tab_label); + if (!TextUtils.isEmpty(item.getTagPict()) && !item.isCrossPking() && TextUtils.isEmpty(item.getIconContent())) { + mIvTabLabel.setVisibility(View.VISIBLE); + ImageLoadUtils.loadAvatarBig(item.getTagPict(),mIvTabLabel); + } else { + mIvTabLabel.setVisibility(View.GONE); + } + + ImageView ivCover = helper.findViewById(R.id.iv_cover); + if (!TextUtils.isEmpty(item.getAvatar())) { + ImageLoadUtils.loadAvatarBig(item.getAvatar(), ivCover); + } else { + GlideApp.with(BaseApp.getContext()) + .load(R.drawable.default_cover) + .placeholder(R.drawable.default_cover) + .into(ivCover); + } + } + +} diff --git a/app/src/main/java/com/chwl/app/home/adapter/MainMagicIndicatorAdapter.java b/app/src/main/java/com/chwl/app/home/adapter/MainMagicIndicatorAdapter.java new file mode 100644 index 0000000..37bef66 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/adapter/MainMagicIndicatorAdapter.java @@ -0,0 +1,110 @@ +package com.chwl.app.home.adapter; + +import android.content.Context; +import android.graphics.Color; +import android.view.Gravity; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.TextView; + +import androidx.core.content.ContextCompat; + +import com.chwl.app.R; +import com.chwl.app.ui.widget.XRecyclerView.ScaleTransitionPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.CommonNavigatorAdapter; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.indicators.LinePagerIndicator; + +import java.util.List; + +public class MainMagicIndicatorAdapter extends CommonNavigatorAdapter { + private final Context mContext; + private final List mTitleList; + + private int textSize = 24; + private float minScale = 0.83f; + private boolean showIndicator =true; + + public MainMagicIndicatorAdapter(Context context, List charSequences ) { + this.mContext = context; + this.mTitleList = charSequences; + } + + @Override + public int getCount() { + return mTitleList == null ? 0 : mTitleList.size(); + } + + + @Override + public IPagerTitleView getTitleView(Context context, final int i) { + ScaleTransitionPagerTitleView scaleTransitionPagerTitleView = new ScaleTransitionPagerTitleView(context, true); + scaleTransitionPagerTitleView.setNormalColor(ContextCompat.getColor(context,R.color.color_444444)); + scaleTransitionPagerTitleView.setSelectedColor(ContextCompat.getColor(context,R.color.color_333333)); + scaleTransitionPagerTitleView.setMinScale(minScale); + scaleTransitionPagerTitleView.setTextSize(textSize); + int padding = UIUtil.dip2px(context, 5); + scaleTransitionPagerTitleView.setPadding(padding, 0, padding, 0); + scaleTransitionPagerTitleView.setText(mTitleList.get(i)); + scaleTransitionPagerTitleView.setOnClickListener(view -> { + if (mOnItemSelectListener != null) { + mOnItemSelectListener.onItemSelect(i, scaleTransitionPagerTitleView); + } + + }); + return scaleTransitionPagerTitleView; + } + + + @Override + public IPagerIndicator getIndicator(Context context) { + if (!showIndicator) return null; + LinePagerIndicator indicator = new LinePagerIndicator(context); + indicator.setMode(LinePagerIndicator.MODE_EXACTLY); + indicator.setLineHeight(UIUtil.dip2px(mContext, 10)); + indicator.setRoundRadius(UIUtil.dip2px(mContext, 10)); + indicator.setLineWidth(UIUtil.dip2px(mContext, 48)); + indicator.setColors(Color.parseColor("#FFFFD15A")); + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + lp.gravity = Gravity.END; + lp.bottomMargin = UIUtil.dip2px(mContext, 0); + indicator.setLayoutParams(lp); + return indicator; + } + + public int getTextSize() { + return textSize; + } + + public void setTextSize(int textSize) { + this.textSize = textSize; + } + + public float getMinScale() { + return minScale; + } + + public void setMinScale(float minScale) { + this.minScale = minScale; + } + + public boolean isShowIndicator() { + return showIndicator; + } + + public void setShowIndicator(boolean showIndicator) { + this.showIndicator = showIndicator; + } + + private OnItemSelectListener mOnItemSelectListener; + + public void setOnItemSelectListener(OnItemSelectListener onItemSelectListener) { + mOnItemSelectListener = onItemSelectListener; + } + + public interface OnItemSelectListener { + void onItemSelect(int position, TextView view); + } +} diff --git a/app/src/main/java/com/chwl/app/home/adapter/MeCenterAdapter.kt b/app/src/main/java/com/chwl/app/home/adapter/MeCenterAdapter.kt new file mode 100644 index 0000000..3076223 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/adapter/MeCenterAdapter.kt @@ -0,0 +1,49 @@ +package com.chwl.app.home.adapter + +import android.widget.ImageView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chad.library.adapter.base.diff.BaseQuickDiffCallback +import com.chwl.app.R +import com.chwl.app.ui.utils.loadImage +import com.chwl.core.room.bean.MeCenterInfo + + +class MeCenterAdapter : + BaseQuickAdapter(R.layout.item_me_center) { + + override fun convert(helper: BaseViewHolder, item: MeCenterInfo) { + item.icon?.let { + helper.getView(R.id.iv_pic).setImageResource(it) + } ?: let { + helper.getView(R.id.iv_pic).loadImage(item.androidCenterPic) + } + helper.setText(R.id.tv_name, item.centerName) + } + + fun updateData(list: List?) { + val newList = ArrayList() + if (list != null) { + newList.addAll(list) + } + setNewDiffData(object : BaseQuickDiffCallback(newList) { + override fun areItemsTheSame( + oldItem: MeCenterInfo, + newItem: MeCenterInfo + ): Boolean { + return newItem.centerId == oldItem.centerId + } + + override fun areContentsTheSame( + oldItem: MeCenterInfo, + newItem: MeCenterInfo + ): Boolean { + return newItem.skipType == oldItem.skipType + && newItem.centerName == oldItem.centerName + && newItem.centerUrl == oldItem.centerUrl + && newItem.androidCenterPic == oldItem.androidCenterPic + } + }, true) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/adapter/MeGameAdapter.kt b/app/src/main/java/com/chwl/app/home/adapter/MeGameAdapter.kt new file mode 100644 index 0000000..eb9e5b9 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/adapter/MeGameAdapter.kt @@ -0,0 +1,19 @@ +package com.chwl.app.home.adapter + +import android.widget.ImageView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.ui.utils.load +import com.chwl.core.room.game.bean.GameInfo + + +class MeGameAdapter : + BaseQuickAdapter(R.layout.item_me_game) { + + override fun convert(helper: BaseViewHolder, item: GameInfo) { + helper.getView(R.id.iv_pic).load(item.pic?:"") + helper.setText(R.id.tv_name, item.name?:"") + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/adapter/RoomActAdapter.kt b/app/src/main/java/com/chwl/app/home/adapter/RoomActAdapter.kt new file mode 100644 index 0000000..80b8aa2 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/adapter/RoomActAdapter.kt @@ -0,0 +1,51 @@ +package com.chwl.app.home.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import com.chwl.app.R +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.app.ui.webview.room_banner.RoomBannerWebDialogActivity +import com.chwl.app.ui.widget.rollviewpager.adapter.StaticPagerAdapter +import com.chwl.app.utils.CommonJumpHelper +import com.chwl.core.home.bean.BannerInfo +import com.chwl.core.room.model.AvRoomModel +import okhttp3.internal.filterList + +class RoomActAdapter(private val mContext: Context, private val data: List) : + StaticPagerAdapter() { + override fun getView(container: ViewGroup, position: Int): View { + val view = LayoutInflater.from(mContext).inflate(R.layout.item_room_act, container, false) + val ivCover = view.findViewById(R.id.iv_cover) + val bannerInfo = data[position] + val actId = bannerInfo.bannerId.toString() + ivCover.scaleType = ImageView.ScaleType.CENTER_CROP + ImageLoadUtils.loadImage( + mContext, + bannerInfo.bannerPic, + ivCover, + R.drawable.default_cover + ) + ivCover.setOnClickListener { v: View? -> + AvRoomModel.get().activityClickLog("2", actId).subscribe() + if (bannerInfo.getSkipType() == 3) { + val list = data.filterList { + getSkipType() == 3 + } + val newPosition = list.indexOfFirst { + it == bannerInfo + } + RoomBannerWebDialogActivity.start(mContext, newPosition, list) + } else { + CommonJumpHelper.bannerJump(mContext, bannerInfo) + } + } + return view + } + + override fun getCount(): Int { + return data.size + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/adapter/RoomCommonAdapter.kt b/app/src/main/java/com/chwl/app/home/adapter/RoomCommonAdapter.kt new file mode 100644 index 0000000..29b5228 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/adapter/RoomCommonAdapter.kt @@ -0,0 +1,28 @@ +package com.chwl.app.home.adapter + +import android.widget.ImageView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.ui.utils.ImageLoadUtilsV2 +import com.chwl.app.ui.utils.load +import com.chwl.core.home.bean.HomeRoomInfo +import com.chwl.core.utils.CoreTextUtils + + +class RoomCommonAdapter : BaseQuickAdapter(R.layout.item_room_common) { + + override fun convert(helper: BaseViewHolder, item: HomeRoomInfo) { + helper.apply { + getView(R.id.iv_room_image).load(item.avatar) + setText(R.id.tv_online_number, "${item.onlineNum}") + setText(R.id.tv_room_title, item.title) + setText(R.id.tv_id, "ID:${item.erbanNo}") + } + helper.setVisible(R.id.tv_in_pk, item.isCrossPking) + helper.setGone(R.id.iv_room_tag, !CoreTextUtils.isEmptyText(item.tagPict)) + ImageLoadUtilsV2.loadImage(helper.getView(R.id.iv_room_tag), item.tagPict) + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/adapter/RoomGameAdapter.kt b/app/src/main/java/com/chwl/app/home/adapter/RoomGameAdapter.kt new file mode 100644 index 0000000..38eab42 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/adapter/RoomGameAdapter.kt @@ -0,0 +1,61 @@ +package com.chwl.app.home.adapter + +import android.graphics.Color +import android.graphics.LinearGradient +import android.graphics.Shader +import android.widget.ImageView +import android.widget.TextView +import androidx.core.view.isGone +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.avroom.activity.AVRoomActivity +import com.chwl.app.ui.utils.load +import com.chwl.core.home.bean.HomeRoomInfo +import com.chwl.library.utils.ResUtil + + +class RoomGameAdapter : BaseQuickAdapter(R.layout.item_room_game) { + + + override fun convert(helper: BaseViewHolder, item: HomeRoomInfo) { + helper.apply { + getView(R.id.iv_room_image).load(item.avatar) + setText(R.id.tv_room_title, item.title) + itemView.setOnClickListener { + AVRoomActivity.start(mContext, item.uid) + } + val tvRoomGame = helper.getView(R.id.tv_room_game) + tvRoomGame.text = item.mgName + helper.setText(R.id.tv_game_status, if (item.state == 1) ResUtil.getString(R.string.home_adapter_roomgameadapter_02) else ResUtil.getString(R.string.home_adapter_roomgameadapter_03)) + setGradient(tvRoomGame) + } + + val avatars: Array = arrayOf( + helper.getView(R.id.iv_avatar_0), + helper.getView(R.id.iv_avatar_1), + helper.getView(R.id.iv_avatar_2), + helper.getView(R.id.iv_avatar_3), + helper.getView(R.id.iv_avatar_4) + ) + for (i in avatars.indices) { + val avatarUrl = item.micUsers?.getOrNull(i)?.avatar + avatars[i].isGone = avatarUrl.isNullOrBlank() + avatars[i].load(avatarUrl) + } + + } + + private fun setGradient(textView: TextView) { + val endX = textView.paint.textSize * textView.text.length + val linearGradient = LinearGradient( + 0f, 0f, endX, 0f, + Color.parseColor("#FF61C4FE"), + Color.parseColor("#FFA979FF"), + Shader.TileMode.CLAMP + ) + textView.paint.shader = linearGradient + textView.invalidate() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/adapter/RoomHistoryListAdapter.kt b/app/src/main/java/com/chwl/app/home/adapter/RoomHistoryListAdapter.kt new file mode 100644 index 0000000..4760e0e --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/adapter/RoomHistoryListAdapter.kt @@ -0,0 +1,32 @@ +package com.chwl.app.home.adapter + +import android.widget.ImageView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.avroom.activity.AVRoomActivity +import com.chwl.app.ui.utils.load +import com.chwl.core.bean.RoomHistoryInfo +import com.chwl.library.utils.TimeUtils + + +class RoomHistoryListAdapter : + BaseQuickAdapter(R.layout.item_room_history_list) { + + override fun convert(helper: BaseViewHolder, item: RoomHistoryInfo) { + helper.apply { + getView(R.id.iv_room_image).load(item.avatar) + setText(R.id.tv_room_title, item.title) + setText(R.id.tv_id, "ID:${item.erbanNo}") + setText(R.id.tv_room_title, item.title) + setText( + R.id.tv_time, + TimeUtils.getDateTimeString(item.updateTime, TimeUtils.DATE_FORMAT) + ) + itemView.setOnClickListener { + AVRoomActivity.start(mContext, item.roomUid) + } + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/adapter/RoomNewFriendsAdapter.kt b/app/src/main/java/com/chwl/app/home/adapter/RoomNewFriendsAdapter.kt new file mode 100644 index 0000000..f6a6538 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/adapter/RoomNewFriendsAdapter.kt @@ -0,0 +1,232 @@ +package com.chwl.app.home.adapter + +import android.text.TextUtils +import android.view.View +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import androidx.appcompat.widget.AppCompatImageView +import androidx.appcompat.widget.AppCompatTextView +import androidx.recyclerview.widget.RecyclerView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.google.android.flexbox.AlignItems +import com.google.android.flexbox.FlexDirection +import com.opensource.svgaplayer.SVGAImageView +import com.chwl.app.R +import com.chwl.app.audio.helper.AudioPlayerHelper +import com.chwl.app.audio.helper.OnPlayListener +import com.chwl.app.avroom.activity.AVRoomActivity +import com.chwl.app.ui.im.avtivity.NimP2PMessageActivity +import com.chwl.app.ui.user.activity.UserInfoActivity +import com.chwl.app.ui.user.adapter.UserInfoLabelAdapter +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.app.ui.utils.loadAvatar +import com.chwl.app.ui.utils.loadFromAssets +import com.chwl.app.view.GenderAgeTextView +import com.chwl.core.Constants +import com.chwl.core.manager.AudioEngineManager +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.user.bean.UserInfo +import com.chwl.core.utils.extension.ifNullOrEmpty +import com.chwl.library.common.widget.LinesFlexBoxLayoutManager +import com.chwl.library.utils.ListUtils +import com.chwl.library.utils.SingleToastUtil +import io.reactivex.Observable +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import io.reactivex.schedulers.Schedulers +import java.util.concurrent.TimeUnit + +class RoomNewFriendsAdapter : + BaseQuickAdapter(R.layout.item_room_new_friends) { + + private var disposable: Disposable? = null + + private var isMute = false + private var isRemoteMute = false + + override fun convert(helper: BaseViewHolder, item: UserInfo) { + helper.getView(R.id.iv_avatar).loadAvatar(item.avatar) + helper.setText(R.id.tv_desc, item.userDesc.ifNullOrEmpty { "我是个默认签名" }) + + val tvGenderAge = helper.getView(R.id.tv_gender_age) + tvGenderAge.setBirthDay(item.birth) + tvGenderAge.setGender(item.gender) + + //设置星座 +// val star = StarUtils.getConstellation(Date(item.birth)) +// helper.setImageResource(R.id.iv_constellation, star) + + val tvTalk = helper.getView(R.id.tv_talk) + + helper.setVisible( + R.id.view_online, if (item.inMic) { + false + } else item.inOnline + ) + helper.setVisible(R.id.group_party, item.inMic) + + if (item.inRoomUid != 0L) { + tvTalk.text = "去找TA" + tvTalk.setOnClickListener { + AVRoomActivity.startForFromType( + mContext, + item.inRoomUid, + AVRoomActivity.FROM_TYPE_USER, + item.nick, + item.uid.toString() + ) + } + } else { + tvTalk.text = "和TA聊" + tvTalk.setOnClickListener { + NimP2PMessageActivity.start(mContext, item.uid.toString()) + } + } + + helper.getView(R.id.iv_avatar).setOnClickListener { + UserInfoActivity.Companion.start(mContext, item.uid) + } + + val tvNickname = helper.getView(R.id.tv_nickname) + tvNickname.text = item.nick + + val ivUserLevel: AppCompatImageView = helper.getView(R.id.iv_user_level) + ivUserLevel.visibility = View.GONE + if (item.userLevelVo != null && !TextUtils.isEmpty(item.userLevelVo.getExperUrl())) { + ivUserLevel.visibility = View.VISIBLE + ImageLoadUtils.loadImage(mContext, item.userLevelVo.getExperUrl(), ivUserLevel) + } + + val ivCharmLevel: AppCompatImageView = helper.getView(R.id.iv_charm_level) + ivCharmLevel.visibility = View.GONE + if (item.userLevelVo != null && !TextUtils.isEmpty(item.userLevelVo.getCharmUrl())) { + ivCharmLevel.visibility = View.VISIBLE + ImageLoadUtils.loadImage( + mContext, + item.userLevelVo.getCharmUrl(), + ivCharmLevel + ) + } + + if (item.userVoice.isNullOrBlank()) { + helper.getView(R.id.tv_desc).visibility = View.VISIBLE + helper.getView(R.id.llAudio).visibility = View.GONE + } else { + helper.getView(R.id.tv_desc).visibility = View.GONE + helper.getView(R.id.llAudio).visibility = View.VISIBLE + + helper.getView(R.id.tvAudio).text = item.voiceDura.toString() + helper.getView(R.id.llAudio) + .setOnClickListener { toggleAudio(helper, item) } + helper.setImageResource(R.id.liv_user, R.drawable.ic_sound_wave) + } + + val mLabelRecyclerView = helper.getView(R.id.mLabelRecyclerView) + if (!ListUtils.isListEmpty(item.labels)) { + mLabelRecyclerView.visibility = View.VISIBLE + val userInfoLabelAdapter = UserInfoLabelAdapter() + + val labelLayoutManager = LinesFlexBoxLayoutManager(mContext) + labelLayoutManager.flexDirection = FlexDirection.ROW + labelLayoutManager.alignItems = AlignItems.FLEX_START + labelLayoutManager.setMaxLines(1) + mLabelRecyclerView.layoutManager = labelLayoutManager + mLabelRecyclerView.adapter = userInfoLabelAdapter + + userInfoLabelAdapter.setNewData(item.labels) + } else { + mLabelRecyclerView.visibility = View.GONE + } + + } + + private fun toggleAudio(holder: BaseViewHolder, item: UserInfo) { + if (item.isVoicePlaying) { + stopAudio() + } else { + playAudio(holder, item) + } + } + + private fun stopAudio() { + AudioPlayerHelper.get().endPlay() + } + + private fun resetAudioUI(holder: BaseViewHolder, item: UserInfo) { + item.isVoicePlaying = false + + disposable?.dispose() + holder.setImageResource(R.id.iv_audio_control, R.drawable.ic_sound_pause) + holder.setText(R.id.tvAudio, item.voiceDura.toString()) + + val svgaImageView = holder.getView(R.id.liv_user) + svgaImageView.stopAnimation() + svgaImageView.setImageResource(R.drawable.ic_sound_wave) + + AvRoomDataManager.get().mCurrentRoomInfo?.run { + AudioEngineManager.get().isRemoteMute = isRemoteMute //非靜音 + AudioEngineManager.get().isMute = isMute //能説話 + AudioEngineManager.get().setRole( + if (isRemoteMute) Constants.CLIENT_ROLE_AUDIENCE else Constants.CLIENT_ROLE_BROADCASTER + ) + } + } + + private fun playAudio(holder: BaseViewHolder, item: UserInfo) { + AudioPlayerHelper.get().endPlay() + + item.isVoicePlaying = true + + + holder.setImageResource(R.id.iv_audio_control, R.drawable.ic_sound_start) + val svgaImageView = holder.getView(R.id.liv_user) + svgaImageView.loadFromAssets("svga/home_voice_playing.svga") + + disposable = Observable.interval(1L, TimeUnit.SECONDS) + .subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + .map { it + 1 } + .takeUntil { it == item.voiceDura.toLong() } + .subscribe { + holder.setText(R.id.tvAudio, (item.voiceDura - it).toString()) + } + + AvRoomDataManager.get().mCurrentRoomInfo?.run { + isRemoteMute = AudioEngineManager.get().isRemoteMute + isMute = AudioEngineManager.get().isMute + AudioEngineManager.get().isRemoteMute = true //設置靜音 + AudioEngineManager.get().isMute = true //不能説話 + AudioEngineManager.get().setRole(Constants.CLIENT_ROLE_AUDIENCE) + } + + AudioPlayerHelper.get().playInThread(item.userVoice, object : OnPlayListener { + override fun onError(error: String) { + SingleToastUtil.showToast(mContext.getString(R.string.me_error_playing)) + resetAudioUI(holder, item) + } + + override fun onPrepared() {} + override fun onPlaying(currDuration: Long) {} + override fun onCompletion() { + resetAudioUI(holder, item) + } + }) + } + + override fun onViewDetachedFromWindow(holder: BaseViewHolder) { + super.onViewDetachedFromWindow(holder) + + val position = holder.absoluteAdapterPosition + + if (position < 0 || position >= data.size) { + return + } + + val item = data[position] + if (item.isVoicePlaying) { + stopAudio() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/adapter/TopMagicIndicatorAdapter.java b/app/src/main/java/com/chwl/app/home/adapter/TopMagicIndicatorAdapter.java new file mode 100644 index 0000000..88d43c5 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/adapter/TopMagicIndicatorAdapter.java @@ -0,0 +1,83 @@ +package com.chwl.app.home.adapter; + +import android.content.Context; +import android.view.Gravity; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import androidx.core.content.ContextCompat; + +import com.chwl.app.R; +import com.chwl.app.ui.widget.XRecyclerView.ScaleTransitionPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.CommonNavigatorAdapter; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.indicators.GradientLinePagerIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.indicators.LinePagerIndicator; + +import java.util.List; + +/** + *

公共多个滑动tab样式

+ * + * @author Administrator + * @date 2017/11/15 + */ +public class TopMagicIndicatorAdapter extends CommonNavigatorAdapter { + + private int textSize = 18; + private float minScale = 0.75f; + private Context mContext; + private List mTitleList; + + public TopMagicIndicatorAdapter(Context context, List titleList) { + mContext = context; + mTitleList = titleList; + } + + @Override + public int getCount() { + return mTitleList == null ? 0 : mTitleList.size(); + } + + @Override + public IPagerTitleView getTitleView(Context context, final int i) { + ScaleTransitionPagerTitleView scaleTransitionPagerTitleView = new ScaleTransitionPagerTitleView(context, false); + scaleTransitionPagerTitleView.setNormalColor(ContextCompat.getColor(context,R.color.text_secondary_4f516a)); + scaleTransitionPagerTitleView.setSelectedColor(ContextCompat.getColor(context,R.color.text_title_color)); + scaleTransitionPagerTitleView.setMinScale(minScale); + scaleTransitionPagerTitleView.setTextSize(textSize); + scaleTransitionPagerTitleView.setText(mTitleList.get(i)); + scaleTransitionPagerTitleView.setOnClickListener(view -> { + if (mOnItemSelectListener != null) { + mOnItemSelectListener.onItemSelect(i); + } + }); + return scaleTransitionPagerTitleView; + } + + + @Override + public IPagerIndicator getIndicator(Context context) { + GradientLinePagerIndicator indicator = new GradientLinePagerIndicator(context); + indicator.setMode(LinePagerIndicator.MODE_WRAP_CONTENT); + indicator.setLineHeight(UIUtil.dip2px(mContext, 8)); + indicator.setRoundRadius(UIUtil.dip2px(mContext, 360)); + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + lp.gravity = Gravity.END; + lp.bottomMargin = UIUtil.dip2px(mContext, 0); + indicator.setLayoutParams(lp); + return indicator; + } + + private OnItemSelectListener mOnItemSelectListener; + + public void setOnItemSelectListener(OnItemSelectListener onItemSelectListener) { + mOnItemSelectListener = onItemSelectListener; + } + + public interface OnItemSelectListener { + void onItemSelect(int position); + } +} diff --git a/app/src/main/java/com/chwl/app/home/adapter/VisitorListAdapter.java b/app/src/main/java/com/chwl/app/home/adapter/VisitorListAdapter.java new file mode 100644 index 0000000..9b7a588 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/adapter/VisitorListAdapter.java @@ -0,0 +1,107 @@ +package com.chwl.app.home.adapter; + +import android.view.View; +import android.widget.TextView; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.app.ui.user.activity.UserInfoActivity; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.home.bean.VisitorInfo; +import com.chwl.library.common.util.OtherExtKt; +import com.example.lib_utils.ktx.ResourcesKtxKt; + +import org.jetbrains.annotations.NotNull; + +/** + * create by lvzebiao @2019/11/13 + * 人气主播更多 + */ +public class VisitorListAdapter extends BaseQuickAdapter { + + + public VisitorListAdapter() { + super(R.layout.item_home_visitor_list); + } + + @Override + protected void convert(@NotNull BaseViewHolder helper, VisitorInfo item) { + if (item == null) { + return; + } + + + if (OtherExtKt.isVerify(item.getAvatar())) { + ImageLoadUtils.loadAvatar(mContext, + item.getAvatar(), + helper.getView(R.id.iv_avatar) + ); + } + + if (OtherExtKt.isVerify(item.getRegionIcon())) { + ImageLoadUtils.loadImage(mContext, + item.getRegionIcon(), + helper.getView(R.id.region) + ); + helper.getView(R.id.region).setVisibility(View.VISIBLE); + } else { + helper.getView(R.id.region).setVisibility(View.GONE); + } + + + if (item.getUserLevelVo() != null && OtherExtKt.isVerify(item.getUserLevelVo().getExperUrl())) { + ImageLoadUtils.loadImage(mContext, + item.getUserLevelVo().getExperUrl(), + helper.getView(R.id.experLevel) + ); + helper.getView(R.id.experLevel).setVisibility(View.VISIBLE); + } else { + helper.getView(R.id.experLevel).setVisibility(View.GONE); + } + + if (item.getUserLevelVo() != null && OtherExtKt.isVerify(item.getUserLevelVo().getCharmUrl())) { + ImageLoadUtils.loadImage(mContext, + item.getUserLevelVo().getCharmUrl(), + helper.getView(R.id.charmLevel) + ); + helper.getView(R.id.charmLevel).setVisibility(View.VISIBLE); + } else { + helper.getView(R.id.charmLevel).setVisibility(View.GONE); + } + + if (item.getUserVipInfoVO() != null && OtherExtKt.isVerify(item.getUserVipInfoVO().getNameplateUrl())) { + ImageLoadUtils.loadImage(mContext, + item.getUserVipInfoVO().getNameplateUrl(), + helper.getView(R.id.vip) + ); + helper.getView(R.id.vip).setVisibility(View.VISIBLE); + } else { + helper.getView(R.id.vip).setVisibility(View.GONE); + } + + + + helper.setText(R.id.tv_nickname, item.getNick()) + .setText(R.id.erBanNo, ResourcesKtxKt.getString(R.string.text_user_id,item.getErbanNo())) + .setText(R.id.tv_time, ResourcesKtxKt.getString(R.string._ver_24_View_Time_s,item.getVisitTimeDesc())) + .setImageResource(R.id.iv_gender, item.getGender() == 1 ? R.drawable.ic_gender_male : R.drawable.ic_gender_female); +// + helper.getView(R.id.iv_avatar).setOnClickListener(v -> + UserInfoActivity.Companion.start(mContext, item.getUid()) + ); + + View iconLayout = helper.getView(R.id.iconLayout); + View userNameLayout = helper.getView(R.id.userNameLayout); + TextView tvNickname = helper.getView(R.id.tv_nickname); + OtherExtKt.postSafe(iconLayout,() -> { + int iconWidth = iconLayout.getWidth(); + int userNameWidth = userNameLayout.getWidth(); + int tvNickWidth = userNameWidth - iconWidth; + tvNickname.setMaxWidth(tvNickWidth); + return null; + }); + + } + +} diff --git a/app/src/main/java/com/chwl/app/home/dialog/EventDurationDialog.kt b/app/src/main/java/com/chwl/app/home/dialog/EventDurationDialog.kt new file mode 100644 index 0000000..1ab177b --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/dialog/EventDurationDialog.kt @@ -0,0 +1,124 @@ +package com.chwl.app.home.dialog + +import android.content.Context +import android.view.Gravity +import android.view.ViewGroup.LayoutParams +import android.widget.TextView +import com.chwl.app.R +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.databinding.DialogEventDurationBinding +import com.chwl.app.home.helper.EventCenterUtil +import com.chwl.core.auth.AuthModel +import com.chwl.core.bean.response.ServiceResult +import com.chwl.core.gift.bean.EventUserConfig +import com.chwl.core.utils.net.RxHelper +import com.chwl.library.common.util.ClickUtils.click +import com.chwl.library.common.util.doLog +import com.chwl.library.common.util.isVerify +import com.chwl.library.net.rxnet.RxNet +import com.example.lib_utils.ktx.getColor +import com.jzxiang.pickerview.adapters.AbstractWheelTextAdapter +import com.jzxiang.pickerview.config.PickerConfig +import com.jzxiang.pickerview.wheel.OnWheelChangedListener +import com.jzxiang.pickerview.wheel.WheelView +import io.reactivex.Single +import retrofit2.http.GET +import retrofit2.http.Query + +class EventDurationDialog : BaseDialogFragment() { + + private lateinit var mAdapter : TimeAdapter + private var mSelect = 0 + private var mTimeData : List?=null + + private var mConfig:EventUserConfig? = null + + + override var height = LayoutParams.WRAP_CONTENT + override var width = LayoutParams.MATCH_PARENT + override var gravity = Gravity.BOTTOM + + override fun isCancelable() = false + + override fun init() { + + + binding.confirm.click { + mAdapter.mData.isVerify(mSelect) { + mActionCallBack?.onAction(mConfig?.durations?.get(mSelect)?:-1,mConfig?.getGoldNum()) + dismiss() + } + } + + val secConfig = PickerConfig() + secConfig.mWheelTVNormalColor = R.color.color_7b7b7d.getColor() + secConfig.mWheelTVSelectorColor = R.color.color_313131.getColor() + secConfig.mWheelTVSize = 18 + secConfig.cyclic = false + secConfig.mThemeColor = R.color.color_F4F4F4 + binding.timeList.setConfig(secConfig) + mAdapter = TimeAdapter(binding.timeList.context) + binding.timeList.viewAdapter = mAdapter + binding.timeList.isCyclic = false + binding.timeList.addChangingListener(OnWheelChangedListener { wheel: WheelView?, oldValue: Int, newValue: Int -> + " select oldValue=$oldValue newValue=$newValue".doLog() + mSelect = newValue + }) + binding.timeList.setCurrentItem(0, false) + } + + public fun setData(config: EventUserConfig?) { + config?.let { + mConfig = it + mTimeData = getTimeData(it.durations) + } + } + + override fun onResume() { + super.onResume() + mTimeData?.let { + mAdapter.setNewData(it) + } + } + + private fun getTimeData(ints: MutableList): List { + return ints.map { minute -> + EventCenterUtil.formatDuration(minute.toLong()) + } + } + + class TimeAdapter(context: Context) : AbstractWheelTextAdapter(context) { + + var mData:List = arrayListOf() + override fun getItemsCount() = mData.size + + override fun getItemText(pos: Int): CharSequence { + return mData[pos] + } + + override fun configureTextView(view: TextView?) { + super.configureTextView(view) + view?.textSize = 18f + } + + + fun setNewData(data : List) { + this.mData = data + notifyDataChangedEvent() + notifyDataInvalidatedEvent() + } + + } + + private fun getConfig(): Single { + return api.getConfig(AuthModel.get().currentUid) + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()) + } + + private val api: Api = RxNet.create(Api::class.java); + private interface Api{ + @GET("/userevent/goldConfig") + fun getConfig( @Query("uid") uid: Long): Single> + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/dialog/HelloMessageDialog.kt b/app/src/main/java/com/chwl/app/home/dialog/HelloMessageDialog.kt new file mode 100644 index 0000000..2855594 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/dialog/HelloMessageDialog.kt @@ -0,0 +1,63 @@ +package com.chwl.app.home.dialog + +import android.annotation.SuppressLint +import android.os.Bundle +import android.view.Gravity +import android.view.WindowManager +import android.widget.ImageView +import androidx.core.view.isGone +import com.chwl.app.R +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.databinding.DialogHelloMessageBinding +import com.chwl.app.ui.utils.load +import com.chwl.app.room_chat.activity.RoomMsgActivity +import com.chwl.core.channel_page.bean.HelloMessageInfo +import com.chwl.library.utils.ResUtil + +class HelloMessageDialog : BaseDialogFragment() { + + companion object { + + fun newInstance(helloMessageInfo: HelloMessageInfo): HelloMessageDialog { + val args = Bundle() + args.putSerializable("helloMessageInfo", helloMessageInfo) + val fragment = HelloMessageDialog() + fragment.arguments = args + return fragment + } + + } + + override var width: Int = WindowManager.LayoutParams.MATCH_PARENT + override var height: Int = WindowManager.LayoutParams.WRAP_CONTENT + override var gravity: Int = Gravity.TOP + override var dimAmount: Float = 0f + + private val helloMessageInfo: HelloMessageInfo by lazy { + requireArguments().getSerializable("helloMessageInfo") as HelloMessageInfo + } + + @SuppressLint("CheckResult", "SetTextI18n") + override fun init() { + val avatarList = listOf(binding!!.ivAvatar0, binding!!.ivAvatar1, binding!!.ivAvatar2) + avatarList.forEachIndexed { index, imageView -> + val avatarUrl = helloMessageInfo.sayHelloUserAvatarList?.getOrNull(index) + imageView.load(avatarUrl) + imageView.isGone = avatarUrl.isNullOrEmpty() + } + binding?.tvContent?.text = if (helloMessageInfo.sayHelloUserAvatarList?.size == 1) { + ResUtil.getString(R.string.home_dialog_hellomessagedialog_01) + } else { + ResUtil.getString(R.string.home_dialog_hellomessagedialog_02) + } + binding?.tvView?.setOnClickListener { + RoomMsgActivity.start(context) + dismissAllowingStateLoss() + } + binding?.ivClose?.setOnClickListener { + dismissAllowingStateLoss() + } + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/dialog/NewUserHelloDialog.kt b/app/src/main/java/com/chwl/app/home/dialog/NewUserHelloDialog.kt new file mode 100644 index 0000000..4f00278 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/dialog/NewUserHelloDialog.kt @@ -0,0 +1,54 @@ +package com.chwl.app.home.dialog + +import android.annotation.SuppressLint +import android.os.Bundle +import android.view.WindowManager +import com.chwl.app.avroom.activity.AVRoomActivity +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.databinding.DialogNewUserHelloBinding +import com.chwl.app.ui.utils.load +import com.chwl.core.channel_page.bean.NewUserHelloInfo +import com.chwl.core.utils.extension.subAndReplaceDot + +class NewUserHelloDialog : BaseDialogFragment() { + + companion object { + + fun newInstance(newUserHelloInfo: NewUserHelloInfo): NewUserHelloDialog { + val args = Bundle() + args.putSerializable("newUserHelloInfo", newUserHelloInfo) + val fragment = NewUserHelloDialog() + fragment.arguments = args + return fragment + } + + } + + override var width: Int = WindowManager.LayoutParams.MATCH_PARENT + override var dimAmount: Float = 0.8f + + private val newUserHelloInfo: NewUserHelloInfo by lazy { + requireArguments().getSerializable("newUserHelloInfo") as NewUserHelloInfo + } + + @SuppressLint("CheckResult", "SetTextI18n") + override fun init() { + binding?.ivClose?.setOnClickListener { + dismissAllowingStateLoss() + } + binding?.ivAvatar?.load(newUserHelloInfo.sayHelloUserAvatar) + binding?.tvId?.text = "ID:${newUserHelloInfo.sayHelloUserErbanNo}" + binding?.tvNick?.text = newUserHelloInfo.sayHelloUserNickname.subAndReplaceDot(8) + binding?.tvGoRoom?.setOnClickListener { + AVRoomActivity.startForFromType( + requireContext(), + newUserHelloInfo.roomUid, + AVRoomActivity.FROM_TYPE_HELLO, + newUserHelloInfo.sayHelloUserNickname, + newUserHelloInfo.sayHelloUserUid.toString() + ) + dismissAllowingStateLoss() + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/dialog/ProtocolUpdateDialog.java b/app/src/main/java/com/chwl/app/home/dialog/ProtocolUpdateDialog.java new file mode 100644 index 0000000..a135d06 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/dialog/ProtocolUpdateDialog.java @@ -0,0 +1,112 @@ +package com.chwl.app.home.dialog; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.method.LinkMovementMethod; +import android.text.style.ForegroundColorSpan; +import android.view.Gravity; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; + +import com.chwl.app.R; +import com.chwl.app.base.BaseSdDialog; +import com.chwl.app.common.widget.OriginalDrawStatusClickSpan; +import com.chwl.app.ui.webview.CommonWebViewActivity; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.core.user.bean.ProtocolInfo; +import com.chwl.core.utils.SharedPreferenceUtils; + +/** + * 家长模式 提醒框 + * create by lvzebiao @2019/7/27 + */ +public class ProtocolUpdateDialog extends BaseSdDialog implements View.OnClickListener { + + private TextView tvTitle; + private TextView tvContent; + private TextView tvCancel; + private TextView tvConfirm; + + @NonNull + private final ProtocolInfo protocolInfo; + + public static final String SP_KEY = "ProtocolUpdate"; + + public ProtocolUpdateDialog(Context context, @NonNull ProtocolInfo protocolInfo) { + super(context); + this.protocolInfo = protocolInfo; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.dialog_protocol_update); + findView(); + initListener(); + setCancelable(false); + setCanceledOnTouchOutside(false); + Window window = getWindow(); + if (window != null) { + window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); + WindowManager.LayoutParams windowParams = window.getAttributes(); + windowParams.width = UIUtil.dip2px(getContext(), 300); + windowParams.height = WindowManager.LayoutParams.WRAP_CONTENT; + windowParams.dimAmount = 0.5f; + windowParams.gravity = Gravity.CENTER; + window.setAttributes(windowParams); + } + + tvContent.setText(protocolInfo.getContent()); + tvTitle.setText(protocolInfo.getTitle()); + String privacyAgreementTip = protocolInfo.getLinkText(); + int privacyAgreementTipIndex = protocolInfo.getContent().indexOf(privacyAgreementTip); + SpannableString ss = new SpannableString(protocolInfo.getContent()); + ss.setSpan(new ForegroundColorSpan(ContextCompat.getColor(context, R.color.color_7154EE)), privacyAgreementTipIndex, privacyAgreementTipIndex + privacyAgreementTip.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + ss.setSpan(new OriginalDrawStatusClickSpan() { + @Override + public void onClick(@NonNull View widget) { + CommonWebViewActivity.start(getContext(), protocolInfo.getLinkUrl()); + } + }, privacyAgreementTipIndex, privacyAgreementTipIndex + privacyAgreementTip.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + tvContent.setText(ss); + tvContent.setMovementMethod(new LinkMovementMethod()); + } + + private void findView() { + tvTitle = findViewById(R.id.tv_title); + tvContent = findViewById(R.id.tv_content); + tvCancel = findViewById(R.id.tv_cancel); + tvConfirm = findViewById(R.id.tv_confirm); + } + + private void initListener() { + tvCancel.setOnClickListener(this); + tvConfirm.setOnClickListener(this); + } + + + @Override + public void onClick(View view) { + switch (view.getId()) { + case R.id.tv_cancel: + dismiss(); + ((Activity) context).finish(); + break; + case R.id.tv_confirm: + SharedPreferenceUtils.put(ProtocolUpdateDialog.SP_KEY, protocolInfo.getVer()); + dismiss(); + break; + } + } + +} diff --git a/app/src/main/java/com/chwl/app/home/dialog/RecommendRoomDialog.kt b/app/src/main/java/com/chwl/app/home/dialog/RecommendRoomDialog.kt new file mode 100644 index 0000000..e9e7c42 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/dialog/RecommendRoomDialog.kt @@ -0,0 +1,40 @@ +package com.chwl.app.home.dialog + +import android.annotation.SuppressLint +import android.os.Bundle +import com.chwl.app.avroom.activity.AVRoomActivity +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.databinding.DialogRecommendRoomBinding +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.core.home.bean.HomeRoomInfo + +class RecommendRoomDialog : BaseDialogFragment() { + + companion object { + + fun newInstance(roomInfo: HomeRoomInfo): RecommendRoomDialog { + val args = Bundle() + args.putSerializable("roomInfo", roomInfo) + val fragment = RecommendRoomDialog() + fragment.arguments = args + return fragment + } + + } + + private val roomInfo: HomeRoomInfo by lazy { requireArguments().getSerializable("roomInfo") as HomeRoomInfo } + + @SuppressLint("CheckResult") + override fun init() { + binding?.ivClose?.setOnClickListener { + dismissAllowingStateLoss() + } + binding?.tvGo?.setOnClickListener { + dismissAllowingStateLoss() + AVRoomActivity.start(context, roomInfo.uid) + } + binding?.tvRoomTitle?.text = roomInfo.title + ImageLoadUtils.loadImage(context, roomInfo.avatar, binding?.ivAvatar) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/event/ContactTrashEvent.java b/app/src/main/java/com/chwl/app/home/event/ContactTrashEvent.java new file mode 100644 index 0000000..4dc5589 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/event/ContactTrashEvent.java @@ -0,0 +1,4 @@ +package com.chwl.app.home.event; + +public class ContactTrashEvent { +} diff --git a/app/src/main/java/com/chwl/app/home/fragment/AttentionFragment.java b/app/src/main/java/com/chwl/app/home/fragment/AttentionFragment.java new file mode 100644 index 0000000..d211cdb --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/fragment/AttentionFragment.java @@ -0,0 +1,272 @@ +package com.chwl.app.home.fragment; + +import static com.chwl.app.R.id.swipe_refresh; +import static com.chwl.app.friend.action.AbstractSelectFriendAction.ROOM_MSG; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.os.Bundle; +import android.view.View; + +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chwl.app.R; +import com.chwl.app.avroom.activity.AVRoomActivity; +import com.chwl.app.base.BaseFragment; +import com.chwl.app.common.NoDataFragment; +import com.chwl.app.friend.action.AbstractSelectFriendAction; +import com.chwl.app.friend.view.SelectFriendActivity; +import com.chwl.app.ui.relation.adapter.AttentionListAdapter; +import com.chwl.app.ui.user.activity.UserInfoActivity; +import com.chwl.app.room_chat.activity.NimRoomP2PMessageActivity; +import com.chwl.core.Constants; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.praise.event.PraiseEvent; +import com.chwl.core.user.AttentionModel; +import com.chwl.core.user.bean.AttentionInfo; +import com.chwl.core.user.event.LoginUserInfoUpdateEvent; +import com.chwl.library.utils.ListUtils; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.ArrayList; +import java.util.List; + +import io.reactivex.SingleObserver; +import io.reactivex.disposables.Disposable; + +/** + *

主页关注界面

+ * + * @author Administrator + * @date 2017/11/14 + */ +public class AttentionFragment extends BaseFragment { + public static final String TAG = "AttentionFragment"; + + private RecyclerView mRecylcerView; + private SwipeRefreshLayout swipeRefreshLayout; + private AttentionListAdapter adapter; + private List mAttentionInfoList = new ArrayList<>(); + private int mPage = Constants.PAGE_START; + private int type; + + private SelectFriendActivity friendActivity; + + public static AttentionFragment newInstance(int type) { + AttentionFragment attentionFragment = new AttentionFragment(); + Bundle bundle = new Bundle(); + bundle.putInt(AbstractSelectFriendAction.KEY_TYPE, type); + attentionFragment.setArguments(bundle); + return attentionFragment; + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + EventBus.getDefault().register(this); + } + + @Override + public void onDestroy() { + super.onDestroy(); + EventBus.getDefault().unregister(this); + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + if (activity instanceof SelectFriendActivity) { + friendActivity = (SelectFriendActivity) activity; + } + } + + @Override + public void setUserVisibleHint(boolean isVisibleToUser) { + super.setUserVisibleHint(isVisibleToUser); + //需要踩人等东西,所以进入这个界面需要强制刷新 + if (isVisibleToUser) { + firstLoadData(); + } + } + + @Override + public void onFindViews() { + if (getArguments() != null) { + type = getArguments().getInt(AbstractSelectFriendAction.KEY_TYPE); + } + mRecylcerView = mView.findViewById(R.id.recycler_view); + swipeRefreshLayout = mView.findViewById(swipe_refresh); + mRecylcerView.setLayoutManager(new LinearLayoutManager(getContext())); + } + + @Override + public void onSetListener() { + swipeRefreshLayout.setOnRefreshListener(onRefreshLisetener); + adapter = new AttentionListAdapter(mAttentionInfoList); + adapter.setType(type); + adapter.setRylListener(new AttentionListAdapter.onClickListener() { + @Override + public void rylListeners(AttentionInfo attentionInfo) { + if (type == ROOM_MSG) { + NimRoomP2PMessageActivity.start(getActivity(), String.valueOf(attentionInfo.getUid())); + } else { + UserInfoActivity.Companion.start(getContext(), attentionInfo.getUid()); + } + } + + @Override + public void findHimListeners(AttentionInfo attentionInfo) { + if (attentionInfo.getUserInRoom() != null) + AVRoomActivity.startForFromType(mContext, attentionInfo.getUserInRoom().getUid(), + AVRoomActivity.FROM_TYPE_USER,attentionInfo.getNick(),String.valueOf(attentionInfo.getUid())); + } + + @Override + public void sendListener(AttentionInfo attentionInfo) { + if (friendActivity != null) { + friendActivity.showSureDialog(String.valueOf(attentionInfo.getUid()), attentionInfo.avatar, attentionInfo.getNick()); + } + } + }); + adapter.setOnLoadMoreListener(new BaseQuickAdapter.RequestLoadMoreListener() { + @Override + public void onLoadMoreRequested() { + mPage++; + onRefreshing(); + } + }, mRecylcerView); + } + + @Override + public void initiate() { + mRecylcerView.setAdapter(adapter); + swipeRefreshLayout.setRefreshing(true); + firstLoadData(); + } + + @Override + public int getRootLayoutId() { + return R.layout.fragment_fans_list; + } + + SwipeRefreshLayout.OnRefreshListener onRefreshLisetener = this::firstLoadData; + + public void firstLoadData() { + mPage = Constants.PAGE_START; + onRefreshing(); + } + + private void onRefreshing() { + AttentionModel.get().getAttentionList( + AuthModel.get().getCurrentUid(), + mPage, + Constants.PAGE_SIZE + ) + .subscribe(new SingleObserver>() { + @Override + public void onSubscribe(Disposable d) { + mCompositeDisposable.add(d); + } + + @Override + public void onSuccess(List attentionInfos) { + onGetAttentionList(attentionInfos, mPage); + } + + @Override + public void onError(Throwable e) { + onGetAttentionListFail(e.getMessage(), mPage); + } + }); + } + + public void onGetAttentionList(List attentionInfoList, int page) { + mPage = page; + if (!ListUtils.isListEmpty(attentionInfoList)) { + if (mPage == Constants.PAGE_START) { + hideStatus(); + swipeRefreshLayout.setRefreshing(false); + mAttentionInfoList.clear(); + adapter.setNewData(attentionInfoList); + if (attentionInfoList.size() < Constants.PAGE_SIZE) { + adapter.setEnableLoadMore(false); + } + } else { + adapter.loadMoreComplete(); + adapter.addData(attentionInfoList); + } + } else { + if (mPage == Constants.PAGE_START) { + swipeRefreshLayout.setRefreshing(false); + if (adapter != null) { + mAttentionInfoList.clear(); + adapter.setNewData(attentionInfoList); + } + showNoData(R.drawable.icon_common_failure, getString(R.string.no_attention_text)); + } else { + adapter.loadMoreEnd(true); + } + + } + } + + public void onGetAttentionListFail(String error, int page) { + mPage = page; + if (mPage == Constants.PAGE_START) { + swipeRefreshLayout.setRefreshing(false); + showNetworkErr(); + } else { + adapter.loadMoreFail(); + toast(error); + } + } + + @SuppressLint("ResourceType") + @Override + public void showNoData(View view, int drawable, CharSequence charSequence) { + if (!checkActivityValid()) + return; + + if (view == null) { + return; + } + View status = view.findViewById(R.id.status_layout); + if (status == null || status.getId() <= 0) { + return; + } + NoDataFragment fragment = NoDataFragment.newInstance(R.layout.frg_no_data_large_iv_transparent, drawable, charSequence); + fragment.setListener(getLoadListener()); + getChildFragmentManager().beginTransaction().replace(status.getId(), fragment, STATUS_TAG).commitAllowingStateLoss(); + } + + // ------------------关注动作回调 begin------------------- + @Subscribe(threadMode = ThreadMode.MAIN) + public void onPraise(PraiseEvent event) { + if (event.isFailed()) { + return; + } + onRefreshing(); + } + // ------------------关注动作回调 end------------------- + + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onLoginUserInfoUpdateEvent(LoginUserInfoUpdateEvent event) { + onRefreshing(); + } + + @Override + public void onReloadData() { + super.onReloadData(); + mPage = Constants.PAGE_START; + showLoading(); + onRefreshing(); + } +} diff --git a/app/src/main/java/com/chwl/app/home/fragment/ContactsListFragment.kt b/app/src/main/java/com/chwl/app/home/fragment/ContactsListFragment.kt new file mode 100644 index 0000000..414fdc7 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/fragment/ContactsListFragment.kt @@ -0,0 +1,171 @@ +package com.chwl.app.home.fragment + +import android.annotation.SuppressLint +import android.view.GestureDetector +import android.view.MotionEvent +import android.widget.LinearLayout +import android.widget.TextView +import androidx.core.view.GestureDetectorCompat +import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import androidx.viewpager2.widget.ViewPager2 +import com.chwl.app.MainTabContentView +import com.chwl.app.R +import com.chwl.app.avroom.adapter.CommonVPAdapter +import com.chwl.app.base.BaseViewBindingFragment +import com.chwl.app.databinding.FragmentContactListBinding +import com.chwl.app.home.HomeMessageViewModel +import com.chwl.app.home.helper.AutoScrollTask +import com.chwl.app.public_chat.ui.message.PublicChatRoomMessageActivity +import com.chwl.app.support.FragmentVisibleStateHelper +import com.chwl.app.ui.im.friend.FriendListFragment +import com.chwl.app.ui.im.recent.RecentListFragment +import com.chwl.app.ui.relation.FansListFragment +import com.chwl.app.ui.user.adapter.ContactsIndicatorAdapter +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.CommonNavigator +import com.chwl.app.utils.HomeUIManager +import com.chwl.core.Constants +import com.example.lib_utils.UiUtils + +/** + * @author jack + * @Description + * @Date 2018/11/1 + */ +class ContactsListFragment : BaseViewBindingFragment(), + MainTabContentView { + + private val viewModel: HomeMessageViewModel by activityViewModels() + + private val stateHelper = FragmentVisibleStateHelper(this).start { + onVisibleChanged(it) + } + companion object { + const val TAG = "ContactsListFragment" + + @JvmStatic + fun newInstance(): Fragment { + return ContactsListFragment() + } + } + + private var isRTL = false + + private val autoScrollTask = AutoScrollTask(15) { + val x = if (isRTL) { + -2 + } else { + 2 + } + } + + override fun init() { + isRTL = UiUtils.isRtl(requireContext()) + initViewPager() + initPublicChatView() + HomeUIManager.setHomeUI(binding.root) + } + + private fun initViewPager() { + val fragmentList: MutableList = ArrayList(4) + fragmentList.add(RecentListFragment.newInstance(false)) + fragmentList.add(FriendListFragment.newInstance(false, 0)) + fragmentList.add(AttentionFragment.newInstance(Constants.FAN_NO_MAIN_PAGE_TYPE)) + fragmentList.add(FansListFragment.newInstance(Constants.FAN_NO_MAIN_PAGE_TYPE)) + val tagList: MutableList = ArrayList(4) + tagList.add(getString(R.string.message)) + tagList.add(getString(R.string.layout_fragment_contact_list_02)) + tagList.add(getString(R.string.layout_fragment_contact_list_03)) + tagList.add(getString(R.string.layout_fragment_contact_list_04)) + val commonNavigator = CommonNavigator(context) + commonNavigator.setTitleWrapContent(false) + val magicIndicatorAdapter = ContactsIndicatorAdapter(context, tagList) + magicIndicatorAdapter.setOnItemSelectListener { position: Int, view: TextView? -> + binding.viewPager.currentItem = position + } + commonNavigator.adapter = magicIndicatorAdapter + binding.magicIndicator.navigator = commonNavigator + commonNavigator.titleContainer.showDividers = LinearLayout.SHOW_DIVIDER_MIDDLE + binding.viewPager.offscreenPageLimit = 4 + binding.viewPager.adapter = CommonVPAdapter(childFragmentManager, lifecycle, fragmentList) + binding.viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { + override fun onPageScrollStateChanged(state: Int) { + super.onPageScrollStateChanged(state) + binding.magicIndicator.onPageScrollStateChanged(state) + } + + override fun onPageScrolled( + position: Int, + positionOffset: Float, + positionOffsetPixels: Int + ) { + super.onPageScrolled(position, positionOffset, positionOffsetPixels) + binding.magicIndicator.onPageScrolled( + position, + positionOffset, + positionOffsetPixels + ) + } + + override fun onPageSelected(position: Int) { + super.onPageSelected(position) + binding.magicIndicator.onPageSelected(position) + binding.viewPager.requestLayout() + } + }) + } + + @SuppressLint("ClickableViewAccessibility") + private fun initPublicChatView() { + val gestureDetectorCompat = GestureDetectorCompat(requireContext(), object : + GestureDetector.OnGestureListener { + override fun onDown(e: MotionEvent): Boolean { + return true + } + + override fun onShowPress(e: MotionEvent) { + } + + override fun onSingleTapUp(e: MotionEvent): Boolean { + PublicChatRoomMessageActivity.start(requireContext()) + return true + } + + override fun onScroll( + e1: MotionEvent?, + e2: MotionEvent, + distanceX: Float, + distanceY: Float + ): Boolean { + return true + } + + override fun onLongPress(e: MotionEvent) { + } + + override fun onFling( + e1: MotionEvent?, + e2: MotionEvent, + velocityX: Float, + velocityY: Float + ): Boolean { + return true + } + }) + } + + private fun switchPublicChatMessageScrollState(isVisible: Boolean) { +// if (isVisible && publicChatAdapter.getRealItemCount() > 0) { +// autoScrollTask.start() +// } else { +// autoScrollTask.stop() +// } + } + + private fun onVisibleChanged(isVisible: Boolean) { +// switchPublicChatMessageScrollState(isVisible) +// if (isVisible) { +// viewModel.getTopPublicChatMessageIfNull() +// } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/fragment/EventMyFragment.kt b/app/src/main/java/com/chwl/app/home/fragment/EventMyFragment.kt new file mode 100644 index 0000000..b3df0d3 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/fragment/EventMyFragment.kt @@ -0,0 +1,302 @@ +package com.chwl.app.home.fragment + +import android.view.View +import android.view.ViewGroup +import com.chwl.app.R +import com.chwl.app.avroom.activity.AVRoomActivity +import com.chwl.app.base.BaseViewBindingFragment +import com.chwl.app.common.EmptyViewHelper +import com.chwl.app.common.widget.dialog.DialogManager +import com.chwl.app.databinding.FragmentEventMyBinding +import com.chwl.app.databinding.ItemEventMyHeadBinding +import com.chwl.app.home.activity.EventCreateActivity +import com.chwl.app.home.activity.EventMyAllActivity +import com.chwl.app.home.adapter.EventSquareAdapter +import com.chwl.app.ui.webview.CommonWebViewActivity +import com.chwl.core.UriProvider +import com.chwl.core.auth.AuthModel +import com.chwl.core.bean.EventOfficialBean +import com.chwl.core.bean.response.ServiceResult +import com.chwl.core.utils.net.RxHelper +import com.chwl.library.common.util.ClickUtils.click +import com.chwl.library.common.util.doLog +import com.chwl.library.common.util.doToast +import com.chwl.library.common.util.isVerify +import com.chwl.library.common.util.setVis +import com.chwl.library.net.rxnet.RxNet +import com.example.lib_utils.ktx.dp +import com.example.lib_utils.ktx.getString +import com.google.gson.JsonElement +import com.scwang.smart.refresh.layout.api.RefreshLayout +import com.scwang.smart.refresh.layout.listener.OnRefreshLoadMoreListener +import io.reactivex.Single +import retrofit2.http.GET +import retrofit2.http.POST +import retrofit2.http.Query + +class EventMyFragment : BaseViewBindingFragment() { + + private lateinit var mAdapter: EventSquareAdapter + private lateinit var mHeadAdapter: EventSquareAdapter + private lateinit var mHeadViewBinding : ItemEventMyHeadBinding + private var mPage = 1; + private lateinit var mEmptyView2 : View + override fun init() { + + mHeadViewBinding = ItemEventMyHeadBinding.inflate(layoutInflater) + mHeadAdapter = EventSquareAdapter(true) + mHeadAdapter.setOnItemClickListener { baseQuickAdapter, view, i -> + mHeadAdapter.data.isVerify(i){ + CommonWebViewActivity.start(context, UriProvider.getEventDetail(it.id)) + } + } + + mHeadAdapter.setOnItemChildClickListener { baseQuickAdapter, view, i -> + when (view.id) { + R.id.btnNext -> { + mHeadAdapter.data?.isVerify(i){ + when (it.btnStatus) { + EventSquareAdapter.B_IN_ROOM-> { + AVRoomActivity.start(context,it.roomUid) + + } + EventSquareAdapter.B_SUB->{ + doEventSub(mHeadAdapter,it,i) + } + EventSquareAdapter.B_DEL->{ + doEventDel(mHeadAdapter,it,i) + } + } + } + } + } + } + mHeadViewBinding.rvList.adapter = mHeadAdapter + mHeadViewBinding.TvMyEvent.click { + context?.let { it1 -> EventMyAllActivity.start(it1) } + } + + + mAdapter = EventSquareAdapter(false) + mAdapter.setOnItemClickListener { baseQuickAdapter, view, i -> + mAdapter.data.isVerify(i){ + CommonWebViewActivity.start(context,UriProvider.getEventDetail(it.id)) + } + } + mAdapter.setOnItemChildClickListener { baseQuickAdapter, view, i -> + when (view.id) { + R.id.btnNext -> { + mAdapter.data?.isVerify(i){ + when (it.btnStatus) { + EventSquareAdapter.B_IN_ROOM-> { + AVRoomActivity.start(context,it.roomUid) + + } + EventSquareAdapter.B_SUB->{ + doEventSub(mAdapter,it,i) + } + } + } + } + } + } + mEmptyView2 = EmptyViewHelper.createEmptyView( + context, R.drawable.base_status_empty, R.string.empty_data.getString(), + ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + 300.dp + ) + ) + mAdapter.addHeaderView(mHeadViewBinding.root) + binding.rvList.adapter = mAdapter + + + binding.btnNext.click { + context?.let { it1 -> EventCreateActivity.start(it1) } + } + + binding.srlList.setOnRefreshLoadMoreListener(object : OnRefreshLoadMoreListener { + override fun onRefresh(refreshLayout: RefreshLayout) { + mPage = 1 + getData() + } + override fun onLoadMore(refreshLayout: RefreshLayout) { + getData() + } + }) + + + } + + + + override fun onResume() { + super.onResume() + mPage = 1 + getData() + "Fragment=${this@EventMyFragment::class.java.simpleName} onResume".doLog() + } + + private fun getData() { + if (mPage == 1) { + getEventMySquare() + .compose(bindToLifecycle()) + .doOnSuccess { + mHeadAdapter.setNewData(it) + mHeadViewBinding.empty.setVis(!it.isVerify()) + } + .doOnError { + it?.message?.doToast() + }.subscribe() + } + + getEventMySub(mPage) + .compose(bindToLifecycle()) + .doOnSuccess { + if (mPage == 1) { + mAdapter.setNewData(it) + } else { + mAdapter.addData(it) + } + + if (it.size == 20) { + mPage ++ + } + + binding.srlList.setEnableLoadMore(it.size == 20) + binding.srlList.finishRefresh() + binding.srlList.finishLoadMore() + + if (mAdapter.data.isVerify()) { + if (mAdapter.footerLayout != null && mAdapter.footerLayoutCount != 0) { + mAdapter.footerLayout.removeAllViews() + } + } else { + if (mAdapter.footerLayout == null || mAdapter.footerLayoutCount == 0) { + mAdapter.addFooterView(mEmptyView2) + } + } + } + .doOnError { + binding.srlList.finishRefresh() + binding.srlList.finishLoadMore() + it?.message?.doToast() + }.subscribe() + + } + + + private fun doEventSub( + adapter: EventSquareAdapter, + eventOfficialBean: EventOfficialBean, + pos: Int + ) { + val status = !eventOfficialBean.isSubStatus + val statusInt = if (status) 1 else 0 + postSub(eventOfficialBean.id, statusInt) + .compose(bindToLifecycle()) + .doOnSuccess { + adapter.data.isVerify(pos) { + try { + if (status) { + it.subStatus = status + it.subNum += if (status) 1 else -1 + adapter.notifyItemChanged(pos+adapter.headerLayoutCount) + } else { + adapter.remove(pos) + } + } catch (e: Exception) { + } + } + } + .doOnError { + it?.message?.doToast() + }.subscribe() + } + + private fun doEventDel( + adapter: EventSquareAdapter, + eventOfficialBean: EventOfficialBean, + pos: Int + ) { + var dialog = dialogManager + if (dialog == null) { + dialog = DialogManager(context) + } + val desc = StringBuilder() + desc.appendLine(R.string.v_27_del_event_1.getString()) + desc.appendLine(R.string.v_27_del_event_2.getString()) + desc.appendLine(R.string.v_27_del_event_3.getString()) + desc.appendLine(R.string.v_27_del_event_4.getString()) + dialog.showOkCancelDialog( + R.string.Confirmation.getString(), + desc.toString(), + R.string.delete.getString(), + R.string.cancel.getString() + ) { + postDel(eventOfficialBean.id) + .compose(bindToLifecycle()) + .doOnSuccess { + adapter.data.isVerify(pos) { + adapter.remove(pos) + } + mHeadViewBinding.empty.setVis(!mHeadAdapter.data.isVerify()) + } + .doOnError { + it?.message?.doToast() + }.subscribe() + } + + } + + + private fun getEventMySquare(): Single> { + return api.getEventMySquare(AuthModel.get().currentUid,1,4) + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()) + } + + private fun getEventMySub(page:Int): Single> { + return api.getEventMySub(AuthModel.get().currentUid,page,20) + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()) + } + + + private fun postSub(eventId: Long,subStatus:Int): Single { + return api.postSub(AuthModel.get().currentUid,eventId,subStatus) + .compose(RxHelper.handleIgnoreData()) + .compose(RxHelper.handleSchedulers()) + } + + private fun postDel(eventId: Long): Single { + return api.postDel(eventId) + .compose(RxHelper.handleIgnoreData()) + .compose(RxHelper.handleSchedulers()) + } + + + private val api: Api = RxNet.create(Api::class.java); + interface Api { + @GET("/userevent/mysquare") + fun getEventMySquare(@Query("uid") uid: Long,@Query("page") page: Int, @Query("pageSize") pageSize: Int): Single>> + + @GET("/userevent/mySub") + fun getEventMySub(@Query("uid") uid: Long,@Query("page") page: Int, @Query("pageSize") pageSize: Int): Single>> + + + @POST("/userevent/sub") + fun postSub( + @Query("uid") uid: Long, + @Query("eventId") eventId: Long, + @Query("subStatus") subStatus: Int + ): Single> + + @POST("/userevent/del") + fun postDel( + @Query("eventId") eventId: Long, + ): Single> + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/fragment/EventOfficialFragment.kt b/app/src/main/java/com/chwl/app/home/fragment/EventOfficialFragment.kt new file mode 100644 index 0000000..564f9a5 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/fragment/EventOfficialFragment.kt @@ -0,0 +1,104 @@ +package com.chwl.app.home.fragment + +import android.view.View +import android.view.ViewGroup +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingFragment +import com.chwl.app.common.EmptyViewHelper +import com.chwl.app.databinding.FragmentEventOfficialBinding +import com.chwl.app.home.adapter.EventOfficialAdapter +import com.chwl.app.utils.CommonJumpHelper +import com.chwl.core.auth.AuthModel +import com.chwl.core.bean.response.ServiceResult +import com.chwl.core.home.bean.BannerInfo +import com.chwl.core.utils.net.RxHelper +import com.chwl.library.common.util.doLog +import com.chwl.library.common.util.doToast +import com.chwl.library.common.util.isVerify +import com.chwl.library.net.rxnet.RxNet +import com.example.lib_utils.ktx.getString +import io.reactivex.Single +import retrofit2.http.GET +import retrofit2.http.Query + +class EventOfficialFragment : BaseViewBindingFragment() { + + + private lateinit var mAdapter: EventOfficialAdapter + + override fun init() { + mAdapter = EventOfficialAdapter() + mAdapter.onItemClickListener = object : BaseQuickAdapter.OnItemClickListener { + override fun onItemClick(p0: BaseQuickAdapter<*, *>?, p1: View?, p2: Int) { + mAdapter.data.isVerify(p2){ banner-> + CommonJumpHelper.bannerJump(context, banner) + } + } + } + val emptyView = EmptyViewHelper.createEmptyView( + context, R.drawable.base_status_empty, R.string.empty_data.getString(), + ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ) + ) + mAdapter.emptyView = emptyView + binding.rvList.adapter = mAdapter + + binding.srlList.setOnRefreshListener { getData() } + + } + + + + override fun onResume() { + super.onResume() + getData() + "Fragment=${this@EventOfficialFragment::class.java.simpleName} onResume".doLog() + } + private fun getData() { + apiHomeBanner() + .doOnSuccess { + mAdapter.setNewData(it) + binding.srlList.finishRefresh() + } + .doOnError { + binding.srlList.finishRefresh() + it?.message?.doToast() + } + .subscribe() + } + + private fun apiHomeBanner(): Single> { + return api.apiHomeBanner( + "1", + AuthModel.get().currentUid.toString(), + 1 + ) + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()) + } + + + private val api: Api = RxNet.create(Api::class.java); + + private interface Api { + + /** + * 首页Banner + * + * @param type + * @param uid + * @param types + * @param ticket + * @return + */ + @GET("/home/banner") + fun apiHomeBanner( + @Query("type") type: String, + @Query("uid") uid: String, + @Query("activityShow") activityShow: Int, + ): Single>> + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/fragment/EventSquareFragment.kt b/app/src/main/java/com/chwl/app/home/fragment/EventSquareFragment.kt new file mode 100644 index 0000000..a444945 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/fragment/EventSquareFragment.kt @@ -0,0 +1,178 @@ +package com.chwl.app.home.fragment + +import android.view.ViewGroup +import com.chwl.app.R +import com.chwl.app.avroom.activity.AVRoomActivity +import com.chwl.app.base.BaseViewBindingFragment +import com.chwl.app.common.EmptyViewHelper +import com.chwl.app.databinding.FragmentEventSquareBinding +import com.chwl.app.home.activity.EventCreateActivity +import com.chwl.app.home.adapter.EventSquareAdapter +import com.chwl.app.ui.webview.CommonWebViewActivity +import com.chwl.core.UriProvider +import com.chwl.core.auth.AuthModel +import com.chwl.core.bean.EventOfficialBean +import com.chwl.core.bean.response.ServiceResult +import com.chwl.core.utils.net.RxHelper +import com.chwl.library.common.util.ClickUtils.click +import com.chwl.library.common.util.doLog +import com.chwl.library.common.util.doToast +import com.chwl.library.common.util.isVerify +import com.chwl.library.net.rxnet.RxNet +import com.example.lib_utils.ktx.getString +import com.google.gson.JsonElement +import com.scwang.smart.refresh.layout.api.RefreshLayout +import com.scwang.smart.refresh.layout.listener.OnRefreshLoadMoreListener + + +import io.reactivex.Single +import retrofit2.http.GET +import retrofit2.http.POST +import retrofit2.http.Query + +class EventSquareFragment : BaseViewBindingFragment() { + + + private lateinit var mAdapter: EventSquareAdapter + private var mPage = 1; + + + override fun init() { + + mAdapter = EventSquareAdapter(false) + mAdapter.setOnItemClickListener { baseQuickAdapter, view, i -> + mAdapter.data.isVerify(i){ + CommonWebViewActivity.start(context,UriProvider.getEventDetail(it.id)) + } + } + mAdapter.setOnItemChildClickListener { baseQuickAdapter, view, i -> + when (view.id) { + R.id.btnNext -> { + mAdapter.data?.isVerify(i){ + when (it.btnStatus) { + EventSquareAdapter.B_IN_ROOM-> { + AVRoomActivity.start(context,it.roomUid) + } + EventSquareAdapter.B_SUB->{ + doEventSub(it,i) + } + EventSquareAdapter.B_DEL->{ + + } + } + } + } + } + } + val emptyView = EmptyViewHelper.createEmptyView( + context, R.drawable.base_status_empty, R.string.empty_data.getString(), + ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ) + ) + mAdapter.emptyView = emptyView + mAdapter.isUseEmpty(true) + binding.rvList.adapter = mAdapter + binding.btnNext.click { + context?.let { it1 -> EventCreateActivity.start(it1) } + } + + binding.srlList.setOnRefreshLoadMoreListener(object : OnRefreshLoadMoreListener { + + override fun onRefresh(p0: RefreshLayout) { + mPage = 1 + getData() + } + + override fun onLoadMore(p0: RefreshLayout) { + getData() + } + }) + + + + } + + + + override fun onResume() { + super.onResume() + mPage = 1 + getData() + "Fragment=${this@EventSquareFragment::class.java.simpleName} onResume".doLog() + } + + private fun doEventSub(eventOfficialBean: EventOfficialBean, pos: Int) { + val status = !eventOfficialBean.isSubStatus + val statusInt = if (status) 1 else 0 + postSub(eventOfficialBean.id, statusInt) + .compose(bindToLifecycle()) + .doOnSuccess { + mAdapter.data.isVerify(pos) { + it.subStatus = status + it.subNum += if (status) 1 else -1 + mAdapter.notifyItemChanged(pos) + } + } + .doOnError { + it?.message?.doToast() + }.subscribe() + } + + private fun getData() { + getEventSquare(mPage) + .compose(bindToLifecycle()) + .doOnSuccess { + if (mPage == 1) { + mAdapter.setNewData(it) + } else { + mAdapter.addData(it) + } + + if (it.size == 20) { + mPage ++ + } + + binding.srlList.setEnableLoadMore(it.size == 20) + binding.srlList.finishRefresh() + binding.srlList.finishLoadMore() + } + .doOnError { + binding.srlList.finishRefresh() + binding.srlList.finishLoadMore() + it?.message?.doToast() + }.subscribe() + } + + + private fun getEventSquare(page:Int): Single> { + return api.getEventSquare(page,20) + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()) + } + + + private fun postSub(eventId: Long,subStatus:Int): Single { + return api.postSub(AuthModel.get().currentUid,eventId,subStatus) + .compose(RxHelper.handleIgnoreData()) + .compose(RxHelper.handleSchedulers()) + } + + + private val api: Api = RxNet.create(Api::class.java); + interface Api { + @GET("/userevent/square") + fun getEventSquare(@Query("page") page: Int,@Query("pageSize") pageSize: Int): Single>> + + + @POST("/userevent/sub") + fun postSub( + @Query("uid") uid: Long, + @Query("eventId") eventId: Long, + @Query("subStatus") subStatus: Int + ): Single> + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/fragment/HomeFragment.kt b/app/src/main/java/com/chwl/app/home/fragment/HomeFragment.kt new file mode 100644 index 0000000..ba8fdc2 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/fragment/HomeFragment.kt @@ -0,0 +1,131 @@ +package com.chwl.app.home.fragment + +import android.view.View +import android.widget.TextView +import androidx.fragment.app.Fragment +import com.chwl.app.BuildConfig +import com.chwl.app.R +import com.chwl.app.application.IReportConstants +import com.chwl.app.application.ReportManager +import com.chwl.app.avroom.adapter.CommonVPAdapter +import com.chwl.app.base.BaseViewBindingFragment +import com.chwl.app.databinding.FragmentHomeBinding +import com.chwl.app.ui.search.SearchActivity +import com.chwl.app.ui.user.adapter.ContactsIndicatorAdapter +import com.chwl.app.ui.widget.magicindicator.ViewPagerHelper +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.CommonNavigator +import com.chwl.app.utils.HomeUIManager +import com.chwl.core.DemoCache +import com.chwl.library.common.util.doLog +import com.example.lib_utils.ktx.getString + +/** +首页 + */ +class HomeFragment : BaseViewBindingFragment(), View.OnClickListener { + + override fun init() { + initListener() + initTab() + HomeUIManager.setHomeUI(binding.root) + } + + private fun initListener() { + binding.tvSearch.setOnClickListener(this) + binding.layoutTitleBar.setOnClickListener(this) + } + + override fun onClick(v: View) { + when (v.id) { + R.id.layout_title_bar->{ + if (BuildConfig.DEBUG) { + //todo do 测试代码 + context?.let { context-> +// +// val str1 = "字符串1" +// val str2 = "字符串2" +// val str3 = "字符串3" +// +// R.string.v26_s_send_s_win_s.getString(str1,str2,str3).doLog() + +// GiftDialog(context,-1).show() + + "测试 ${R.string.v_27_Banner_Costs.getString(111)}".doLog() + + +// RoomMsgTabFragment().show(context) + + + // 在ViewModel或Activity中调用 +// lifecycleScope.launch { +// val success = ZipDownloader.downloadAndUnzip( +// context = requireContext(), +// zipUrl = "https://molistar-1320554189.cos.ap-hongkong.myqcloud.com/TestFace.zip", +// targetSubDir = "download/face" +// ) +// "表情包 获取表情包结果 = $success".doLog() +// +// if (success) { +// // 解压后的文件路径: +// val faceDir = File(requireContext().getExternalFilesDir(null), "download/face") +// Toast.makeText(context, "文件已保存到:$faceDir", Toast.LENGTH_SHORT).show() +// "表情包 已保存到 = $faceDir".doLog() +// } else { +// Toast.makeText(context, "下载失败", Toast.LENGTH_SHORT).show() +// } +// } + +// EventCenterActivity.start(context) +// EventCreateActivity.start(context) +// EventSelectRoomActivity.start(context) +// DynamicFaceDialog().show(context) + +// EventDurationDialog().show(context) + + + } + } + } + + R.id.tv_search -> { + //首页_搜索 + ReportManager.get().reportEvent( + IReportConstants.MODULE_HOMEPAGE_CLICK, mapOf( + Pair(IReportConstants.HOMEPAGE_TYPE, IReportConstants.ONE), + Pair(IReportConstants.MODULE, IReportConstants.MOLISTAR_HOMEPAGE) + ) + ) + SearchActivity.start(activity) + //为啥触发条件这么恶心 + if (DemoCache.readAnchorCardView() == 0) { + DemoCache.saveAnchorCardView(1) + } + } + } + } + + private fun initTab() { + val fragmentList = ArrayList() + fragmentList.add(HomeRecommendFragment()) + fragmentList.add(HomeWithMeFragment()) + val titleList = ArrayList() + titleList.add(getString(R.string.main_tab_recommend)) + titleList.add(getString(R.string.main_me)) + val commonNavigator = CommonNavigator(context) + commonNavigator.setTitleWrapContent(false) + val magicIndicatorAdapter = ContactsIndicatorAdapter(context, titleList) + magicIndicatorAdapter.setOnItemSelectListener { position: Int, view: TextView? -> + binding.viewPager.currentItem = position + } + commonNavigator.adapter = magicIndicatorAdapter + binding.magicIndicator.navigator = commonNavigator + binding.viewPager.offscreenPageLimit = 2 + binding.viewPager.adapter = CommonVPAdapter( + childFragmentManager, + lifecycle, + fragmentList + ) + ViewPagerHelper.bind(binding.magicIndicator, binding.viewPager) + binding.viewPager.isUserInputEnabled = false + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/fragment/HomeRecommendFragment.kt b/app/src/main/java/com/chwl/app/home/fragment/HomeRecommendFragment.kt new file mode 100644 index 0000000..9e9b939 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/fragment/HomeRecommendFragment.kt @@ -0,0 +1,400 @@ +package com.chwl.app.home.fragment + +import android.graphics.Color +import android.util.SparseArray +import android.view.LayoutInflater +import android.view.View +import androidx.core.view.isVisible +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentTransaction +import androidx.fragment.app.activityViewModels +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener +import androidx.viewpager2.widget.ViewPager2 +import com.chwl.app.R +import com.chwl.app.application.IReportConstants +import com.chwl.app.application.ReportManager +import com.chwl.app.avroom.activity.AVRoomActivity +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.base.BaseViewBindingFragment +import com.chwl.app.databinding.FragmentHomeRecommendBinding +import com.chwl.app.databinding.ItemHomeRecommentdTagBinding +import com.chwl.app.home.HomeViewModel +import com.chwl.app.home.activity.EventCenterActivity +import com.chwl.app.home.adapter.HomeBannerAdapter +import com.chwl.app.home.adapter.HomeRankViewFlipperAdapter +import com.chwl.app.home.dialog.RecommendRoomDialog +import com.chwl.app.support.FragmentVisibleStateHelper +import com.chwl.app.ui.bean.CountryBean +import com.chwl.app.ui.login.dialog.CountrySelectDialog +import com.chwl.app.ui.search.SearchActivity +import com.chwl.app.ui.utils.load +import com.chwl.app.ui.webview.CommonWebViewActivity +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil +import com.chwl.app.utils.CommonJumpHelper +import com.chwl.app.utils.HomeUIManager +import com.chwl.core.DemoCache +import com.chwl.core.auth.AuthModel +import com.chwl.core.home.bean.BannerInfo +import com.chwl.core.home.bean.HomeTagInfo +import com.chwl.library.common.util.ClickUtils.click +import com.chwl.library.common.util.isVerify +import com.chwl.library.common.util.setMargin +import com.chwl.library.common.util.setRL +import com.chwl.library.common.util.setVis +import com.chwl.library.common.util.toColor +import com.chwl.library.utils.ListUtils +import com.example.lib_utils.ktx.getColor +import com.zhpan.bannerview.BannerViewPager +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.launch + +/** +首页 + */ +class HomeRecommendFragment : BaseViewBindingFragment(), + View.OnClickListener { + + private val homeViewModel: HomeViewModel by activityViewModels() + private val tabList = mutableListOf() + private val fragmentArray = SparseArray() + private var tempFragment: Fragment? = null + private var mPosition = 0 + private val tabViewList = mutableListOf() + + override fun init() { + initListener() + initTab() + initBanner() + initResource() + initRank() + FragmentVisibleStateHelper(this).apply { + start { + onVisibleChanged(it, isFirstVisible) + } + } + if (AuthModel.get().isLogin) { + homeViewModel.getHomeTabInfo() + homeViewModel.getBannerInfo() + homeViewModel.getHomeResourceInfo() + homeViewModel.getHomeRankList() + } + + + if (HomeUIManager.mConfigInfo?.appUiSetting?.backgroundColor.isVerify()) { + binding.tabLayoutMarks.setGradientDrawable(R.color.transparent.getColor(),-1, Color.parseColor(HomeUIManager.mConfigInfo?.appUiSetting?.backgroundColor),-1,-1f) + } + + binding.tabLayoutMarks.setRL() + } + + var isFirst = true + override fun onResume() { + super.onResume() + if (!isFirst) { + if (!tabList.isVerify()) { + binding.refreshLayout.autoRefresh() + } + } else { + isFirst = false + } + } + + private fun initListener() { + binding.refreshLayout.setOnRefreshListener { + if (!AuthModel.get().isLogin) return@setOnRefreshListener + it.finishRefresh() + try { + childFragmentManager?.fragments?.forEach { + (it as? OnRefreshListener)?.onRefresh() + } + } catch (e: Exception) { } + + if (!tabList.isVerify()){ + homeViewModel.getHomeTabInfo() + } + homeViewModel.getBannerInfo() + homeViewModel.getHomeRankList() + homeViewModel.getHomeResourceInfo() + } + binding.refreshLayout.setEnableLoadMore(false) + binding.refreshLayout.setEnableOverScrollBounce(false) + } + + private fun initResource() { + homeViewModel.homeResourceLiveData.observe(this) { + it?.let { + val resourceViews = arrayOf( + binding.ivResource0 + ) + if (it.size != 2) { + resourceViews.forEach { + it.isVisible = false + } + binding.viewFlipper.isVisible = false + return@observe + } + binding.viewFlipper.isVisible = true + resourceViews.forEachIndexed { index, imageView -> + imageView.isVisible = true + if (index != 0) { + imageView.load(it[index].icon) + } + imageView.setOnClickListener { _ -> + when { + it[index].resourceType == 5 -> { + CommonWebViewActivity.start(context, it[index].resourceContent) + } + + else -> { + dialogManager.showProgressDialog(mContext) + homeViewModel.getResourceJumpInfo(it[index].id) + } + } + } + } + } + } + + lifecycleScope.launch { + lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) { + homeViewModel.resourceJumpFlow.collectLatest { + dialogManager.dismissDialog() + it?.let { + if (it.isPick) { + AVRoomActivity.start(context, it.uid) + } else { + RecommendRoomDialog.newInstance(it).show(context) + } + } + } + } + } + binding.ivResource1.setVis(true) + binding.ivResource1.click { + context?.let { it1 -> EventCenterActivity.start(it1) } + } + } + + private fun initBanner() { + //xxx , 周星自动化 + val bannerView: BannerViewPager = binding.bannerView as BannerViewPager + homeViewModel.bannerLiveData.observe(this) { + it?.let { + if (ListUtils.isListEmpty(it)) { + bannerView.visibility = View.GONE + return@let + } + bannerView.visibility = View.VISIBLE + bannerView.adapter = HomeBannerAdapter() + bannerView.post { + binding.bannerView.setPageMargin(UIUtil.dip2px(mContext, 8.0)) + .setScrollDuration(800) + .setOnPageClickListener { _: View?, position: Int -> + CommonJumpHelper.bannerJump(context, it[position]) + } + .registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { + override fun onPageSelected(position: Int) { + super.onPageSelected(position) + + } + }) + .create(it) + } + } + } + } + + private fun initRank() { + val rankAdapter = HomeRankViewFlipperAdapter() + binding.viewFlipper.adapter = rankAdapter + binding.viewFlipper.setInAnimation(context, R.animator.home_rank_anim_in) + binding.viewFlipper.setOutAnimation(context, R.animator.home_rank_anim_out) + homeViewModel.homeRankListLiveData.observe(this) { + rankAdapter.setNewData(it ?: emptyList()) + } + } + + override fun onClick(v: View) { + when (v.id) { + R.id.tv_search -> { + //首页_搜索 + ReportManager.get().reportEvent( + IReportConstants.MODULE_HOMEPAGE_CLICK, mapOf( + Pair(IReportConstants.HOMEPAGE_TYPE, IReportConstants.ONE), + Pair(IReportConstants.MODULE, IReportConstants.MOLISTAR_HOMEPAGE) + ) + ) + SearchActivity.start(activity) + //为啥触发条件这么恶心 + if (DemoCache.readAnchorCardView() == 0) { + DemoCache.saveAnchorCardView(1) + } + } + + binding.tabLayoutMore.id->{ + + val listData = arrayListOf() + tabList.forEachIndexed { index, homeTagInfo -> + if (homeTagInfo.regionId != -1) { + listData.add(CountryBean().apply { + id = homeTagInfo.id + name = homeTagInfo.name + icon = homeTagInfo.icon + checked = index == mPosition + }) + } + } + + CountrySelectDialog().apply { + isRegion = false + mData = listData + mActionCallBack = object : BaseDialogFragment.Action { + override fun onAction(type: Int, data: Any?) { + if (data is CountryBean) { + + val indexOfFirst = tabList.indexOfFirst { tab -> + tab.id == data.id + } + + if (indexOfFirst != -1) { + selectTabView(indexOfFirst) + this@HomeRecommendFragment.binding.tabLayout.postDelayed({ + this@HomeRecommendFragment.binding.tabLayout.scrollToTab(mPosition, 0f) + }, 200) + } + + } + + } + } + }.show(context) + } + } + + + } + + private fun initTab() { + + homeViewModel.homeTabLiveData.observe(this) { + loadTabList(transformTabList(it)) + } + + binding.tabLayoutMore.setOnClickListener(this) + } + + private fun resetTabIndicator(list: List) { + + tabViewList.clear() + + binding.tabLayout.setViews(list.size) { container, position, adapter -> + val from = LayoutInflater.from(container.context) + val view = ItemHomeRecommentdTagBinding.inflate(from, container, false) + view.icon.load(list.getOrNull(position)?.icon?:"") + tabViewList.add(view.root) + if (position == list.lastIndex) { + view.root.setMargin(end = 35) + } + return@setViews view.root + } + + binding.tabLayout.setOnTabClickListener{pos,view-> + selectTabView(pos) + } + + binding.tabLayout.post { + changePage() + this@HomeRecommendFragment.binding.tabLayout.scrollToTab(mPosition, 0f) + } + + //显示更多按钮 + binding.tabLayoutMore.setVis(list.size > 6) + binding.tabLayoutMarks.setVis(list.size > 6) + + } + + private fun selectTabView(pos:Int) { + if (mPosition == pos) return + //取消选中 + tabViewList?.getOrNull(mPosition)?.let { oldView-> + val tabView = ItemHomeRecommentdTagBinding.bind(oldView) + tabView.bg.changeStrikeColor("#ffffff".toColor()) + } + + mPosition = pos + changePage() + } + + private fun transformTabList(list: List): List { + return list + } + + private fun loadTabList(list: List) { + // 预防脏数据导致fragment复用问题 + val newList = list.distinctBy { + it.id + } + val currentListId = tabList.joinToString { it.id.toString() } + val newListId = newList.joinToString { it.id.toString() } + if (currentListId == newListId) { + return + } + tabList.clear() + tabList.addAll(newList) + fragmentArray.clear() + if (tabList.isVerify()) { + tabList.forEach { + fragmentArray.put(it.id,HomeTabRoomFragment.newInstance(it.id)) + } + } + + resetTabIndicator(tabList) + } + + private fun changePage() { + val tab = tabList.getOrNull(mPosition) ?: return + val showFragment = fragmentArray.get(tab.id) + if (showFragment === tempFragment) return + + val transaction: FragmentTransaction = childFragmentManager.beginTransaction() + if (!showFragment.isAdded) { + transaction.add(R.id.view_pager, showFragment, null) + } + transaction.show(showFragment) + if (tempFragment != null) { + transaction.hide(tempFragment!!) + } + tempFragment = showFragment + if (!isDetached) { + transaction.commitNowAllowingStateLoss() + } + + //选中 + tabViewList?.getOrNull(mPosition)?.let { oldView-> + val tabView = ItemHomeRecommentdTagBinding.bind(oldView) + tabView.bg.changeStrikeColor("#ff8c03".toColor()) + } + } + + override fun onDestroyView() { + super.onDestroyView() + tabList.clear() + } + + private fun onVisibleChanged(isVisible: Boolean, isFirstVisible: Boolean) { + if (isVisible) { + if (!isFirstVisible) { + if (homeViewModel.homeResourceLiveData.value == null) { + homeViewModel.getHomeResourceInfo() + } + homeViewModel.getHomeRankList() + } + binding.viewFlipper.startFlipping() + } else { + binding.viewFlipper.stopFlipping() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/fragment/HomeRoomCollectListFragment.kt b/app/src/main/java/com/chwl/app/home/fragment/HomeRoomCollectListFragment.kt new file mode 100644 index 0000000..d302f12 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/fragment/HomeRoomCollectListFragment.kt @@ -0,0 +1,102 @@ +package com.chwl.app.home.fragment + +import android.view.View +import androidx.fragment.app.viewModels +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chwl.app.R +import com.chwl.app.avroom.activity.AVRoomActivity +import com.chwl.app.base.BaseViewBindingFragment +import com.chwl.app.common.EmptyViewHelper +import com.chwl.app.databinding.HomeTabRoomFragmentBinding +import com.chwl.app.home.HomeMeViewModel +import com.chwl.app.home.adapter.HomeRoomAdapter +import com.chwl.app.support.FragmentVisibleStateHelper +import com.chwl.app.ui.utils.RVDelegate +import com.chwl.core.home.bean.HomeRoomInfo + +/** + * 收藏 + */ +class HomeRoomCollectListFragment : BaseViewBindingFragment(), + SwipeRefreshLayout.OnRefreshListener { + + private lateinit var adapter: HomeRoomAdapter + + private lateinit var rvDelegate: RVDelegate + + private val viewModel: HomeMeViewModel by viewModels() + + private var pageNum = 1 + private val pageSize = 50 + + companion object { + fun newInstance(): HomeRoomCollectListFragment { + return HomeRoomCollectListFragment() + } + } + + override fun init() { + initListView() + FragmentVisibleStateHelper(this).apply { + start { + if (it && !isFirstVisible) { + loadData(true) + } + } + } + } + + private fun initListView() { + adapter = HomeRoomAdapter(arrayListOf()) + adapter.onItemClickListener = + BaseQuickAdapter.OnItemClickListener { _: BaseQuickAdapter<*, *>?, _: View?, position: Int -> + val homePlayInfo: HomeRoomInfo? = adapter.getItem(position) + if (homePlayInfo != null) { + //首页_房间派对 + AVRoomActivity.start(mContext, homePlayInfo.uid) + } + } + rvDelegate = RVDelegate.Builder() + .setPageSize(pageSize) + .setAdapter(adapter) + .setRecyclerView(binding.mRecyclerRoom) + .setEmptyView( + EmptyViewHelper.createEmptyTextViewHeight( + context, + getString(R.string.data_empty) + ) + ) + .setLayoutManager(LinearLayoutManager(mContext)) + .build() + + adapter.setOnLoadMoreListener({ + loadData(false) + }, binding.mRecyclerRoom) + + viewModel.collectRoomListLiveData.observe(this) { + rvDelegate.loadData(it) + } + } + + override fun onLazyLoad() { + super.onLazyLoad() + loadData(true) + } + + private fun loadData(isRefresh: Boolean) { + if (isRefresh) { + pageNum = 1 + } else { + pageNum++ + } + viewModel.getHomeCollectList(pageNum, pageSize) + } + + override fun onRefresh() { + if (isResumed) { + loadData(true) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/fragment/HomeRoomHistoryListFragment.kt b/app/src/main/java/com/chwl/app/home/fragment/HomeRoomHistoryListFragment.kt new file mode 100644 index 0000000..69181ab --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/fragment/HomeRoomHistoryListFragment.kt @@ -0,0 +1,102 @@ +package com.chwl.app.home.fragment + +import android.view.View +import androidx.fragment.app.viewModels +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chwl.app.R +import com.chwl.app.avroom.activity.AVRoomActivity +import com.chwl.app.base.BaseViewBindingFragment +import com.chwl.app.common.EmptyViewHelper +import com.chwl.app.databinding.HomeTabRoomFragmentBinding +import com.chwl.app.home.HomeMeViewModel +import com.chwl.app.home.adapter.HomeRoomAdapter +import com.chwl.app.support.FragmentVisibleStateHelper +import com.chwl.app.ui.utils.RVDelegate +import com.chwl.core.home.bean.HomeRoomInfo + +/** + * 最近访问记录 + */ +class HomeRoomHistoryListFragment : BaseViewBindingFragment(), + SwipeRefreshLayout.OnRefreshListener { + + private lateinit var adapter: HomeRoomAdapter + + private lateinit var rvDelegate: RVDelegate + + private val viewModel: HomeMeViewModel by viewModels() + + private var pageNum = 1 + private val pageSize = 50 + + companion object { + fun newInstance(): HomeRoomHistoryListFragment { + return HomeRoomHistoryListFragment() + } + } + + override fun init() { + initListView() + FragmentVisibleStateHelper(this).apply { + start { + if (it && !isFirstVisible) { + loadData(true) + } + } + } + } + + private fun initListView() { + adapter = HomeRoomAdapter(arrayListOf()) + adapter.onItemClickListener = + BaseQuickAdapter.OnItemClickListener { _: BaseQuickAdapter<*, *>?, _: View?, position: Int -> + val homePlayInfo: HomeRoomInfo? = adapter.getItem(position) + if (homePlayInfo != null) { + //首页_房间派对 + AVRoomActivity.start(mContext, homePlayInfo.uid) + } + } + rvDelegate = RVDelegate.Builder() + .setPageSize(pageSize) + .setAdapter(adapter) + .setRecyclerView(binding.mRecyclerRoom) + .setEmptyView( + EmptyViewHelper.createEmptyTextViewHeight( + context, + getString(R.string.data_empty) + ) + ) + .setLayoutManager(LinearLayoutManager(mContext)) + .build() + + adapter.setOnLoadMoreListener({ + loadData(false) + }, binding.mRecyclerRoom) + + viewModel.historyRoomListLiveData.observe(this) { + rvDelegate.loadData(it) + } + } + + override fun onLazyLoad() { + super.onLazyLoad() + loadData(true) + } + + private fun loadData(isRefresh: Boolean) { + if (isRefresh) { + pageNum = 1 + } else { + pageNum++ + } + viewModel.getHomeHistoryList(pageNum, pageSize) + } + + override fun onRefresh() { + if (isResumed) { + loadData(true) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/fragment/HomeTabRoomFragment.kt b/app/src/main/java/com/chwl/app/home/fragment/HomeTabRoomFragment.kt new file mode 100644 index 0000000..090a9ff --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/fragment/HomeTabRoomFragment.kt @@ -0,0 +1,156 @@ +package com.chwl.app.home.fragment + +import android.os.Bundle +import android.view.View +import androidx.fragment.app.viewModels +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chwl.app.R +import com.chwl.app.avroom.activity.AVRoomActivity +import com.chwl.app.base.BaseViewBindingFragment +import com.chwl.app.common.EmptyViewHelper +import com.chwl.app.databinding.HomeTabRoomFragmentBinding +import com.chwl.app.home.HomeViewModel +import com.chwl.app.home.adapter.HomeRoomAdapter +import com.chwl.app.support.FragmentVisibleStateHelper +import com.chwl.app.ui.utils.RVDelegate +import com.chwl.core.home.bean.HomeRoomInfo +import com.chwl.library.common.util.isVerify +import com.chwl.library.utils.ListUtils + +/** + * 首页-房间列表 + */ +class HomeTabRoomFragment : BaseViewBindingFragment(), + SwipeRefreshLayout.OnRefreshListener { + + private lateinit var adapter: HomeRoomAdapter + + private lateinit var rvDelegate: RVDelegate + + private val homeViewModel: HomeViewModel by viewModels() + + var autoRefreshOnVisible = false + var isLoadBanner = false + + private var pageNum = 1 + private val pageSize = 50 + private var tabId: Int? = null + + companion object { + fun newInstance(tabId: Int): HomeTabRoomFragment { + return HomeTabRoomFragment().apply { + arguments = Bundle().apply { + putInt("tabId", tabId) + } + } + } + } + + override fun init() { + tabId = arguments?.getInt("tabId") + initListView() + if (autoRefreshOnVisible) { + FragmentVisibleStateHelper(this).apply { + start { + if (it && !isFirstVisible) { + loadData(true) + } + } + } + } + } + + private fun initListView() { + adapter = HomeRoomAdapter(arrayListOf()) + adapter.onItemClickListener = + BaseQuickAdapter.OnItemClickListener { _: BaseQuickAdapter<*, *>?, _: View?, position: Int -> + val homePlayInfo: HomeRoomInfo? = adapter.getItem(position) + if (homePlayInfo != null) { + //首页_房间派对 + AVRoomActivity.start(mContext, homePlayInfo.uid) + } + } + rvDelegate = RVDelegate.Builder() + .setPageSize(pageSize) + .setAdapter(adapter) + .setRecyclerView(binding.mRecyclerRoom) + .setEmptyView( + EmptyViewHelper.createEmptyTextViewHeight( + context, + getString(R.string.data_empty) + ) + ) + .setLayoutManager(LinearLayoutManager(mContext)) + .build() + + + adapter.setOnLoadMoreListener({ + loadData(false) + }, binding.mRecyclerRoom) + + + homeViewModel.tabRoomListLiveData.observe(this) { + if (pageNum == 1){ + isLoadBanner = true + homeViewModel.getSecondBannerInfo() + } + rvDelegate.loadData(it) + } + + + homeViewModel.secondBannerLiveData.observe(this){ + it?.let { + if (ListUtils.isListEmpty(it)) { + isLoadBanner = false + return@let + } + + var newData = mutableListOf() + if (adapter?.data != null) { + newData = adapter.data.filter { !it.isBanner }.toMutableList() + } + + val homeRoomInfo = HomeRoomInfo().apply { + isBanner = true + bannerVoList = it + } + + if (newData.size >= 6) { + newData.add(5,homeRoomInfo) + } else { + newData.add(homeRoomInfo) + } + adapter.setNewData(newData) + isLoadBanner = false + return@let + + } + isLoadBanner = false + } + + + } + + override fun onLazyLoad() { + super.onLazyLoad() + loadData(true) + } + + private fun loadData(isRefresh: Boolean) { + if (isLoadBanner) return + if (isRefresh) { + pageNum = 1 + } else { + pageNum++ + } + homeViewModel.getTabRoomList(tabId ?: 0, pageNum, pageSize) + } + + override fun onRefresh() { + if (isResumed) { + loadData(true) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/fragment/HomeWithMeFragment.kt b/app/src/main/java/com/chwl/app/home/fragment/HomeWithMeFragment.kt new file mode 100644 index 0000000..8600921 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/fragment/HomeWithMeFragment.kt @@ -0,0 +1,119 @@ +package com.chwl.app.home.fragment + +import androidx.core.view.isGone +import androidx.core.view.isVisible +import androidx.fragment.app.activityViewModels +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout +import com.chwl.app.R +import com.chwl.app.avroom.adapter.CommonVPAdapter +import com.chwl.app.base.BaseViewBindingFragment +import com.chwl.app.databinding.HomeMeFragmentBinding +import com.chwl.app.home.HomeMeViewModel +import com.chwl.app.home.helper.OpenRoomHelper +import com.chwl.app.support.FragmentVisibleStateHelper +import com.chwl.app.ui.user.adapter.HomeRecommendIndicatorAdapter +import com.chwl.app.ui.utils.load +import com.chwl.app.ui.utils.loadAvatar +import com.chwl.app.ui.widget.magicindicator.ViewPagerHelper +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.CommonNavigator +import com.chwl.core.home.bean.HomeRoomCardInfo +import com.chwl.core.home.bean.MicUsersBean +import com.chwl.library.common.util.isVerify +import com.chwl.library.common.util.setVis +import com.example.lib_utils.ktx.singleClick + +/** +首页-我的 + */ +class HomeWithMeFragment : BaseViewBindingFragment() { + + private val viewModel: HomeMeViewModel by activityViewModels() + + override fun init() { + initListener() + initTab() + initObserve() + FragmentVisibleStateHelper(this).start { + if (it) { + viewModel.getMyRoomInfo() + } + } + } + + private fun initListener() { + binding.refreshLayout.setOnRefreshListener { + it.finishRefresh() + viewModel.getMyRoomInfo() + childFragmentManager.fragments.forEach { + (it as? SwipeRefreshLayout.OnRefreshListener)?.onRefresh() + } + } + binding.refreshLayout.setEnableLoadMore(false) + binding.refreshLayout.setEnableOverScrollBounce(false) + binding.layoutRoomCard.singleClick { + OpenRoomHelper.openRoom(baseActivity) + } + } + + private fun initTab() { + val tabList = listOf(getString(R.string.lately), getString(R.string.collect)) + val fragmentList = listOf(HomeRoomHistoryListFragment(), HomeRoomCollectListFragment()) + val commonNavigator = CommonNavigator(context) + val magicIndicatorAdapter = HomeRecommendIndicatorAdapter( + context, + tabList + ) + magicIndicatorAdapter.setOnItemSelectListener { position, _ -> + binding.viewPager.currentItem = position + } + commonNavigator.adapter = magicIndicatorAdapter + binding.magicIndicator.navigator = commonNavigator + binding.magicIndicator.onPageSelected(binding.viewPager.currentItem) + binding.viewPager.offscreenPageLimit = fragmentList.size + binding.viewPager.adapter = CommonVPAdapter( + childFragmentManager, + lifecycle, + fragmentList + ) + ViewPagerHelper.bind(binding.magicIndicator, binding.viewPager) + } + + private fun initObserve() { + viewModel.roomInfoLiveData.observe(this) { + updateRoomInfo(it) + } + } + + private fun updateRoomInfo(roomInfo: HomeRoomCardInfo?) { + binding.tvRoomName.text = roomInfo?.title + binding.tvRoomTopic.text = roomInfo?.roomDesc + binding.ivRoomCover.load(roomInfo?.avatar ?: "") + binding.tvOnlineNumber.text = roomInfo?.onlineNum?.toString() ?: "0" + if (roomInfo?.regionFlag.isVerify()) { + binding.flag.load(roomInfo?.regionFlag) + } + binding.flag.setVis(roomInfo?.regionFlag.isVerify()) + loadRoomUsers(roomInfo?.micUsers) + } + + private fun loadRoomUsers(list: List?) { + val avatarViewList = arrayOf( + binding.ivRoomUser0, + binding.ivRoomUser1, + binding.ivRoomUser2, + binding.ivRoomUser3, + binding.ivRoomUser4 + ) + avatarViewList.forEachIndexed { index, imageView -> + val item = list?.getOrNull(index) + if (item == null) { + imageView.setImageDrawable(null) + imageView.isGone = true + } else { + imageView.loadAvatar(item.avatar) + imageView.isVisible = true + } + } + binding.layoutRoomUserList.isGone = list.isNullOrEmpty() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/fragment/MeFragment.kt b/app/src/main/java/com/chwl/app/home/fragment/MeFragment.kt new file mode 100644 index 0000000..82efcd1 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/fragment/MeFragment.kt @@ -0,0 +1,424 @@ +package com.chwl.app.home.fragment + +import android.annotation.SuppressLint +import android.content.ClipData +import android.content.ClipboardManager +import android.content.Context +import android.content.Intent +import android.text.TextUtils +import android.view.View +import android.view.View.OnLongClickListener +import androidx.databinding.DataBindingUtil +import androidx.fragment.app.activityViewModels +import androidx.fragment.app.viewModels +import com.chwl.app.R +import com.chwl.app.UIHelper +import com.chwl.app.application.IReportConstants +import com.chwl.app.application.ReportManager +import com.chwl.app.avroom.activity.AVRoomActivity +import com.chwl.app.avroom.dialog.RoomBgSetDialog +import com.chwl.app.base.BaseActivity +import com.chwl.app.base.BaseFragment +import com.chwl.app.databinding.FragmentMeBinding +import com.chwl.app.home.HomeViewModel +import com.chwl.app.home.MeViewModel +import com.chwl.app.home.activity.AssociationActivity +import com.chwl.app.home.activity.VisitorListActivity +import com.chwl.app.home.adapter.MeCenterAdapter +import com.chwl.app.home.helper.OpenRoomHelper +import com.chwl.app.module_hall.HallDataManager +import com.chwl.app.module_hall.hall.activity.ModuleClanActivity +import com.chwl.app.module_hall.hall.activity.ModuleHallActivity +import com.chwl.app.support.FragmentVisibleStateHelper +import com.chwl.app.ui.im.RouterHandler +import com.chwl.app.ui.relation.FansListActivity +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.app.ui.wallet.WalletActivity +import com.chwl.app.ui.webview.CommonWebViewActivity +import com.chwl.app.utils.HomeUIManager +import com.chwl.app.view.GenderAgeTextView +import com.chwl.app.vip.VipCenterActivity +import com.chwl.app.vip.VipViewModel +import com.chwl.core.auth.AuthModel +import com.chwl.core.im.custom.bean.RouterType +import com.chwl.core.initial.InitialModel +import com.chwl.core.level.UserLevelVo +import com.chwl.core.manager.IMNetEaseManager +import com.chwl.core.manager.RelationShipEvent +import com.chwl.core.module_hall.hall.bean.ClanAndHallInfo +import com.chwl.core.module_hall.hall.bean.H5FamilyInfo +import com.chwl.core.module_hall.hall.bean.UserClanInfo +import com.chwl.core.pay.PayModel +import com.chwl.core.pay.event.GetWalletInfoEvent +import com.chwl.core.pay.event.UpdateWalletInfoEvent +import com.chwl.core.room.bean.MeCenterInfo +import com.chwl.core.room.bean.RoomInfo +import com.chwl.core.user.UserModel +import com.chwl.core.user.bean.UserInfo +import com.chwl.core.user.event.LoginUserInfoUpdateEvent +import com.chwl.core.utils.CoreLogger +import com.chwl.core.vip.bean.VipInfo +import com.chwl.library.common.util.setVis +import com.example.lib_utils.ktx.singleClick +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode + +/** + * @description: 我的 界面 + * @author: hewenhao + * @date: 2018/9/4 16:53 + */ +class MeFragment : BaseFragment(), View.OnClickListener { + + companion object { + const val TAG = "MeFragment" + } + + private val mCenterAdapter = MeCenterAdapter() + + private var mUserInfo: UserInfo? = null + private lateinit var mBinding: FragmentMeBinding + private val meViewModel: MeViewModel by viewModels() + private val homeViewModel: HomeViewModel by activityViewModels() + private val vipViewModel: VipViewModel by viewModels() + + override fun getRootLayoutId(): Int { + return R.layout.fragment_me + } + + override fun onSetListener() { + mBinding = DataBindingUtil.bind(mView)!! + mBinding.click = this + } + + override fun onDestroy() { + super.onDestroy() + EventBus.getDefault().unregister(this) + } + + @SuppressLint("CheckResult", "SetTextI18n") + override fun initiate() { + HomeUIManager.setHomeUI(mBinding.root) + EventBus.getDefault().register(this) + + mBinding.rvMenu.adapter = mCenterAdapter + + mCenterAdapter.setOnItemClickListener { adapter, view, position -> + mCenterAdapter.getItem(position)?.let { + if (it.skipType == RouterType.MY_GUILD) { + mBinding.ivGuild.performClick() + } else { + RouterHandler.handle(mContext, it.skipType ?: -1, it.centerUrl) + } + } + } + + if (AuthModel.get().isLogin) { + vipViewModel.getVipPageInfo() + } + + + mCompositeDisposable.add( + IMNetEaseManager.get() + .relationShipEventObservable + .subscribe { e: RelationShipEvent -> + onGetRelationShipEvent(e) + } + ) + + meViewModel.menuListLiveData.observe(viewLifecycleOwner) { + setCenterData(it) + } + + homeViewModel.pickRoomLiveData.observe(viewLifecycleOwner) { + it?.let { + AVRoomActivity.start(mContext, it.uid) + } + } + + homeViewModel.openGameRoomLiveData.observe(viewLifecycleOwner) { + it?.let { + OpenRoomHelper.openRoom(mContext as BaseActivity, RoomInfo.ROOMTYPE_GAME, it) + } + } + + vipViewModel.myVipInfoLiveData.observe(viewLifecycleOwner) { + loadVipInfo(it) + } + + FragmentVisibleStateHelper(this).apply { + start { + onVisibleChanged(it, isFirstVisible) + } + } + } + + private fun setCenterData(list: List?) { + if (list.isNullOrEmpty()) { + mBinding.layoutMenu.visibility = View.GONE + return + } + mBinding.layoutMenu.visibility = View.VISIBLE + mCenterAdapter.updateData(list) + } + + private fun onGetRelationShipEvent(event: RelationShipEvent) { + if (event.event == RelationShipEvent.EVENT_FRIEND_UPDATE) { + requestUpdateUserInfo() + } + } + + override fun onResume() { + super.onResume() + setUserData() + if (mUserInfo?.isReview == true) { + requestUpdateUserInfo() + } + } + + @SuppressLint("SetTextI18n") + private fun setUserData() { + mUserInfo = UserModel.get().cacheLoginUserInfo + mUserInfo?.let { + if (it.gender == GenderAgeTextView.GENDER_MALE) { + mBinding.ivGender.setImageResource(R.drawable.base_ic_male) + } else { + mBinding.ivGender.setImageResource(R.drawable.base_ic_female) + } + mBinding.userInfo = mUserInfo + mBinding.tvUserId.text = String.format( + getString(R.string.text_user_id), it.erbanNo.toString() + ) + mBinding.tvUserId.setOnLongClickListener(OnLongClickListener { _ -> + copyName(it.erbanNo.toString()) + return@OnLongClickListener true + }) + mBinding.ivCopy.setOnClickListener { _ -> + copyName(it.erbanNo.toString()) + } + setUserLevel(it.userLevelVo) + setWalletInfo() + setDonation(it) + } + } + + + + private fun copyName(erbanNo: String) { + try { + val cm = + context?.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager + cm.setPrimaryClip(ClipData.newPlainText("text", erbanNo)) + toast(getString(R.string.have_copy)) + } catch (e: Exception) { + CoreLogger.info("copyText", e.toString()) + toast(e.toString()) + } + } + + private fun setUserLevel(userLevelVo: UserLevelVo?) { + mBinding.ivUserCharm.visibility = View.GONE + mBinding.ivUserLevel.visibility = View.GONE + if (userLevelVo != null) { + val userLevelUrl = userLevelVo.getExperUrl() + val userCharmUrl = userLevelVo.getCharmUrl() + if (!TextUtils.isEmpty(userLevelUrl)) { + mBinding.ivUserLevel.visibility = View.VISIBLE + ImageLoadUtils.loadImage(mContext, userLevelUrl, mBinding.ivUserLevel) + } + if (!TextUtils.isEmpty(userCharmUrl)) { + mBinding.ivUserCharm.visibility = View.VISIBLE + ImageLoadUtils.loadImage(mContext, userCharmUrl, mBinding.ivUserCharm) + } + } + } + + private fun setWalletInfo() { + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onLoginUserInfoUpdateEvent(event: LoginUserInfoUpdateEvent?) { + setUserData() + vipViewModel.getVipPageInfo() + } + + @SuppressLint("CheckResult") + private fun reloadClanInfo() { + if (!AuthModel.get().isLogin) return + HallDataManager.get().requestUserClanInfo(AuthModel.get().currentUid) + .compose(bindToLifecycle()) + .subscribe { info: UserClanInfo? -> + val clanHallInfo = info?.asClanHall() + if (clanHallInfo != null) { + this.updateHallInfo(clanHallInfo) + } else { + val familyInfo = info?.asFamily() + if (familyInfo != null) { + this.updateHallInfo(familyInfo) + } else { + this.updateHallInfo(null) + } + } + } + + UserModel.get().userMineInfo.compose(bindToLifecycle()).doOnSuccess { + mBinding.tvUserFriendText.text = it.friendCount.toString() + mBinding.tvUserVisitorText.text = it.browseNum.toString() + mBinding.tvUserVisitorUnRead.text = "+${it.browseNumTip}" + mBinding.tvUserVisitorUnRead.setVis(it.browseNumTip != 0) + }.subscribe() + } + + private fun updateHallInfo(clanAndHallInfo: ClanAndHallInfo?) { + if ((clanAndHallInfo?.clan?.elderUid ?: 0L) > 0) { + mBinding.tvGuild.setText(R.string.me_my_guild) + mBinding.ivGuild.singleClick { + ModuleClanActivity.start(context, clanAndHallInfo?.clan?.elderUid ?: 0L) + } + } else if ((clanAndHallInfo?.hall?.ownerUid ?: 0L) > 0) { + mBinding.tvGuild.setText(R.string.me_my_guild) + mBinding.ivGuild.singleClick { + ModuleHallActivity.start( + context, + clanAndHallInfo?.hall?.hallId ?: 0L, + clanAndHallInfo?.hall?.ownerUid ?: 0L + ) + } + } else { + mBinding.tvGuild.setText(R.string.me_join_guild) + mBinding.ivGuild.singleClick { + //公會周榜 + context?.let { it1 -> AssociationActivity.start(it1) } + } + } + } + + private fun setDonation(userInfo: UserInfo) { + val initInfo = InitialModel.get().cacheInitInfo + + val diamondList = initInfo?.giveDiamondErbanNoList + val giftList = initInfo?.giveGiftErbanNoList + + val levelSep = userInfo.userLevelVo.experLevelSeq + + if (diamondList?.contains(userInfo.erbanNo) == true + || giftList?.contains(userInfo.erbanNo) == true + || levelSep >= (initInfo?.giveDiamondExperLevel ?: 0) + || levelSep >= (initInfo?.giveGiftExperLevel ?: 0) + ) { + meViewModel.updateDonationMenuVisible(true) + } else { + meViewModel.updateDonationMenuVisible(false) + } + } + + + + private fun updateHallInfo(familyInfo: H5FamilyInfo) { + if (familyInfo.familyId != null && familyInfo.familyId != 0L) { + mBinding.tvGuild.setText(R.string.me_my_guild) + mBinding.ivGuild.singleClick { + CommonWebViewActivity.start(context, familyInfo.getFullMyFamilyUrl()) + } + } else { + mBinding.tvGuild.setText(R.string.me_join_guild) + mBinding.ivGuild.singleClick { + CommonWebViewActivity.start(context, familyInfo.getFullFamilyListUrl()) + } + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onWalletInfoUpdate(event: UpdateWalletInfoEvent?) { + setWalletInfo() + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onGetWalletInfoEvent(event: GetWalletInfoEvent?) { + setWalletInfo() + } + + private fun requestUpdateUserInfo() { + UserModel.get().updateCurrentUserInfo().subscribe() + } + + override fun onClick(v: View) { + when (v.id) { + R.id.iv_user_head, R.id.rl_user_info -> { + mUserInfo?.let { UIHelper.showUserInfoAct(mContext, it.uid) } + } +// +// R.id.iv_edit -> +// mUserInfo?.let { UIHelper.showUserInfoModifyAct(mContext, it.uid) } + + R.id.ll_user_attentions -> { + FansListActivity.start(mContext,FansListActivity.TYPE_ATTENTION) + } + + R.id.ll_user_fans -> { + FansListActivity.start(mContext,FansListActivity.TYPE_FANS) + } + + R.id.ll_user_friend -> { + FansListActivity.start(mContext,FansListActivity.TYPE_FRIEND) + } + + R.id.ll_user_visitor -> { + VisitorListActivity.start(mContext); + } + + R.id.iv_wallet -> { + //进入充值页面埋点 + val goldWalletInfo = PayModel.get().currentWalletInfo + val map = HashMap(5) + map[IReportConstants.PAYPAGE_TYPE] = IReportConstants.FOUR + if (goldWalletInfo != null) { + map[IReportConstants.ACCOUNT_BALANCE] = goldWalletInfo.diamondNum + } + map[IReportConstants.MODULE] = IReportConstants.MOLISTAR_PAY + ReportManager.get().reportEvent(IReportConstants.PAYPAGE_SHOW, map) + + WalletActivity.start(requireContext()) + } + + R.id.iv_vip -> { + VipCenterActivity.start(mContext) + //进入贵族中心埋点 + val goldWalletInfo = PayModel.get().currentWalletInfo + val map = HashMap(5) + map[IReportConstants.PAYPAGE_TYPE] = IReportConstants.FIVE + if (goldWalletInfo != null) { + map[IReportConstants.ACCOUNT_BALANCE] = goldWalletInfo.diamondNum + } + map[IReportConstants.MODULE] = IReportConstants.MOLISTAR_PAY + ReportManager.get().reportEvent(IReportConstants.PAYPAGE_SHOW, map) + } + + R.id.tv_user_name -> { + + } + + else -> {} + } + } + + private fun loadVipInfo(data: VipInfo?) { + } + + private fun onVisibleChanged(isVisible: Boolean, isFirstVisible: Boolean) { + if (isVisible) { + reloadClanInfo() + meViewModel.requestMenuList() + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + parentFragmentManager.fragments.forEach { + if (it is RoomBgSetDialog) { + it.onActivityResult(requestCode, resultCode, data) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/helper/AutoScrollTask.kt b/app/src/main/java/com/chwl/app/home/helper/AutoScrollTask.kt new file mode 100644 index 0000000..bed2ab5 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/helper/AutoScrollTask.kt @@ -0,0 +1,23 @@ +package com.chwl.app.home.helper + +import android.os.Handler +import android.os.Looper + +class AutoScrollTask(val timeInterval: Long, call: () -> Unit) { + private val handler = Handler(Looper.getMainLooper()) + private val autoRunnable = object : Runnable { + override fun run() { + call.invoke() + handler.postDelayed(this, timeInterval) + } + } + + fun start() { + handler.removeCallbacks(autoRunnable) + handler.postDelayed(autoRunnable, 0) + } + + fun stop() { + handler.removeCallbacks(autoRunnable) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/helper/BannerHelper.kt b/app/src/main/java/com/chwl/app/home/helper/BannerHelper.kt new file mode 100644 index 0000000..e648fe0 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/helper/BannerHelper.kt @@ -0,0 +1,80 @@ +package com.chwl.app.home.helper + +import android.graphics.Color +import android.graphics.drawable.Drawable +import android.graphics.drawable.GradientDrawable +import android.view.View +import com.netease.nim.uikit.common.util.sys.ScreenUtil +import com.chwl.app.R +import com.chwl.app.home.adapter.BannerAdapter +import com.chwl.app.ui.widget.rollviewpager.RollPagerView +import com.chwl.app.ui.widget.rollviewpager.Util +import com.chwl.app.ui.widget.rollviewpager.hintview.ColorPointHintView +import com.chwl.core.home.bean.BannerInfo +import com.chwl.library.utils.ListUtils + +class BannerHelper { + companion object { + + fun setBanner( + rollView: RollPagerView, + bannerList: List?, + onItemClickListener: BannerAdapter.OnItemClickListener? = null + ) { + + if (ListUtils.isListEmpty(bannerList)) { + rollView.visibility = View.GONE + return + } + rollView.visibility = View.VISIBLE + if (rollView.adapter == null) { + rollView.setHintView(object : ColorPointHintView( + rollView.context, Color.WHITE, rollView.context.resources.getColor( + R.color.color_66FFFFFF + ) + ) { + override fun makeFocusDrawable(): Drawable { + val dotFocus = GradientDrawable() + dotFocus.setColor(Color.WHITE) + dotFocus.cornerRadius = Util.dip2px( + context, 2f + ).toFloat() + dotFocus.setSize( + Util.dip2px(context, 9f), Util.dip2px( + context, 4f + ) + ) + return dotFocus + } + + override fun makeNormalDrawable(): Drawable { + val dotNormal = GradientDrawable() + dotNormal.setColor(rollView.context.resources.getColor(R.color.color_66FFFFFF)) + dotNormal.cornerRadius = Util.dip2px( + context, 2f + ).toFloat() + dotNormal.setSize( + Util.dip2px(context, 4f), Util.dip2px( + context, 4f + ) + ) + return dotNormal + } + }) + val bannerAdapter = BannerAdapter(bannerList, rollView.context) + bannerAdapter.setRoundingRadius(ScreenUtil.dip2px(8f)) + bannerAdapter.setOnItemClickListener(onItemClickListener) + rollView.adapter = bannerAdapter + rollView.setPlayDelay(3000) + //设置透明度 + rollView.setAnimationDurtion(500) + } + + (rollView.adapter as? BannerAdapter)?.let { + it.setBannerInfoList(bannerList) + it.notifyDataSetChanged() + } + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/helper/EventCenterUtil.kt b/app/src/main/java/com/chwl/app/home/helper/EventCenterUtil.kt new file mode 100644 index 0000000..6d5a940 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/helper/EventCenterUtil.kt @@ -0,0 +1,32 @@ +package com.chwl.app.home.helper + +import com.chwl.app.R +import com.example.lib_utils.ktx.getString + +class EventCenterUtil { + + companion object{ + + fun formatDuration(minutes: Long): String { + val days = minutes / (24 * 60) + val hours = (minutes % (24 * 60)) / 60 + val remainingMinutes = minutes % 60 + + return buildString { + if (days > 0) { + append(R.string.sDays.getString(days)+" ") + } + if (hours > 0) { + append(R.string.s_hours.getString(hours)+" ") + } + if (remainingMinutes > 0 || (days == 0L && hours == 0L)) { // 确保当没有天和小时的时候也能显示分钟 + append(R.string.s_minutes.getString(remainingMinutes)) + } + }.trim() + } + + } + + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/helper/LoadPageDataHelper.java b/app/src/main/java/com/chwl/app/home/helper/LoadPageDataHelper.java new file mode 100644 index 0000000..dd0e9d4 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/helper/LoadPageDataHelper.java @@ -0,0 +1,61 @@ +package com.chwl.app.home.helper; + +import com.chwl.app.R; +import com.chwl.core.Constants; +import com.chwl.library.utils.ResUtil; + +import io.reactivex.Single; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.functions.Action; + +/** + * @author jack + * @Description + * @Date 2018/10/31 + */ +public class LoadPageDataHelper { + private int curPage = Constants.PAGE_START; + private boolean loading = false; + private LoadData loadData; + + public LoadPageDataHelper(LoadData loadData) { + this.loadData = loadData; + } + + public Single refreshData() { + this.curPage = Constants.PAGE_START; + return internalLoadData(this.curPage); + } + + public Single loadMoreData() { + return internalLoadData(this.curPage); + } + + private Single internalLoadData(int targetPage) { + if (loading) { + return Single.error(new Throwable(ResUtil.getString(R.string.home_helper_loadpagedatahelper_01))); + } + loading = true; + return loadData.loadData(targetPage) + .observeOn(AndroidSchedulers.mainThread()) + .doAfterTerminate(new Action() { + @Override + public void run() throws Exception { + curPage++; + loading = false; + } + }); + } + + public interface LoadData { + Single loadData(int curPage); + } + + public void setCurPage(int newPage) { + this.curPage = newPage; + } + + public boolean isLoading() { + return loading; + } +} diff --git a/app/src/main/java/com/chwl/app/home/helper/OpenRoomHelper.java b/app/src/main/java/com/chwl/app/home/helper/OpenRoomHelper.java new file mode 100644 index 0000000..95490af --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/helper/OpenRoomHelper.java @@ -0,0 +1,245 @@ +package com.chwl.app.home.helper; + +import static com.chwl.core.certification.CertificationModel.CER_TYPE_FORCE; +import static com.chwl.core.certification.CertificationModel.CER_TYPE_GUIDE; +import static com.chwl.core.certification.CertificationModel.CER_TYPE_NONE; + +import android.annotation.SuppressLint; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.TextUtils; +import android.text.style.ForegroundColorSpan; + +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; + +import com.chwl.app.MainActivity; +import com.chwl.app.R; +import com.chwl.app.avroom.activity.AVRoomActivity; +import com.chwl.app.avroom.dialog.CreateRoomDialog; +import com.chwl.app.base.BaseActivity; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.app.ui.webview.CommonWebViewActivity; +import com.chwl.core.UriProvider; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.certification.CertificationModel; +import com.chwl.core.patriarch.exception.PmRoomLimitException; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.core.room.model.AvRoomModel; +import com.chwl.core.room.model.RoomSettingModel; +import com.chwl.core.user.UserModel; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.core.utils.net.BeanObserver; +import com.chwl.core.utils.net.DontWarnObserver; +import com.chwl.core.utils.net.RxHelper; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; + +import io.reactivex.Single; + +public class OpenRoomHelper { + + public static void openRoom(BaseActivity activity) { + openRoom(activity, RoomInfo.ROOMTYPE_DEFAULT, 0); + } + + public static void openHomePartyRoom(BaseActivity activity) { + openRoom(activity, RoomInfo.ROOMTYPE_HOME_PARTY, 0); + } + + public static void openRoom(BaseActivity activity, int type, long gameId) { + UserInfo userInfo = UserModel.get().getCacheLoginUserInfo(); + if (userInfo != null && !userInfo.isCertified()) { + switch (CertificationModel.get().getCertificationType()) { + default: + case CER_TYPE_NONE: + requestOpenRoom(activity, type, gameId); + break; + case CER_TYPE_FORCE: + activity.getDialogManager().showTipsDialog(getCertificationTips(activity), + activity.getString(R.string.go_to_certification), + new DialogManager.AbsOkDialogListener() { + @Override + public void onOk() { + // 跳去实名认证页面 + CommonWebViewActivity.start(activity, + UriProvider.getTutuRealNamePage()); + } + }); + break; + case CER_TYPE_GUIDE: + activity.getDialogManager().showTipsDialog(getCertificationTips(activity), + activity.getString(R.string.go_to_certification), + new DialogManager.OkCancelDialogListener() { + @Override + public void onCancel() { + requestOpenRoom(activity, type, gameId); + } + + @Override + public void onOk() { + // 跳去实名认证页面 + CommonWebViewActivity.start(activity, + UriProvider.getTutuRealNamePage()); + } + }); + break; + } + } else { + requestOpenRoom(activity, type, gameId); + } + } + + @NonNull + private static SpannableStringBuilder getCertificationTips(BaseActivity activity) { + String tips = activity.getString(R.string.tips_need_to_certification); + SpannableStringBuilder builder = new SpannableStringBuilder(tips); + builder.setSpan(new ForegroundColorSpan(ContextCompat.getColor(activity, R.color.appColor)), + tips.length() - 4, tips.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE); + return builder; + } + + /** + * 开启房间 + */ + public static void requestOpenRoom(BaseActivity activity, int type, long gameId) { + activity.getDialogManager().showProgressDialog(activity, activity.getString(R.string.waiting_text)); + AvRoomModel.get().requestRoomInfoV2(String.valueOf(AuthModel.get().getCurrentUid()), 0) + .compose(RxHelper.bindActivity(activity)) + .subscribe(new DontWarnObserver() { + @Override + public void acceptThrowable(RoomInfo roomInfo, Throwable throwable) { + super.acceptThrowable(roomInfo, throwable); + if (roomInfo != null) { + if (roomInfo.isReselect() && type == RoomInfo.ROOMTYPE_DEFAULT && roomInfo.getIsPermitRoom() != 1) { + activity.getDialogManager().dismissDialog(); + new CreateRoomDialog().show(activity); + } else { + if (roomInfo.isValid()) { + if (type == RoomInfo.ROOMTYPE_DEFAULT || (roomInfo.getType() == type && roomInfo.getMgId() == gameId)) { + onOpenRoomSuccess(activity, roomInfo); + } else { + updateRoomInfo(activity, roomInfo, type, gameId, true); + } + } else { + openRoom(activity, roomInfo, type, gameId); + } + } + } else { + if (throwable instanceof PmRoomLimitException) { + onOpenRoomPmLimit(activity, throwable.getMessage()); + } else if (!TextUtils.isEmpty(throwable.getMessage())) { + onOpenRoomFail(activity, throwable.getMessage()); + } + } + } + }); + + } + + public static Single updateRoomInfoRx(RoomInfo roomInfo, int type, long gameId) { + RoomSettingModel roomSettingModel = new RoomSettingModel(); + return roomSettingModel.updateRoomInfo( + roomInfo.getTitle(), + roomInfo.getAvatar(), + roomInfo.getRoomDesc(), + roomInfo.getIntroduction(), + roomInfo.roomPwd, + roomInfo.getRoomTypeLable(), + roomInfo.tagId, + roomInfo.getUid(), + AuthModel.get().getTicket(), + roomInfo.isHasAnimationEffect(), + roomInfo.getAudioQuality(), + roomInfo.getLimitType(), + roomInfo.isPureMode(), + type, + gameId); + } + + public static Single updateRoomInfoEx(RoomInfo roomInfo) { + RoomSettingModel roomSettingModel = new RoomSettingModel(); + return roomSettingModel.updateRoomInfoEx(roomInfo); + } + + public static void updateRoomInfo(BaseActivity activity, RoomInfo roomInfo, int type, long gameId, boolean needOpen) { + RoomSettingModel roomSettingModel = new RoomSettingModel(); + roomSettingModel.updateRoomInfo( + roomInfo.getTitle(), + roomInfo.getAvatar(), + roomInfo.getRoomDesc(), + roomInfo.getIntroduction(), + roomInfo.roomPwd, + roomInfo.getRoomTypeLable(), + roomInfo.tagId, + roomInfo.getUid(), + AuthModel.get().getTicket(), + roomInfo.isHasAnimationEffect(), + roomInfo.getAudioQuality(), + roomInfo.getLimitType(), + roomInfo.isPureMode(), + type, + gameId) + .compose(RxHelper.bindContext(activity)) + .subscribe(new BeanObserver() { + @Override + public void onErrorMsg(String error) { + onOpenRoomFail(activity, error); + } + + @Override + public void onSuccess(@NonNull RoomInfo roomInfo) { + if (needOpen) { + openRoom(activity, roomInfo, type, gameId); + } + } + }); + } + + @SuppressLint("CheckResult") + private static void openRoom(BaseActivity activity, RoomInfo roomInfo, int type, long gameId) { + AvRoomModel.get().openRoom( + AuthModel.get().getCurrentUid(), + type == RoomInfo.ROOMTYPE_DEFAULT ? (roomInfo.getType() == 0 ? RoomInfo.ROOMTYPE_HOME_PARTY : roomInfo.getType()) : type, + roomInfo.getTitle(), + roomInfo.getRoomDesc(), + roomInfo.getBackPic(), + null, + gameId) + .compose(RxHelper.bindActivity(activity)) + .subscribe((roomResult, throwable) -> { + if (throwable != null) { + onOpenRoomFail(activity, throwable.getMessage()); + } else if (roomResult != null && roomResult.isSuccess()) { + onOpenRoomSuccess(activity, roomInfo); + } else if (roomResult != null && !roomResult.isSuccess()) { + if (roomResult.getCode() == 1500) { + onOpenRoomSuccess(activity, roomInfo); + } else { + onOpenRoomFail(activity, roomResult.getError()); + } + } else { + onOpenRoomFail(activity, ResUtil.getString(R.string.home_helper_openroomhelper_01)); + } + }); + } + + private static void onOpenRoomSuccess(BaseActivity activity, RoomInfo roomInfo) { + activity.getDialogManager().dismissDialog(); + AVRoomActivity.start(activity, AuthModel.get().getCurrentUid()); + } + + private static void onOpenRoomFail(BaseActivity activity, String error) { + activity.getDialogManager().dismissDialog(); + SingleToastUtil.showToast(error); + } + + private static void onOpenRoomPmLimit(BaseActivity activity, String error) { + activity.getDialogManager().dismissDialog(); + if (activity instanceof MainActivity) { + ((MainActivity) activity).handleOpenRoomWhenPmLimit(error); + } + } + + +} diff --git a/app/src/main/java/com/chwl/app/home/presenter/CommunityNoticePresenter.java b/app/src/main/java/com/chwl/app/home/presenter/CommunityNoticePresenter.java new file mode 100644 index 0000000..404bddb --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/presenter/CommunityNoticePresenter.java @@ -0,0 +1,91 @@ +package com.chwl.app.home.presenter; + +import android.annotation.SuppressLint; + +import com.chwl.app.R; +import com.chwl.app.base.BaseMvpPresenter; +import com.chwl.app.home.view.ICommunityNoticeAct; +import com.chwl.core.Constants; +import com.chwl.core.community.bean.CommunityNoticeInfo; +import com.chwl.core.home.model.CommunityNoticeModel; +import com.chwl.library.utils.ResUtil; + +import java.util.List; + +import io.reactivex.functions.BiConsumer; + +public class CommunityNoticePresenter extends BaseMvpPresenter { + private int page = 0; + private int pageSize = Constants.PAGE_SIZE; + private Long lastId; + + public void refresh(long uid) { + page = 1; + getMsgList(uid, null); + } + + public void loadMore(long uid) { + page++; + getMsgList(uid, lastId); + } + + @SuppressLint("CheckResult") + private void getMsgList(long uid, Long id) { + CommunityNoticeModel.get().getMsg(uid, id, pageSize) + .compose(bindToLifecycle()) + .subscribe(new BiConsumer, Throwable>() { + @Override + public void accept(List communityNoticeInfos, Throwable throwable) throws Exception { + + if (throwable == null) { + if (communityNoticeInfos != null && communityNoticeInfos.size() > 0) { + lastId = communityNoticeInfos.get(communityNoticeInfos.size() - 1).getMsgId(); + + if (mMvpView != null) { + mMvpView.getMsgListSuccess(communityNoticeInfos); + } + } else { + if (mMvpView != null) { + mMvpView.getMsgListFail(ResUtil.getString(R.string.home_presenter_communitynoticepresenter_01)); + } + } + + } else { + page--; + if (mMvpView != null) { + mMvpView.getMsgListFail(throwable.getMessage()); + } + } + + } + }); + + } + + @SuppressLint("CheckResult") + public void delete(long uid) { + CommunityNoticeModel.get().delete(uid).compose(bindToLifecycle()) + .subscribe(new BiConsumer() { + @Override + public void accept(String s, Throwable throwable) throws Exception { + + if (throwable == null) { + if (mMvpView != null) { + mMvpView.clearSuccess(); + } + + } else { + if (mMvpView != null) { + mMvpView.clearFail(throwable.getMessage()); + } + + } + + } + }); + } + + public int getPage() { + return page; + } +} diff --git a/app/src/main/java/com/chwl/app/home/presenter/MainFragmentPresenter.java b/app/src/main/java/com/chwl/app/home/presenter/MainFragmentPresenter.java new file mode 100644 index 0000000..32972dc --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/presenter/MainFragmentPresenter.java @@ -0,0 +1,87 @@ +package com.chwl.app.home.presenter; + +import android.os.Bundle; + +import androidx.annotation.Nullable; + +import com.chwl.app.base.BaseMvpPresenter; +import com.chwl.app.home.view.IMainFragmentView; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.core.room.model.AvRoomModel; +import com.chwl.library.net.rxnet.callback.CallBack; + +import org.greenrobot.eventbus.EventBus; + +import io.reactivex.disposables.CompositeDisposable; + +/** + * @author jiajie + * @Description + * @Date 2018/4/13 + */ + +public class MainFragmentPresenter extends BaseMvpPresenter { + + + public static final int OPEN_ROOM_SUCCESS = 1; + public static final int OPEN_ROOM_FAIL_TYPE_IN_ROOM = 2; + public static final int OPEN_ROOM_FAIL = 3; + public static final int OPEN_ROOM_FAIL_ALREADY_OPENED_ROOM = 4; + /** + * 青少年限制时长的报错 + */ + public static final int OPEN_ROOM_FAIL_PM_LIMIT_TIME = 5; + private final static String TAG = MainFragmentPresenter.class.getSimpleName(); + private final AvRoomModel avRoomModel; + private CompositeDisposable mCompositeDisposable; + + public MainFragmentPresenter() { + avRoomModel = AvRoomModel.get(); + } + + public void exitRoom() { + avRoomModel.exitRoom(new CallBack() { + @Override + public void onSuccess(RoomInfo data) { + if (getMvpView() != null) { + getMvpView().exitRoom(data); + } + } + + @Override + public void onFail(int code, String error) { + + } + }); + } + + @Override + public void onCreatePresenter(@Nullable Bundle saveState) { + super.onCreatePresenter(saveState); + if (mCompositeDisposable == null) { + mCompositeDisposable = new CompositeDisposable(); + } + EventBus.getDefault().register(this); + } + + @Override + public void onDestroyPresenter() { + super.onDestroyPresenter(); + if (mCompositeDisposable != null) { + mCompositeDisposable.dispose(); + mCompositeDisposable = null; + } + EventBus.getDefault().unregister(this); + } + + @Override + public IMainFragmentView getMvpView() { + if (super.getMvpView() == null) { + return new IMainFragmentView.FakeIMainFragmentView(); + } else { + return super.getMvpView(); + } + } + + +} diff --git a/app/src/main/java/com/chwl/app/home/presenter/MainPresenter.java b/app/src/main/java/com/chwl/app/home/presenter/MainPresenter.java new file mode 100644 index 0000000..eb3fdd2 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/presenter/MainPresenter.java @@ -0,0 +1,40 @@ +package com.chwl.app.home.presenter; + +import com.chwl.app.base.BaseMvpPresenter; +import com.chwl.app.home.view.IMainView; +import com.chwl.app.utils.RoomHelperManager; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.core.room.model.AvRoomModel; +import com.chwl.library.net.rxnet.callback.CallBack; + +/** + *

+ * + * @author jiahui + * @date 2017/12/12 + */ +public class MainPresenter extends BaseMvpPresenter { + private final AvRoomModel mAvRoomMode; + + public MainPresenter() { + mAvRoomMode = AvRoomModel.get(); + } + + public void exitRoom() { + mAvRoomMode.exitRoom(new CallBack() { + @Override + public void onSuccess(RoomInfo data) { + if (getMvpView() != null) { + getMvpView().exitRoom(data); + RoomHelperManager.INSTANCE.setRoomUid(0L); + } + } + + @Override + public void onFail(int code, String error) { + + } + }); + } + +} diff --git a/app/src/main/java/com/chwl/app/home/presenter/NewUserListPresenter.java b/app/src/main/java/com/chwl/app/home/presenter/NewUserListPresenter.java new file mode 100644 index 0000000..b74f137 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/presenter/NewUserListPresenter.java @@ -0,0 +1,49 @@ +package com.chwl.app.home.presenter; + +import com.chwl.app.base.BaseMvpPresenter; +import com.chwl.app.home.helper.LoadPageDataHelper; +import com.chwl.app.home.view.INewUserListActivityView; +import com.chwl.core.Constants; +import com.chwl.core.home.model.HomeModel; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.library.base.PresenterEvent; + +import java.util.List; + +import io.reactivex.Single; + +/** + * @author jack + * @Description + * @Date 2018/11/1 + */ +public class NewUserListPresenter extends BaseMvpPresenter + implements LoadPageDataHelper.LoadData> { + + LoadPageDataHelper> loadPageDataHelper; + + public NewUserListPresenter() { + loadPageDataHelper = new LoadPageDataHelper<>(this); + } + + + @Override + public Single> loadData(int curPage) { + return HomeModel.INSTANCE.loadNewUserList( + String.valueOf(curPage), + String.valueOf(Constants.PAGE_SIZE) + ) + .compose(bindUntilEvent(PresenterEvent.DESTROY)); + } + + + public Single> refreshData() { + return loadPageDataHelper.refreshData() + .compose(bindUntilEvent(PresenterEvent.DESTROY)); + } + + public Single> loadMoreData() { + return loadPageDataHelper.loadMoreData() + .compose(bindUntilEvent(PresenterEvent.DESTROY)); + } +} diff --git a/app/src/main/java/com/chwl/app/home/view/ICommunityNoticeAct.java b/app/src/main/java/com/chwl/app/home/view/ICommunityNoticeAct.java new file mode 100644 index 0000000..f4a9cd5 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/view/ICommunityNoticeAct.java @@ -0,0 +1,14 @@ +package com.chwl.app.home.view; + +import com.chwl.core.community.bean.CommunityNoticeInfo; +import com.chwl.library.base.IMvpBaseView; + +import java.util.List; + +public interface ICommunityNoticeAct extends IMvpBaseView { + void getMsgListSuccess(List list); + void getMsgListFail(String error); + + void clearSuccess(); + void clearFail(String error); +} diff --git a/app/src/main/java/com/chwl/app/home/view/IFamilyHomeActivityView.java b/app/src/main/java/com/chwl/app/home/view/IFamilyHomeActivityView.java new file mode 100644 index 0000000..e72e3f4 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/view/IFamilyHomeActivityView.java @@ -0,0 +1,21 @@ +package com.chwl.app.home.view; + +import com.chwl.core.family.bean.FamilyInfo; +import com.chwl.library.base.IMvpBaseView; + +/** + * @author jack + * @Description + * @Date 2018/5/23 + */ + +public interface IFamilyHomeActivityView extends IMvpBaseView { + + void onLoadData(FamilyInfo data); + + void showErrorView(String message); + + void reloadMyFamilyInfo(String familyId); + + void close(); +} diff --git a/app/src/main/java/com/chwl/app/home/view/IMainFragmentView.java b/app/src/main/java/com/chwl/app/home/view/IMainFragmentView.java new file mode 100644 index 0000000..ee6acc8 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/view/IMainFragmentView.java @@ -0,0 +1,34 @@ +package com.chwl.app.home.view; + +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.library.base.IMvpBaseView; + +/** + * @author jiajie + * @Description + * @Date 2018/4/13 + */ + +public interface IMainFragmentView extends IMvpBaseView { + + /** + * 退出房间 + */ + void exitRoom(RoomInfo roomInfo); + + + /** + * 假实现,用于在View销毁后 调用View方法导致空指针问题,的一种解决方案 + */ + class FakeIMainFragmentView implements IMainFragmentView { + + @Override + public void exitRoom(RoomInfo roomInfo) { + + } + + + } + + +} diff --git a/app/src/main/java/com/chwl/app/home/view/IMainView.java b/app/src/main/java/com/chwl/app/home/view/IMainView.java new file mode 100644 index 0000000..21a1ca6 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/view/IMainView.java @@ -0,0 +1,17 @@ +package com.chwl.app.home.view; + +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.library.base.IMvpBaseView; + +/** + *

+ * + * @author jiahui + * @date 2017/12/12 + */ +public interface IMainView extends IMvpBaseView { + /** + * 退出房间 + */ + void exitRoom(RoomInfo roomInfo); +} diff --git a/app/src/main/java/com/chwl/app/home/view/INewUserListActivityView.java b/app/src/main/java/com/chwl/app/home/view/INewUserListActivityView.java new file mode 100644 index 0000000..b218b43 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/view/INewUserListActivityView.java @@ -0,0 +1,11 @@ +package com.chwl.app.home.view; + +import com.chwl.library.base.IMvpBaseView; + +/** + * @author jack + * @Description + * @Date 2018/11/1 + */ +public interface INewUserListActivityView extends IMvpBaseView { +} diff --git a/app/src/main/java/com/chwl/app/home/widget/AnchorCardView.kt b/app/src/main/java/com/chwl/app/home/widget/AnchorCardView.kt new file mode 100644 index 0000000..900d68f --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/widget/AnchorCardView.kt @@ -0,0 +1,249 @@ +package com.chwl.app.home.widget + +import android.animation.Animator +import android.animation.AnimatorListenerAdapter +import android.animation.ObjectAnimator +import android.annotation.SuppressLint +import android.content.Context +import android.media.AudioAttributes +import android.os.Vibrator +import android.text.TextUtils +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.MotionEvent +import android.widget.FrameLayout +import android.widget.ImageView +import androidx.core.view.isGone +import androidx.core.view.isVisible +import androidx.recyclerview.widget.LinearLayoutManager +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.audio.helper.AudioPlayerHelper +import com.chwl.app.audio.helper.OnPlayListener +import com.chwl.app.avroom.activity.AVRoomActivity +import com.chwl.app.databinding.LayoutAnchorCardViewBinding +import com.chwl.app.ui.user.activity.UserInfoActivity +import com.chwl.app.ui.user.decorationsend.UserInfoSkillDecoration +import com.chwl.app.ui.utils.load +import com.chwl.app.ui.utils.loadAvatar +import com.chwl.core.room.bean.AnchorInfo +import com.chwl.core.user.bean.UserInfo +import com.chwl.core.user.bean.UserInfoSkillEntity +import com.chwl.core.utils.extension.subAndReplaceDot +import com.chwl.library.utils.ListUtils +import com.chwl.library.utils.SingleToastUtil +import io.reactivex.Observable +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import java.util.concurrent.TimeUnit + +class AnchorCardView @JvmOverloads constructor( + context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 +) : FrameLayout(context, attrs, defStyleAttr) { + + private lateinit var binding: LayoutAnchorCardViewBinding + private var disposable: Disposable? = null + private var downY = 0f + private var audioPlaying = false + private var anchorInfo: AnchorInfo? = null + private var mVibrator: Vibrator? = null + private val patter = longArrayOf(0, 1000, 2500) + private var count: Long = 10 + + private fun initView() { + if (!this::binding.isInitialized) { + mVibrator = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator? + binding = LayoutAnchorCardViewBinding.inflate(LayoutInflater.from(context)) + addView( + binding.root, + LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT) + ) + binding.recyclerviewSkillCard.adapter = object : + BaseQuickAdapter(R.layout.item_anchor_card_skill_abspicture) { + override fun convert(helper: BaseViewHolder, item: String) { + helper.getView(R.id.iv_skill_picture).load(item) + } + } + binding.recyclerviewSkillCard.layoutManager = LinearLayoutManager( + context, + LinearLayoutManager.HORIZONTAL, + false + ) + binding.recyclerviewSkillCard.addItemDecoration(UserInfoSkillDecoration(context, 4)) + } + + } + + private fun setupData() { + anchorInfo?.let { + count = 10 + initView() + startVibrate() + isVisible = true + (binding.recyclerviewSkillCard.adapter as BaseQuickAdapter).setNewData( + it.absCardPics + ) + initVoiceShow(it.voiceCard) + binding.ivAvatar.loadAvatar(it.avatar) + binding.ivAvatar.setOnClickListener { _ -> + UserInfoActivity.Companion.start(context, it.uid) + } + binding.tvNick.text = it.nick.subAndReplaceDot(7) + binding.tvSignature.text = it.userDesc + binding.tvSignature.isGone = it.userDesc.isNullOrEmpty() + if (it.gender == UserInfo.GENDER_MALE) { + binding.ivGender.setImageResource(R.drawable.ic_gender_male) + } else { + binding.ivGender.setImageResource(R.drawable.ic_gender_female) + } + binding.tvGoRoom.setOnClickListener { _ -> + AVRoomActivity.start( + context, + it.roomUid?.let { roomUid -> if (roomUid == 0L) it.uid else roomUid } ?: it.uid + ) + isVisible = false + stopAudio() + } + intervalRange() + } ?: run { + isVisible = false + } + } + + @SuppressLint("SetTextI18n") + private fun intervalRange() { + disposable?.dispose() + val finalCount = count + disposable = Observable.intervalRange(0, count + 1, 0, 1, TimeUnit.SECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .doOnNext { aLong -> + count -= 1 + binding.tvTime.text = "剩餘${finalCount - aLong}s" + } + .doOnComplete { + if (!audioPlaying) isVisible = false + } + .subscribe() + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + disposable?.dispose() + } + + override fun onTouchEvent(event: MotionEvent): Boolean { + when (event.action) { + MotionEvent.ACTION_DOWN -> downY = event.rawY + MotionEvent.ACTION_MOVE -> { + if (event.rawY - downY < 0) { + translationY = event.rawY - downY + } + } + MotionEvent.ACTION_UP -> { + val offset = event.rawY - downY + when { + offset < -height / 2 -> { + val end = -height.toFloat() + startAnimator(translationY, end) { + stopAudio() + isVisible = false + } + } + else -> { + startAnimator(translationY, 0f) {} + translationY = 0f + } + } + } + else -> { + } + } + return true + } + + private fun startAnimator(start: Float, end: Float, onAnimationEnd: () -> Unit) { + val slowdownAnim = ObjectAnimator.ofFloat(this, "TranslationY", start, end) + slowdownAnim.duration = 200 + slowdownAnim.addListener(object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + onAnimationEnd() + } + }) + slowdownAnim.start() + } + + private fun initVoiceShow(skillEntity: UserInfoSkillEntity?) { + if (skillEntity != null) { + binding.llAudio.visibility = VISIBLE + binding.livUser.stop() + binding.llAudio.setOnClickListener { toggleAudio(skillEntity.propVals) } + } else { + binding.llAudio.visibility = GONE + } + } + + private fun toggleAudio(list: List) { + if (ListUtils.isListEmpty(list)) return + var url: String? = "" + for (s in list) { + if (s!!.contains("http")) { + url = s + } + } + if (TextUtils.isEmpty(url)) return + if (!audioPlaying) { + playAudio(url) + } else { + stopAudio() + } + } + + private fun playAudio(url: String?) { + if (audioPlaying) return + disposable?.dispose() + audioPlaying = true + binding.livUser.start() + binding.ivAudioControl.setImageResource(R.drawable.ic_skill_play) + AudioPlayerHelper.get().playInThread(url, object : OnPlayListener { + override fun onError(error: String) { + SingleToastUtil.showToast("播放出錯,請重試") + stopAudio() + } + + override fun onPrepared() {} + override fun onPlaying(currDuration: Long) {} + override fun onCompletion() { + stopAudio() + } + }) + } + + private fun stopAudio() { + if (!audioPlaying) return + intervalRange() + audioPlaying = false + binding.livUser.stop() + binding.ivAudioControl.setImageResource(R.drawable.ic_skill_pause) + AudioPlayerHelper.get().endPlay() + } + + fun setAnchorInfo(anchorInfo: AnchorInfo) { + this.anchorInfo = anchorInfo + setupData() + } + + private fun startVibrate() { + if (mVibrator == null) { + mVibrator = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator? + } + mVibrator?.cancel() + val audioAttributes = AudioAttributes.Builder() + .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) + .setUsage(AudioAttributes.USAGE_ALARM) + .build() + mVibrator?.vibrate(patter, -1, audioAttributes) + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/widget/ListViewAdaptWidth.java b/app/src/main/java/com/chwl/app/home/widget/ListViewAdaptWidth.java new file mode 100644 index 0000000..0fc100b --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/widget/ListViewAdaptWidth.java @@ -0,0 +1,47 @@ +package com.chwl.app.home.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.widget.ListView; + +public class ListViewAdaptWidth extends ListView { + + public ListViewAdaptWidth(Context context) { + super(context); + } + + public ListViewAdaptWidth(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public ListViewAdaptWidth(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + //计算listview的宽度 + int width = getMaxWidthOfChildren() + getPaddingLeft() + getPaddingRight(); + super.onMeasure(MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY), heightMeasureSpec);//设置listview的宽高 + + } + + /** + * 计算item的最大宽度 + * + * @return + */ + private int getMaxWidthOfChildren() { + int maxWidth = 0; + View view = null; + int count = getAdapter().getCount(); + for (int i = 0; i < count; i++) { + view = getAdapter().getView(i, view, this); + view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); + if (view.getMeasuredWidth() > maxWidth) + maxWidth = view.getMeasuredWidth(); + } + return maxWidth; + } +} diff --git a/app/src/main/java/com/chwl/app/home/widget/MePageIndicatorView.java b/app/src/main/java/com/chwl/app/home/widget/MePageIndicatorView.java new file mode 100644 index 0000000..398dd0a --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/widget/MePageIndicatorView.java @@ -0,0 +1,133 @@ +package com.chwl.app.home.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.View; +import android.widget.LinearLayout; + +import com.chwl.app.R; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by shichaohui on 2015/7/10 0010. + *

+ * 页码指示器类,获得此类实例后,可通过{@link MePageIndicatorView#initIndicator(int)}方法初始化指示器 + *

+ */ +public class MePageIndicatorView extends LinearLayout { + + private Context mContext = null; + private int dotSize = 12; // 指示器的大小(dp) + private int height = 4; // 指示器的大小(dp) + private double margins = 0; // 指示器间距(dp) + private List indicatorViews = null; // 存放指示器 + private int selectRes = R.drawable.shape_me_indicator_visible; + private int noSelectRes = R.drawable.shape_me_indicator_invisible; + + public void setSelectRes(int selectRes) { + this.selectRes = selectRes; + } + + public void setNoSelectRes(int noSelectRes) { + this.noSelectRes = noSelectRes; + } + + public MePageIndicatorView(Context context) { + this(context, null); + } + + public MePageIndicatorView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public MePageIndicatorView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context); + } + + private void init(Context context) { + this.mContext = context; + + setGravity(Gravity.CENTER); + setOrientation(HORIZONTAL); + + dotSize = UIUtil.dip2px(context, dotSize); + height = UIUtil.dip2px(context, height); + margins = UIUtil.dip2px(context, (float) margins); + } + + public void setDotSize(int dotSize) { + this.dotSize = dotSize; + } + + public void setHeight(int height) { + this.height = height; + } + + /** + * 初始化指示器,默认选中第一页 + * + * @param count 指示器数量,即页数 + */ + public void initIndicator(int count) { + if (indicatorViews == null) { + indicatorViews = new ArrayList<>(); + } + indicatorViews.clear(); + removeAllViews(); + View view; + LayoutParams params = new LayoutParams(dotSize, height); + int margins = (int) this.margins; + params.setMargins(margins, margins, margins, margins); + for (int i = 0; i < count; i++) { + view = new View(mContext); + view.setBackgroundResource(noSelectRes); + addView(view, params); + indicatorViews.add(view); + } + if (indicatorViews.size() > 0) { + indicatorViews.get(0).setBackgroundResource(selectRes); + } + } + + /** + * 设置选中页 + * + * @param selected 页下标,从0开始 + */ + public void setSelectedPage(int selected) { + for (int i = 0; i < indicatorViews.size(); i++) { + if (i == selected) { + indicatorViews.get(i).setBackgroundResource(selectRes); + } else { + indicatorViews.get(i).setBackgroundResource(noSelectRes); + } + } + } + + /** + * 设置选中页 + * + * @param selected 页下标,从0开始 + */ + public void setDifSelectedPage(int selected) { + for (int i = 0; i < indicatorViews.size(); i++) { + if (i == selected) { + LayoutParams params = new LayoutParams(dotSize, height); + int margins = (int) this.margins; + params.setMargins(margins, margins, margins, margins); + indicatorViews.get(i).setLayoutParams(params); + indicatorViews.get(i).setBackgroundResource(selectRes); + } else { + LayoutParams params = new LayoutParams(height, height); + indicatorViews.get(i).setLayoutParams(params); + indicatorViews.get(i).setBackgroundResource(noSelectRes); + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/home/widget/StickyScrollView.java b/app/src/main/java/com/chwl/app/home/widget/StickyScrollView.java new file mode 100644 index 0000000..5865689 --- /dev/null +++ b/app/src/main/java/com/chwl/app/home/widget/StickyScrollView.java @@ -0,0 +1,396 @@ +package com.chwl.app.home.widget; + + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.AlphaAnimation; + +import androidx.core.widget.NestedScrollView; + +import com.chwl.app.R; + +import java.util.ArrayList; + +public class StickyScrollView extends NestedScrollView { + + /** + * Tag for views that should stick and have constant drawing. e.g. TextViews, ImageViews etc + */ + public static final String STICKY_TAG = "sticky"; + + /** + * Flag for views that should stick and have non-constant drawing. e.g. Buttons, ProgressBars etc + */ + public static final String FLAG_NONCONSTANT = "-nonconstant"; + + /** + * Flag for views that have aren't fully opaque + */ + public static final String FLAG_HASTRANSPARANCY = "-hastransparancy"; + + /** + * Default height of the shadow peeking out below the stuck view. + */ + private static final int DEFAULT_SHADOW_HEIGHT = 10; // dp; + + private ArrayList stickyViews; + private View currentlyStickingView; + private float stickyViewTopOffset; + private int stickyViewLeftOffset; + private boolean redirectTouchesToStickyView; + private boolean clippingToPadding; + private boolean clipToPaddingHasBeenSet; + + private int mShadowHeight; + private Drawable mShadowDrawable; + + private final Runnable invalidateRunnable = new Runnable() { + + @Override + public void run() { + if (currentlyStickingView != null) { + int l = getLeftForViewRelativeOnlyChild(currentlyStickingView); + int t = getBottomForViewRelativeOnlyChild(currentlyStickingView); + int r = getRightForViewRelativeOnlyChild(currentlyStickingView); + int b = (int) (getScrollY() + (currentlyStickingView.getHeight() + stickyViewTopOffset)); + invalidate(l, t, r, b); + } + postDelayed(this, 16); + } + }; + + public StickyScrollView(Context context) { + this(context, null); + } + + public StickyScrollView(Context context, AttributeSet attrs) { + this(context, attrs, android.R.attr.scrollViewStyle); + } + + public StickyScrollView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + setup(); + + TypedArray a = context.obtainStyledAttributes(attrs, + R.styleable.StickyScrollView, defStyle, 0); + + final float density = context.getResources().getDisplayMetrics().density; + int defaultShadowHeightInPix = (int) (DEFAULT_SHADOW_HEIGHT * density + 0.5f); + + mShadowHeight = a.getDimensionPixelSize( + R.styleable.StickyScrollView_stuckShadowHeight, + defaultShadowHeightInPix); + + int shadowDrawableRes = a.getResourceId( + R.styleable.StickyScrollView_stuckShadowDrawable, -1); + + if (shadowDrawableRes != -1) { + mShadowDrawable = context.getResources().getDrawable( + shadowDrawableRes); + } + + a.recycle(); + } + + /** + * Sets the height of the shadow drawable in pixels. + * + * @param height + */ + public void setShadowHeight(int height) { + mShadowHeight = height; + } + + + public void setup() { + stickyViews = new ArrayList(); + } + + private int getLeftForViewRelativeOnlyChild(View v) { + int left = v.getLeft(); + while (v.getParent() != getChildAt(0)) { + v = (View) v.getParent(); + left += v.getLeft(); + } + return left; + } + + private int getTopForViewRelativeOnlyChild(View v) { + int top = v.getTop(); + while (v.getParent() != getChildAt(0)) { + v = (View) v.getParent(); + top += v.getTop(); + } + return top; + } + + private int getRightForViewRelativeOnlyChild(View v) { + int right = v.getRight(); + while (v.getParent() != getChildAt(0)) { + v = (View) v.getParent(); + right += v.getRight(); + } + return right; + } + + private int getBottomForViewRelativeOnlyChild(View v) { + int bottom = v.getBottom(); + while (v.getParent() != getChildAt(0)) { + v = (View) v.getParent(); + bottom += v.getBottom(); + } + return bottom; + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + if (!clipToPaddingHasBeenSet) { + clippingToPadding = true; + } + notifyHierarchyChanged(); + } + + @Override + public void setClipToPadding(boolean clipToPadding) { + super.setClipToPadding(clipToPadding); + clippingToPadding = clipToPadding; + clipToPaddingHasBeenSet = true; + } + + @Override + public void addView(View child) { + super.addView(child); + findStickyViews(child); + } + + @Override + public void addView(View child, int index) { + super.addView(child, index); + findStickyViews(child); + } + + @Override + public void addView(View child, int index, android.view.ViewGroup.LayoutParams params) { + super.addView(child, index, params); + findStickyViews(child); + } + + @Override + public void addView(View child, int width, int height) { + super.addView(child, width, height); + findStickyViews(child); + } + + @Override + public void addView(View child, android.view.ViewGroup.LayoutParams params) { + super.addView(child, params); + findStickyViews(child); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + if (currentlyStickingView != null) { + canvas.save(); + canvas.translate(getPaddingLeft() + stickyViewLeftOffset, getScrollY() + stickyViewTopOffset + (clippingToPadding ? getPaddingTop() : 0)); + + canvas.clipRect(0, (clippingToPadding ? -stickyViewTopOffset : 0), + getWidth() - stickyViewLeftOffset, + currentlyStickingView.getHeight() + mShadowHeight + 1); + + if (mShadowDrawable != null) { + int left = 0; + int right = currentlyStickingView.getWidth(); + int top = currentlyStickingView.getHeight(); + int bottom = currentlyStickingView.getHeight() + mShadowHeight; + mShadowDrawable.setBounds(left, top, right, bottom); + mShadowDrawable.draw(canvas); + } + + canvas.clipRect(0, (clippingToPadding ? -stickyViewTopOffset : 0), getWidth(), currentlyStickingView.getHeight()); + if (getStringTagForView(currentlyStickingView).contains(FLAG_HASTRANSPARANCY)) { + showView(currentlyStickingView); + currentlyStickingView.draw(canvas); + hideView(currentlyStickingView); + } else { + currentlyStickingView.draw(canvas); + } + canvas.restore(); + } + } + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + if (ev.getAction() == MotionEvent.ACTION_DOWN) { + redirectTouchesToStickyView = true; + } + + if (redirectTouchesToStickyView) { + redirectTouchesToStickyView = currentlyStickingView != null; + if (redirectTouchesToStickyView) { + redirectTouchesToStickyView = + ev.getY() <= (currentlyStickingView.getHeight() + stickyViewTopOffset) && + ev.getX() >= getLeftForViewRelativeOnlyChild(currentlyStickingView) && + ev.getX() <= getRightForViewRelativeOnlyChild(currentlyStickingView); + } + } else if (currentlyStickingView == null) { + redirectTouchesToStickyView = false; + } + if (redirectTouchesToStickyView) { + ev.offsetLocation(0, -1 * ((getScrollY() + stickyViewTopOffset) - getTopForViewRelativeOnlyChild(currentlyStickingView))); + } + return super.dispatchTouchEvent(ev); + } + + private boolean hasNotDoneActionDown = true; + + @Override + public boolean onTouchEvent(MotionEvent ev) { + if (redirectTouchesToStickyView) { + ev.offsetLocation(0, ((getScrollY() + stickyViewTopOffset) - getTopForViewRelativeOnlyChild(currentlyStickingView))); + } + + if (ev.getAction() == MotionEvent.ACTION_DOWN) { + hasNotDoneActionDown = false; + } + + if (hasNotDoneActionDown) { + MotionEvent down = MotionEvent.obtain(ev); + down.setAction(MotionEvent.ACTION_DOWN); + super.onTouchEvent(down); + hasNotDoneActionDown = false; + } + + if (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL) { + hasNotDoneActionDown = true; + } + + return super.onTouchEvent(ev); + } + + @Override + protected void onScrollChanged(int l, int t, int oldl, int oldt) { + super.onScrollChanged(l, t, oldl, oldt); + doTheStickyThing(); + } + + private void doTheStickyThing() { + View viewThatShouldStick = null; + View approachingView = null; + for (View v : stickyViews) { + int viewTop = getTopForViewRelativeOnlyChild(v) - getScrollY() + (clippingToPadding ? 0 : getPaddingTop()); + if (viewTop <= 0) { + if (viewThatShouldStick == null || viewTop > (getTopForViewRelativeOnlyChild(viewThatShouldStick) - getScrollY() + (clippingToPadding ? 0 : getPaddingTop()))) { + viewThatShouldStick = v; + } + } else { + if (approachingView == null || viewTop < (getTopForViewRelativeOnlyChild(approachingView) - getScrollY() + (clippingToPadding ? 0 : getPaddingTop()))) { + approachingView = v; + } + } + } + if (viewThatShouldStick != null) { + stickyViewTopOffset = approachingView == null ? 0 : Math.min(0, getTopForViewRelativeOnlyChild(approachingView) - getScrollY() + (clippingToPadding ? 0 : getPaddingTop()) - viewThatShouldStick.getHeight()); + if (viewThatShouldStick != currentlyStickingView) { + if (currentlyStickingView != null) { + stopStickingCurrentlyStickingView(); + } + // only compute the left offset when we start sticking. + stickyViewLeftOffset = getLeftForViewRelativeOnlyChild(viewThatShouldStick); + startStickingView(viewThatShouldStick); + } + } else if (currentlyStickingView != null) { + stopStickingCurrentlyStickingView(); + } + } + + private void startStickingView(View viewThatShouldStick) { + currentlyStickingView = viewThatShouldStick; + if (getStringTagForView(currentlyStickingView).contains(FLAG_HASTRANSPARANCY)) { + hideView(currentlyStickingView); + } + if (((String) currentlyStickingView.getTag()).contains(FLAG_NONCONSTANT)) { + post(invalidateRunnable); + } + } + + private void stopStickingCurrentlyStickingView() { + if (getStringTagForView(currentlyStickingView).contains(FLAG_HASTRANSPARANCY)) { + showView(currentlyStickingView); + } + currentlyStickingView = null; + removeCallbacks(invalidateRunnable); + } + + /** + * Notify that the sticky attribute has been added or removed from one or more views in the View hierarchy + */ + public void notifyStickyAttributeChanged() { + notifyHierarchyChanged(); + } + + private void notifyHierarchyChanged() { + if (currentlyStickingView != null) { + stopStickingCurrentlyStickingView(); + } + stickyViews.clear(); + findStickyViews(getChildAt(0)); + doTheStickyThing(); + invalidate(); + } + + private void findStickyViews(View v) { + if (v instanceof ViewGroup) { + ViewGroup vg = (ViewGroup) v; + for (int i = 0; i < vg.getChildCount(); i++) { + String tag = getStringTagForView(vg.getChildAt(i)); + if (tag != null && tag.contains(STICKY_TAG)) { + stickyViews.add(vg.getChildAt(i)); + } else if (vg.getChildAt(i) instanceof ViewGroup) { + findStickyViews(vg.getChildAt(i)); + } + } + } else { + String tag = (String) v.getTag(); + if (tag != null && tag.contains(STICKY_TAG)) { + stickyViews.add(v); + } + } + } + + private String getStringTagForView(View v) { + Object tagObject = v.getTag(); + return String.valueOf(tagObject); + } + + private void hideView(View v) { + if (Build.VERSION.SDK_INT >= 11) { + v.setAlpha(0); + } else { + AlphaAnimation anim = new AlphaAnimation(1, 0); + anim.setDuration(0); + anim.setFillAfter(true); + v.startAnimation(anim); + } + } + + private void showView(View v) { + if (Build.VERSION.SDK_INT >= 11) { + v.setAlpha(1); + } else { + AlphaAnimation anim = new AlphaAnimation(0, 1); + anim.setDuration(0); + anim.setFillAfter(true); + v.startAnimation(anim); + } + } +} + diff --git a/app/src/main/java/com/chwl/app/luckymoney/adapter/LuckyMoneyMemberListAdapter.java b/app/src/main/java/com/chwl/app/luckymoney/adapter/LuckyMoneyMemberListAdapter.java new file mode 100644 index 0000000..c5881db --- /dev/null +++ b/app/src/main/java/com/chwl/app/luckymoney/adapter/LuckyMoneyMemberListAdapter.java @@ -0,0 +1,57 @@ +package com.chwl.app.luckymoney.adapter; + +import android.content.Context; +import android.view.View; +import android.widget.TextView; + +import com.netease.nim.uikit.common.ui.imageview.HeadImageView; +import com.chwl.app.BR; +import com.chwl.app.R; +import com.chwl.app.bindadapter.BaseAdapter; +import com.chwl.app.bindadapter.BindingViewHolder; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.family.model.FamilyModel; +import com.chwl.core.luckymoney.bean.LuckyMoneyUserInfo; + +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * Created by MadisonRong on 05/06/2018. + */ + +public class LuckyMoneyMemberListAdapter extends BaseAdapter { + + private Context context; + private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss"); + + public LuckyMoneyMemberListAdapter(Context context) { + this(R.layout.item_lucky_money_member_list, BR.memberInfo, context); + } + + public LuckyMoneyMemberListAdapter(int layoutResId, int brid, Context context) { + super(layoutResId, brid); + this.context = context; + } + + @Override + protected void convert(BindingViewHolder helper, LuckyMoneyUserInfo item) { + HeadImageView ivAvatar = helper.getView(R.id.iv_avatar); + TextView tvName = helper.getView(R.id.tv_name); + TextView timestamp = helper.getView(R.id.tv_timestamp); + TextView amount = helper.getView(R.id.tv_member_amount); + + + ImageLoadUtils.loadAvatar(context, item.getAvatar(), ivAvatar); + tvName.setText(item.getNick()); + timestamp.setText(simpleDateFormat.format(new Date(item.getCreateTime()))); + helper.setVisible(R.id.tv_luckiest, item.isLuckiest()); + amount.setText(String.valueOf(item.getAmount())); + helper.setText(R.id.tv_coin_name, FamilyModel.Instance().getMyFamily().getMoneyName()); + + if (this.mData != null && this.mData.size() > 0 && + this.mData.indexOf(item) == this.mData.size() - 1) { + helper.getView(R.id.diver).setVisibility(View.GONE); + } + } +} diff --git a/app/src/main/java/com/chwl/app/luckymoney/dialog/LuckyMoneyComfirmToPayDialog.java b/app/src/main/java/com/chwl/app/luckymoney/dialog/LuckyMoneyComfirmToPayDialog.java new file mode 100644 index 0000000..84427a5 --- /dev/null +++ b/app/src/main/java/com/chwl/app/luckymoney/dialog/LuckyMoneyComfirmToPayDialog.java @@ -0,0 +1,22 @@ +package com.chwl.app.luckymoney.dialog; + +import android.content.Context; +import android.view.View; + +import androidx.appcompat.app.AppCompatDialog; + +/** + * Created by MadisonRong on 17/07/2018. + */ + +public class LuckyMoneyComfirmToPayDialog extends AppCompatDialog implements View.OnClickListener { + + public LuckyMoneyComfirmToPayDialog(Context context) { + super(context); + } + + @Override + public void onClick(View v) { + // + } +} diff --git a/app/src/main/java/com/chwl/app/luckymoney/dialog/LuckyMoneyDialog.java b/app/src/main/java/com/chwl/app/luckymoney/dialog/LuckyMoneyDialog.java new file mode 100644 index 0000000..783d231 --- /dev/null +++ b/app/src/main/java/com/chwl/app/luckymoney/dialog/LuckyMoneyDialog.java @@ -0,0 +1,234 @@ +package com.chwl.app.luckymoney.dialog; + +import android.content.Context; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.util.DisplayMetrics; +import android.view.Display; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatDialog; + +import com.chwl.app.R; +import com.chwl.app.luckymoney.view.LuckyMoneyDetailActivity; +import com.chwl.app.team.viewmodel.TeamVM; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.family.bean.FamilyInfo; +import com.chwl.core.family.model.FamilyModel; +import com.chwl.core.luckymoney.bean.LuckyMoneyInfo; +import com.chwl.core.manager.IMNetEaseManager; +import com.chwl.core.share.bean.SessionType; +import com.chwl.core.team.bean.TeamEvent; +import com.chwl.core.team.model.TeamModel; +import com.chwl.core.user.UserModel; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.library.rxbus.RxBus; +import com.chwl.library.utils.SingleToastUtil; + +import io.reactivex.disposables.Disposable; + +/** + * Created by MadisonRong on 31/05/2018. + */ + +public class LuckyMoneyDialog extends AppCompatDialog implements View.OnClickListener { + + private static final String TAG = "LuckyMoneyDialog"; + + private LuckyMoneyInfo luckyMoneyInfo; + private TeamVM teamViewModel; + private FamilyInfo myFamilyInfo; + private String uuid; + private Disposable disposable; + + public LuckyMoneyDialog(@NonNull Context context, LuckyMoneyInfo luckyMoneyInfo, String uuid) { + super(context); + this.luckyMoneyInfo = luckyMoneyInfo; + this.uuid = uuid; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + Window window = getWindow(); + window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); + WindowManager.LayoutParams params = window.getAttributes(); + params.width = WindowManager.LayoutParams.WRAP_CONTENT; + WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); + Display d = windowManager.getDefaultDisplay(); + DisplayMetrics realDisplayMetrics = new DisplayMetrics(); + d.getRealMetrics(realDisplayMetrics); + params.height = WindowManager.LayoutParams.WRAP_CONTENT; + window.setAttributes(params); + window.setWindowAnimations(R.style.ErbanCommonWindowAnimationStyle); + super.onCreate(savedInstanceState); + teamViewModel = new TeamVM(); + myFamilyInfo = FamilyModel.Instance().getMyFamily(); +// dialogManager = new DialogManager(getContext()); + setCancelable(true); + setDialogContentView(luckyMoneyInfo); + } + + private void setDialogContentView(LuckyMoneyInfo luckyMoneyInfo) { + if (luckyMoneyInfo == null) return; + + switch (luckyMoneyInfo.getClaimStatus()) { + // 红包待开 + default: + case LuckyMoneyInfo.STATE_NOT_OPEN: + setContentView(R.layout.dialog_lucky_money); + findViewById(R.id.iv_close).setOnClickListener(this); + findViewById(R.id.rl_lucky_money_dialog_background).setOnClickListener(this); + break; + + // 打开红包 + case LuckyMoneyInfo.STATE_DID_OPEN: + setContentView(R.layout.dialog_lucky_money_draw); + findViewById(R.id.tv_other_operation).setOnClickListener(this); + findViewById(R.id.iv_close).setOnClickListener(this); + // 显示发送者的头像和名字 + setupAvatarAndNick(luckyMoneyInfo); + TextView amount = findViewById(R.id.tv_amount); + amount.setText(luckyMoneyInfo.getAmount() + myFamilyInfo.getMoneyName()); + break; + + // 红包已领完 + case LuckyMoneyInfo.STATE_OUT_BONUS: + setContentView(R.layout.dialog_lucky_money_out_bonus); + findViewById(R.id.iv_close).setOnClickListener(this); + findViewById(R.id.tv_other_operation).setOnClickListener(this); + // 显示发送者的头像和名字 + setupAvatarAndNick(luckyMoneyInfo); + break; + + // 红包已过期 + case LuckyMoneyInfo.STATE_OUT_DATE: + setContentView(R.layout.dialog_lucky_money_out_date); + findViewById(R.id.iv_close).setOnClickListener(this); + // 显示发送者的头像和名字 + setupAvatarAndNick(luckyMoneyInfo); + break; + } + } + + private void setupAvatarAndNick(LuckyMoneyInfo luckyMoneyInfo) { + ImageView userAvatar = findViewById(R.id.iv_avatar); + ImageLoadUtils.loadAvatar(getContext(), luckyMoneyInfo.getAvatar(), userAvatar); + TextView userName = findViewById(R.id.tv_user_name); + userName.setText(luckyMoneyInfo.getNick()); + } + + private void init(View view) { + // + } + + @Override + protected void onStop() { + super.onStop(); + if (disposable != null && !disposable.isDisposed()) { + disposable.dispose(); + } + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.rl_lucky_money_dialog_background: + // 请求服务器 API 进行开红包 + if (luckyMoneyInfo.getClaimStatus() == LuckyMoneyInfo.STATE_NOT_OPEN) { + disposable = teamViewModel.receiveLuckyMoney(String.valueOf(luckyMoneyInfo.getId())) + .subscribe((luckyMoneyInfoServiceResult, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + } else { + if (luckyMoneyInfoServiceResult.isSuccess()) { + LuckyMoneyInfo respLuckyMoneyInfo = luckyMoneyInfoServiceResult.getData(); + luckyMoneyInfo.setClaimStatus(respLuckyMoneyInfo.getClaimStatus()); + switch (respLuckyMoneyInfo.getClaimStatus()) { + case LuckyMoneyInfo.STATE_DID_OPEN: + if (respLuckyMoneyInfo.getAmount() != 0) { + String uid = String.valueOf(AuthModel.get().getCurrentUid()); + UserInfo cacheLoginUserInfo = UserModel.get().getCacheLoginUserInfo(); + String nick = cacheLoginUserInfo != null ? cacheLoginUserInfo.getNick() : ""; + luckyMoneyInfo.setAmount(respLuckyMoneyInfo.getAmount()); + luckyMoneyInfo.setClaimStatus(LuckyMoneyInfo.STATE_DID_OPEN); + respLuckyMoneyInfo.setReceiveNick(nick); + respLuckyMoneyInfo.setReceiveUid(uid); + respLuckyMoneyInfo.setUid(Integer.parseInt(uid)); + respLuckyMoneyInfo.setSenderUid(luckyMoneyInfo.getSenderUid()); + respLuckyMoneyInfo.setNick(luckyMoneyInfo.getNick()); + respLuckyMoneyInfo.setClaimStatus(LuckyMoneyInfo.STATE_DID_OPEN); + respLuckyMoneyInfo.setAvatar(luckyMoneyInfo.getAvatar()); + respLuckyMoneyInfo.setTId(luckyMoneyInfo.getTId()); + IMNetEaseManager.get().receiveLuckyMoneyMessage(SessionType.TEAM, + TeamModel.get().getCurrentTeamInfo().getTid(), uid, respLuckyMoneyInfo); + setDialogContentView(luckyMoneyInfo); + } else { + dismiss(); + openLuckyMoneyDetail(); + return; + } + break; + + case LuckyMoneyInfo.STATE_OUT_BONUS: + break; + + case LuckyMoneyInfo.STATE_OUT_DATE: + break; + } + updateLuckyMoneyInfo(respLuckyMoneyInfo.getClaimStatus()); + IMNetEaseManager.get().updateLuckyMoneyMessage(uuid, luckyMoneyInfo); + // 刷新界面 + RxBus.get().post(new TeamEvent().setOperation(TeamEvent.OP_UPDATE_MSG).setMsgUuid(uuid)); + } else { + switch (luckyMoneyInfoServiceResult.getCode()) { + case LuckyMoneyInfo.LUCKY_MONEY_HAS_EXPIRED: + updateLuckyMoneyInfo(LuckyMoneyInfo.STATE_OUT_DATE); + break; + + case LuckyMoneyInfo.LUCKY_MONEY_HAS_GONE: + updateLuckyMoneyInfo(LuckyMoneyInfo.STATE_OUT_BONUS); + break; + + case LuckyMoneyInfo.LUCKY_MONEY_HAS_TOKEN: + openLuckyMoneyDetail(); + break; + + case LuckyMoneyInfo.LUCKY_MONEY_NOT_EXIST: + break; + default: + SingleToastUtil.showToast(luckyMoneyInfoServiceResult.getMessage()); + break; + } + } + } + }); + } + break; + + case R.id.iv_close: + dismiss(); + break; + + case R.id.tv_other_operation: + openLuckyMoneyDetail(); + break; + } + } + + private void updateLuckyMoneyInfo(int stateOutBonus) { + luckyMoneyInfo.setClaimStatus(stateOutBonus); + setDialogContentView(luckyMoneyInfo); + } + + private void openLuckyMoneyDetail() { + dismiss(); + LuckyMoneyDetailActivity.start(getContext(), luckyMoneyInfo.getId()); + } +} diff --git a/app/src/main/java/com/chwl/app/luckymoney/view/LuckyMoneyCreationActivity.java b/app/src/main/java/com/chwl/app/luckymoney/view/LuckyMoneyCreationActivity.java new file mode 100644 index 0000000..bbe7b2f --- /dev/null +++ b/app/src/main/java/com/chwl/app/luckymoney/view/LuckyMoneyCreationActivity.java @@ -0,0 +1,322 @@ +package com.chwl.app.luckymoney.view; + +import android.content.Context; +import android.content.Intent; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.View; +import android.widget.EditText; + +import androidx.core.content.ContextCompat; + +import com.netease.nimlib.sdk.NIMClient; +import com.netease.nimlib.sdk.team.TeamService; +import com.netease.nimlib.sdk.team.model.Team; +import com.netease.nimlib.sdk.team.model.TeamMember; +import com.trello.rxlifecycle3.android.ActivityEvent; +import com.chwl.app.R; +import com.chwl.app.base.BaseBindingActivity; +import com.chwl.app.base.TitleBar; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.app.databinding.ActivityLuckyMoneyCreationBinding; +import com.chwl.app.team.viewmodel.TeamVM; +import com.chwl.app.ui.pay.ChargeActivity; +import com.chwl.app.ui.webview.CommonWebViewActivity; +import com.chwl.core.Constants; +import com.chwl.core.UriProvider; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.family.bean.FamilyInfo; +import com.chwl.core.family.model.FamilyModel; +import com.chwl.core.manager.IMNetEaseManager; +import com.chwl.core.share.bean.SessionType; +import com.chwl.core.team.bean.TeamInfo; +import com.chwl.core.team.model.TeamModel; +import com.chwl.core.user.UserModel; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.core.utils.net.BalanceNotEnoughExeption; +import com.chwl.library.annatation.ActLayoutRes; +import com.chwl.library.common.util.DeviceUtil; +import com.chwl.library.utils.AppMetaDataUtil; +import com.chwl.library.utils.JavaUtil; +import com.chwl.library.utils.ResUtil; + +import java.util.Objects; + +import io.reactivex.SingleObserver; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.schedulers.Schedulers; + +/** + * Created by MadisonRong on 05/06/2018. + */ +@ActLayoutRes(R.layout.activity_lucky_money_creation) +public class LuckyMoneyCreationActivity extends BaseBindingActivity + implements View.OnClickListener, TextWatcher { + + private static final int DECIMAL_DIGITS = 2; + private FamilyInfo myFamilyInfo; + private TeamInfo teamInfo; + private TeamVM teamViewModel; + private double redPacketRate; + + public static void start(Context context) { + Intent intent = new Intent(context, LuckyMoneyCreationActivity.class); + context.startActivity(intent); + } + + @Override + protected void init() { + initTitleBar(getString(R.string.title_lucky_money_creation)); + + myFamilyInfo = FamilyModel.Instance().getMyFamily(); + teamViewModel = new TeamVM(); + teamInfo = TeamModel.get().getCurrentTeamInfo(); + + redPacketRate = myFamilyInfo.getRedPacketRate() * 100; + mBinding.tvCoinName.setText(myFamilyInfo.getMoneyName()); + mBinding.tvDisplayCoinName.setText(myFamilyInfo.getMoneyName()); + mBinding.tvFamilyMemberCount.setText(getString(R.string.text_total_family_member, + String.valueOf(teamInfo.getMemberCount()))); + updateRemainCoin(); + mBinding.tvLuckyMoneyRate.setText( + getString(R.string.tips_lucky_money_service_interest_rate, redPacketRate + "%")); + resetLuckyMoneyAmountAndFee(); + mBinding.tvLuckyMoneyReturnBack.setText(getString(R.string.tips_lucky_money_return_back, myFamilyInfo.getMoneyName())); + mBinding.etLuckyMoneyAmount.addTextChangedListener(this); + mBinding.etLuckyMoneyCount.addTextChangedListener(this); + mBinding.setClick(this); + + requestFamilyInfo(); + refreshFamilyCurrencyAmount(String.valueOf(AuthModel.get().getCurrentUid())); + } + + /** + * 这里获取家族信息,决定是否能使用家族币 + */ + private void requestFamilyInfo() { + if (FamilyModel.Instance().getMyFamily() == null) { + return; + } + FamilyModel.Instance().loadFamilySimpleInfo( + FamilyModel.Instance().getMyFamily().getFamilyId() + ) + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onSuccess(FamilyInfo familyInfo) { + if (!familyInfo.isOpenMoney()) { + toast(ResUtil.getString(R.string.luckymoney_view_luckymoneycreationactivity_01)); + finish(); + } + } + + @Override + public void onError(Throwable e) { + + } + }); + } + + @Override + public void initTitleBar(String title) { + mTitleBar = (TitleBar) findViewById(R.id.title_bar); + if (mTitleBar != null) { + mTitleBar.setTitle(title); + mTitleBar.setImmersive(false); + mTitleBar.setBackgroundColor(ContextCompat.getColor(this, R.color.color_ff5454)); + mTitleBar.setTitleColor(getResources().getColor(R.color.white)); + mTitleBar.setLeftImageResource(R.drawable.icon_nav_back); + mTitleBar.setLeftClickListener(v -> onLeftClickListener()); + } + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + // + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + EditText editText = mBinding.etLuckyMoneyAmount; + if (editText.isFocused()) { + // 限制红包金额最多只能输入一个小数点以及两个小数 + if (s.toString().contains(".")) { + if (s.length() - 1 - s.toString().indexOf(".") > DECIMAL_DIGITS) { + s = s.toString().subSequence(0, + s.toString().indexOf(".") + DECIMAL_DIGITS + 1); + editText.setText(s); + editText.setSelection(s.length()); + } + } + if (s.toString().trim().substring(0).equals(".")) { + s = "0" + s; + editText.setText(s); + editText.setSelection(2); + } + if (s.toString().startsWith("0") + && s.toString().trim().length() > 1) { + if (!s.toString().substring(1, 2).equals(".")) { + editText.setText(s.subSequence(0, 1)); + editText.setSelection(1); + return; + } + } + } + } + + @Override + public void afterTextChanged(Editable s) { + if (mBinding.etLuckyMoneyAmount.isFocused()) { + String amountInput = mBinding.etLuckyMoneyAmount.getText().toString(); + if (Objects.equals(amountInput, "")) { + resetLuckyMoneyAmountAndFee(); + } else { + double amountInputValue = JavaUtil.str2double(amountInput); + setLuckyMoneyAmountAndFee(amountInput, amountInputValue); + } + } + if (mBinding.etLuckyMoneyCount.isFocused()) { + String countInput = mBinding.etLuckyMoneyCount.getText().toString(); + mBinding.tvOverMemberCountTips.setVisibility(JavaUtil.str2int(countInput) > 500 ? View.VISIBLE : View.INVISIBLE); + } + } + + private void setLuckyMoneyAmountAndFee(String amountInput, double amountInputValue) { + mBinding.tvDisplayLuckyMoneyAmount.setText(amountInput); + mBinding.tvLuckyMoneyServiceFee.setText(getString(R.string.text_lucky_money_service_fee, + JavaUtil.formatDecimal(amountInputValue * myFamilyInfo.getRedPacketRate()) + myFamilyInfo.getMoneyName())); + } + + private void resetLuckyMoneyAmountAndFee() { + mBinding.tvDisplayLuckyMoneyAmount.setText(getString(R.string.hint_lucky_money_amount)); + mBinding.tvLuckyMoneyServiceFee.setText(getString(R.string.text_lucky_money_service_fee, getString(R.string.hint_lucky_money_amount) + myFamilyInfo.getMoneyName())); + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.btn_ready_to_send: + String tempAmountString = mBinding.etLuckyMoneyAmount.getText().toString(); + String tempCountString = mBinding.etLuckyMoneyCount.getText().toString(); + double amountDoubleValue = JavaUtil.str2double(tempAmountString); + double countDoubleValue = JavaUtil.str2double(tempCountString); + if (countDoubleValue <= 0 || countDoubleValue > 500) { + toast(getString(R.string.tips_lucky_money_count)); + return; + } + if (amountDoubleValue < 1) { + toast(getString(R.string.tips_lucky_money_amount) + myFamilyInfo.getMoneyName()); + return; + } + String tempFee = String.valueOf(JavaUtil.str2double(tempAmountString) + * myFamilyInfo.getRedPacketRate()); + String fee = JavaUtil.formatDecimal(JavaUtil.str2double(tempFee)); + double feeValue = JavaUtil.str2double(tempFee); + String tempRealAmountString = JavaUtil.str2double2len(String.valueOf(amountDoubleValue - feeValue)); + double amountValue = JavaUtil.str2double(tempRealAmountString); + double averageAmount = amountValue / countDoubleValue; + if (averageAmount < 0.01) { + toast(getString(R.string.tips_lucky_money_average_amount)); + return; + } + if (!Objects.equals(tempAmountString, "") && + !Objects.equals(tempCountString, "")) { + hideIME(); + getDialogManager().showLuckyMoneyConfirmToPayDialog(tempAmountString, + fee, + myFamilyInfo.getMoneyName(), + v1 -> { + getDialogManager().showProgressDialog(getApplicationContext(), ResUtil.getString(R.string.luckymoney_view_luckymoneycreationactivity_02), false); + sendLuckyMoney(); + }); + } + break; + } + } + + private void sendLuckyMoney() { + Team team = NIMClient.getService(TeamService.class).queryTeamBlock(teamInfo.getTid()); + String uid = String.valueOf(AuthModel.get().getCurrentUid()); + TeamMember teamMember = NIMClient.getService(TeamService.class).queryTeamMemberBlock(teamInfo.getTid(), uid); + if (!team.isMyTeam()) { + getDialogManager().dismissDialog(); + toast(ResUtil.getString(R.string.luckymoney_view_luckymoneycreationactivity_03)); + return; + } + if (teamMember.isMute()) { + getDialogManager().dismissDialog(); + toast(ResUtil.getString(R.string.luckymoney_view_luckymoneycreationactivity_04)); + return; + } + String message = mBinding.etLuckyMoneyGreetings.getEditableText().toString(); + if (Objects.equals(message, "")) { + message = getString(R.string.hint_lucky_money_greetings); + } + teamViewModel.sendLuckyMoney(teamInfo.getTid(), + Double.parseDouble(mBinding.etLuckyMoneyAmount.getText().toString()), + Integer.parseInt(mBinding.etLuckyMoneyCount.getText().toString()), + message) + .compose(bindToLifecycle()) + .subscribe((luckyMoneyInfo, throwable) -> { + getDialogManager().dismissDialog(); + if (throwable != null) { + throwable.printStackTrace(); + toast(throwable.getMessage()); + if (throwable instanceof BalanceNotEnoughExeption) { + getDialogManager().showOkCancelDialog(ResUtil.getString(R.string.luckymoney_view_luckymoneycreationactivity_05), + true, new DialogManager.AbsOkDialogListener() { + @Override + public void onOk() { +// if (AppMetaDataUtil.getChannelID().equals(Constants.GOOGLE)) { + ChargeActivity.start(LuckyMoneyCreationActivity.this); +// } else { +// CommonWebViewActivity.start( +// context, UriProvider.getOfficialPay( +// 4, +// DeviceUtil.getDeviceId(context) +// ) +// ); +// } + } + }); + + } + } else { + luckyMoneyInfo.setUid(Integer.parseInt(uid)); + UserInfo userInfo = UserModel.get().getCacheLoginUserInfo(); + if (userInfo != null) { + luckyMoneyInfo.setAvatar(userInfo.getAvatar()); + luckyMoneyInfo.setNick(userInfo.getNick()); + } + IMNetEaseManager.get().sendLuckyMoneyMessage(SessionType.TEAM, teamInfo.getTid(), uid, luckyMoneyInfo); + finish(); + } + }); + } + + private void refreshFamilyCurrencyAmount(String uid) { + FamilyModel.Instance().refreshFamilyCurrencyAmount() + .compose(bindToLifecycle()) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe((familyInfo, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + } else { + FamilyModel.Instance().getMyFamily().setFamilyMoney(familyInfo.getFamilyMoney()); + updateRemainCoin(); + } + }); + } + + private void updateRemainCoin() { + mBinding.tvRemainCoin.setText(myFamilyInfo.getMoneyName() + getString(R.string.text_lucky_money_remain_coin, + String.valueOf(myFamilyInfo.getFamilyMoney()))); + } +} diff --git a/app/src/main/java/com/chwl/app/luckymoney/view/LuckyMoneyDetailActivity.java b/app/src/main/java/com/chwl/app/luckymoney/view/LuckyMoneyDetailActivity.java new file mode 100644 index 0000000..70a86bc --- /dev/null +++ b/app/src/main/java/com/chwl/app/luckymoney/view/LuckyMoneyDetailActivity.java @@ -0,0 +1,130 @@ +package com.chwl.app.luckymoney.view; + +import android.content.Context; +import android.content.Intent; +import android.view.View; + +import androidx.core.content.ContextCompat; +import androidx.recyclerview.widget.LinearLayoutManager; + +import com.chwl.app.R; +import com.chwl.app.base.BaseBindingActivity; +import com.chwl.app.base.TitleBar; +import com.chwl.app.databinding.ActivityLuckyMoneyDetailBinding; +import com.chwl.app.luckymoney.adapter.LuckyMoneyMemberListAdapter; +import com.chwl.app.team.viewmodel.TeamVM; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.family.bean.FamilyInfo; +import com.chwl.core.family.model.FamilyModel; +import com.chwl.core.luckymoney.bean.LuckyMoneyInfo; +import com.chwl.core.luckymoney.bean.LuckyMoneyUserInfo; +import com.chwl.core.user.UserModel; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.library.annatation.ActLayoutRes; +import com.chwl.library.utils.FormatUtils; +import com.chwl.library.utils.ListUtils; + +import java.util.List; +import java.util.Objects; + +/** + * Created by MadisonRong on 05/06/2018. + */ +@ActLayoutRes(R.layout.activity_lucky_money_detail) +public class LuckyMoneyDetailActivity extends BaseBindingActivity { + + public static final String EXTRA_LUCKY_MONEY_ID = "EXTRA_LUCKY_MONEY_ID"; + + private LuckyMoneyMemberListAdapter adapter; + private TeamVM teamViewModel; + private FamilyInfo myFamilyInfo; + private int luckyMoneyId; + + public static void start(Context context, int luckyMoneyId) { + Intent intent = new Intent(context, LuckyMoneyDetailActivity.class); + intent.putExtra(EXTRA_LUCKY_MONEY_ID, luckyMoneyId); + context.startActivity(intent); + } + + @Override + protected void init() { + initTitleBar(getString(R.string.action_red_packet)); + + teamViewModel = new TeamVM(); + myFamilyInfo = FamilyModel.Instance().getMyFamily(); + luckyMoneyId = getIntent().getIntExtra(EXTRA_LUCKY_MONEY_ID, -1); + + adapter = new LuckyMoneyMemberListAdapter(this); + mBinding.recyclerView.setAdapter(adapter); + mBinding.recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)); + + showLoading(); + } + + @Override + protected void onResume() { + super.onResume(); + teamViewModel.receiveLuckyMoneyRecords(String.valueOf(luckyMoneyId)) + .compose(bindToLifecycle()) + .subscribe((luckyMoneyRecordsInfo, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + } else { + boolean result = false; + LuckyMoneyUserInfo myself = null; + UserInfo cacheLoginUserInfo = UserModel.get().getCacheLoginUserInfo(); + LuckyMoneyInfo luckyMoneyInfo = luckyMoneyRecordsInfo.getRedPacket(); + mBinding.tvLuckyMoneyGreeting.setText(luckyMoneyInfo.getMessage()); + List records = luckyMoneyRecordsInfo.getRecords(); + if (cacheLoginUserInfo != null) { + for (LuckyMoneyUserInfo record : records) { + if (Objects.equals(record.getUid(), String.valueOf(cacheLoginUserInfo.getUid()))) { + result = true; + myself = record; + break; + } + } + mBinding.llAmount.setVisibility(result ? View.VISIBLE : View.GONE); + mBinding.tvLuckyMoneyTips.setVisibility(result ? View.GONE : View.VISIBLE); + if (result) { + mBinding.tvLuckyMoneyAmount.setText(String.valueOf(myself.getAmount())); + mBinding.tvCoinName.setText(myFamilyInfo.getMoneyName()); + } + ImageLoadUtils.loadAvatar(this, cacheLoginUserInfo.getAvatar(), mBinding.ivAvatar); + mBinding.tvName.setText(cacheLoginUserInfo.getNick()); + } + + //这里保留两位精度,需要计算到第三位 + int amount = (int) (luckyMoneyInfo.getAmount() * 1000); + int claimedAmount = (int) (luckyMoneyInfo.getClaimedAmount() * 1000); + int fee = (int) (luckyMoneyInfo.getFee() * 1000); + double resTemp = (amount - claimedAmount - fee) / 1000.0f; + String restAmount = FormatUtils.formatBigDecimal(resTemp); + mBinding.tvSubTitleLuckyMoneyDetail.setText(String.format(getString(R.string.text_lucky_money_sub_title_detail), + String.valueOf(luckyMoneyInfo.getClaimedNum()), + String.valueOf(luckyMoneyInfo.getNum()), + restAmount + myFamilyInfo.getMoneyName())); + if (!ListUtils.isListEmpty(records)) { + hideStatus(); + adapter.setNewData(records); + adapter.notifyDataSetChanged(); + } else { + showNoData(); + } + } + }); + } + + @Override + public void initTitleBar(String title) { + mTitleBar = (TitleBar) findViewById(R.id.title_bar); + if (mTitleBar != null) { + mTitleBar.setTitle(title); + mTitleBar.setImmersive(false); + mTitleBar.setBackgroundColor(ContextCompat.getColor(this, R.color.color_ff5454)); + mTitleBar.setTitleColor(getResources().getColor(R.color.white)); + mTitleBar.setLeftImageResource(R.drawable.icon_nav_back); + mTitleBar.setLeftClickListener(v -> onLeftClickListener()); + } + } +} diff --git a/app/src/main/java/com/chwl/app/luckymoney/viewholder/LuckyMoneyMsgViewHolder.java b/app/src/main/java/com/chwl/app/luckymoney/viewholder/LuckyMoneyMsgViewHolder.java new file mode 100644 index 0000000..376547c --- /dev/null +++ b/app/src/main/java/com/chwl/app/luckymoney/viewholder/LuckyMoneyMsgViewHolder.java @@ -0,0 +1,126 @@ +package com.chwl.app.luckymoney.viewholder; + +import android.util.Log; +import android.view.View; +import android.widget.TextView; + +import com.netease.nim.uikit.business.session.viewholder.MsgViewHolderBase; +import com.netease.nim.uikit.common.ui.recyclerview.adapter.BaseMultiItemFetchLoadAdapter; +import com.netease.nimlib.sdk.NIMClient; +import com.netease.nimlib.sdk.msg.model.IMMessage; +import com.netease.nimlib.sdk.team.TeamService; +import com.netease.nimlib.sdk.team.model.Team; +import com.chwl.app.R; +import com.chwl.app.luckymoney.dialog.LuckyMoneyDialog; +import com.chwl.app.luckymoney.view.LuckyMoneyDetailActivity; +import com.chwl.core.im.custom.bean.LuckyMoneyAttachment; +import com.chwl.core.luckymoney.bean.LuckyMoneyInfo; +import com.chwl.core.manager.IMNetEaseManager; +import com.chwl.core.team.bean.TeamInfo; +import com.chwl.core.team.model.TeamModel; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; + +import java.util.Objects; + +/** + * Created by MadisonRong on 31/05/2018. + */ + +public class LuckyMoneyMsgViewHolder extends MsgViewHolderBase implements View.OnClickListener { + + private static final String TAG = "LuckyMoneyMsgViewHolder"; + + private View layout; + private TextView greetingView; + private LuckyMoneyInfo luckyMoneyInfo; + + public LuckyMoneyMsgViewHolder(BaseMultiItemFetchLoadAdapter adapter) { + super(adapter); + } + + @Override + public void onClick(View v) { + TeamInfo teamInfo = TeamModel.get().getCurrentTeamInfo(); + if (teamInfo == null) { + return; + } + Team team = NIMClient.getService(TeamService.class) + .queryTeamBlock(TeamModel.get().getCurrentTeamInfo().getTid()); + if (team != null && team.isMyTeam()) { + if (luckyMoneyInfo.getClaimStatus() == LuckyMoneyInfo.STATE_DID_OPEN) { + LuckyMoneyDetailActivity.start(context, luckyMoneyInfo.getId()); + } else { + // 打开群红包弹窗 + new LuckyMoneyDialog(context, luckyMoneyInfo, message.getUuid()).show(); + } + } else { + SingleToastUtil.showToast(ResUtil.getString(R.string.luckymoney_viewholder_luckymoneymsgviewholder_01)); + } + } + + @Override + protected int getContentResId() { + return R.layout.layout_msg_view_holder_lucky_money; + } + + @Override + protected void inflateContentView() { + layout = findViewById(R.id.rl_lucky_money_msg_view_holder); + greetingView = findViewById(R.id.tv_lucky_money_greeting); + IMMessage luckyMoneyMessage = IMNetEaseManager.get().queryMessageByUuid(message.getUuid()); + Log.e(TAG, "inflateContentView: lucky money message: " + luckyMoneyMessage); + LuckyMoneyAttachment luckyMoneyAttachment; + if (luckyMoneyMessage == null) { + luckyMoneyAttachment = (LuckyMoneyAttachment) message.getAttachment(); + IMNetEaseManager.get().saveMessageToLocal(message); + luckyMoneyInfo = luckyMoneyAttachment.getLuckyMoneyInfo(); + if (luckyMoneyInfo.getClaimStatus() == 0) { + luckyMoneyInfo.setClaimStatus(luckyMoneyInfo.getStatus()); + } + message.setLocalExtension(LuckyMoneyInfo.convertToMap(luckyMoneyInfo)); + IMNetEaseManager.get().updateLuckyMoneyMessage(message.getUuid(), luckyMoneyInfo); + } else { + luckyMoneyAttachment = (LuckyMoneyAttachment) luckyMoneyMessage.getAttachment(); + if (luckyMoneyMessage.getLocalExtension() == null) { + luckyMoneyInfo = luckyMoneyAttachment.getLuckyMoneyInfo(); + } else { + luckyMoneyInfo = LuckyMoneyInfo.convertMapToObject(luckyMoneyMessage.getLocalExtension()); + } + if (luckyMoneyInfo.getClaimStatus() == 0) { + luckyMoneyInfo.setClaimStatus(luckyMoneyInfo.getStatus()); + } + luckyMoneyMessage.setLocalExtension(LuckyMoneyInfo.convertToMap(luckyMoneyInfo)); + IMNetEaseManager.get().updateLuckyMoneyMessage(luckyMoneyMessage.getUuid(), luckyMoneyInfo); + } + Log.e(TAG, "inflateContentView: message: " + message.getUuid()); + Log.e(TAG, "inflateContentView: attachment:" + luckyMoneyInfo); + if (luckyMoneyInfo.getMessage() != null && !Objects.equals("", luckyMoneyInfo.getMessage())) { + greetingView.setText(luckyMoneyInfo.getMessage()); + } + layout.setOnClickListener(this); + } + + @Override + protected void bindContentView() { + Log.e(TAG, "bindContentView: "); + } + + @Override + protected int leftBackground() { + if (luckyMoneyInfo.getClaimStatus() == LuckyMoneyInfo.STATE_NOT_OPEN) { + return R.drawable.lucky_money_msg_undraw; + } else { + return R.drawable.lucky_money_msg_draw; + } + } + + @Override + protected int rightBackground() { + if (luckyMoneyInfo.getClaimStatus() == LuckyMoneyInfo.STATE_NOT_OPEN) { + return R.drawable.lucky_money_msg_undraw; + } else { + return R.drawable.lucky_money_msg_draw; + } + } +} diff --git a/app/src/main/java/com/chwl/app/luckymoney/viewholder/LuckyMoneyTipsViewHolder.java b/app/src/main/java/com/chwl/app/luckymoney/viewholder/LuckyMoneyTipsViewHolder.java new file mode 100644 index 0000000..10c714c --- /dev/null +++ b/app/src/main/java/com/chwl/app/luckymoney/viewholder/LuckyMoneyTipsViewHolder.java @@ -0,0 +1,89 @@ +package com.chwl.app.luckymoney.viewholder; + +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.style.ForegroundColorSpan; +import android.util.Log; +import android.widget.TextView; + +import androidx.core.content.ContextCompat; + +import com.netease.nim.uikit.business.session.viewholder.MsgViewHolderBase; +import com.netease.nim.uikit.common.ui.recyclerview.adapter.BaseMultiItemFetchLoadAdapter; +import com.chwl.app.R; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.im.custom.bean.LuckyMoneyTipsAttachment; +import com.chwl.core.luckymoney.bean.LuckyMoneyInfo; +import com.chwl.library.utils.ResUtil; + +import java.util.Objects; + +/** + * Created by MadisonRong on 02/07/2018. + */ + +public class LuckyMoneyTipsViewHolder extends MsgViewHolderBase { + + private static final String TAG = "LuckyMoneyTipsViewHolde"; + + public LuckyMoneyTipsViewHolder(BaseMultiItemFetchLoadAdapter adapter) { + super(adapter); + } + + @Override + protected boolean isShowHeadImage() { + return false; + } + + @Override + protected boolean isMiddleItem() { + return true; + } + + @Override + protected boolean isShowBubble() { + return false; + } + + @Override + protected int getContentResId() { + return R.layout.layout_msg_view_holder_lucky_money_receive; + } + + @Override + protected void inflateContentView() { + TextView tipsView = findViewById(R.id.tv_lucky_money_tips); + LuckyMoneyTipsAttachment luckyMoneyAttachment = (LuckyMoneyTipsAttachment) message.getAttachment(); + LuckyMoneyInfo luckyMoneyInfo = luckyMoneyAttachment.getLuckyMoneyInfo(); + String uid = String.valueOf(AuthModel.get().getCurrentUid()); + Log.e(TAG, "inflateContentView: -----------------"); + Log.e(TAG, "inflateContentView: currentUid: " + uid); + Log.e(TAG, "inflateContentView: senderUid: " + luckyMoneyInfo.getSenderUid()); + Log.e(TAG, "inflateContentView: receiveUid: " + luckyMoneyInfo.getReceiveUid()); + Log.e(TAG, "inflateContentView: -----------------"); + if (Objects.equals(uid, String.valueOf(luckyMoneyInfo.getReceiveUid()))) { + SpannableStringBuilder builder = new SpannableStringBuilder(); + String content = String.format(ResUtil.getString(R.string.luckymoney_viewholder_luckymoneytipsviewholder_01), luckyMoneyInfo.getNick()); + builder.append(content); + builder.setSpan(new ForegroundColorSpan( + ContextCompat.getColor(context, R.color.color_fe555a)), + content.length() - 2, content.length(), + Spanned.SPAN_EXCLUSIVE_INCLUSIVE); + tipsView.setText(builder); + } else if (Objects.equals(uid, String.valueOf(luckyMoneyInfo.getSenderUid()))) { + SpannableStringBuilder builder = new SpannableStringBuilder(); + String content = String.format(ResUtil.getString(R.string.luckymoney_viewholder_luckymoneytipsviewholder_02), luckyMoneyInfo.getReceiveNick()); + builder.append(content); + builder.setSpan(new ForegroundColorSpan( + ContextCompat.getColor(context, R.color.color_fe555a)), + content.length() - 2, content.length(), + Spanned.SPAN_EXCLUSIVE_INCLUSIVE); + tipsView.setText(builder); + } + } + + @Override + protected void bindContentView() { + + } +} diff --git a/app/src/main/java/com/chwl/app/module/Extras.java b/app/src/main/java/com/chwl/app/module/Extras.java new file mode 100644 index 0000000..4ba2ad6 --- /dev/null +++ b/app/src/main/java/com/chwl/app/module/Extras.java @@ -0,0 +1,16 @@ +package com.chwl.app.module; + +public interface Extras { + + String EXTRA_JUMP_P2P = "EXTRA_JUMP_P2P"; + + String EXTRA_DATA = "data"; + + String EXTRA_FROM = "from"; + + String EXTRA_FROM_NOTIFICATION = "from_notification"; + + // 参数 + String EXTRA_ACCOUNT = "account"; + +} diff --git a/app/src/main/java/com/chwl/app/module/IRoomNewbieMessageView.java b/app/src/main/java/com/chwl/app/module/IRoomNewbieMessageView.java new file mode 100644 index 0000000..84c060b --- /dev/null +++ b/app/src/main/java/com/chwl/app/module/IRoomNewbieMessageView.java @@ -0,0 +1,9 @@ +package com.chwl.app.module; + +import com.chwl.core.bean.RoomNewbieMessageInfo; +import com.chwl.library.base.IMvpBaseView; + +public interface IRoomNewbieMessageView extends IMvpBaseView { + void getRoomNewbieMessageSuccess(RoomNewbieMessageInfo info); + void getRoomNewbieMessageFails(String error); +} diff --git a/app/src/main/java/com/chwl/app/module/IRoomNewbieView.java b/app/src/main/java/com/chwl/app/module/IRoomNewbieView.java new file mode 100644 index 0000000..0318126 --- /dev/null +++ b/app/src/main/java/com/chwl/app/module/IRoomNewbieView.java @@ -0,0 +1,14 @@ +package com.chwl.app.module; + +import com.chwl.core.bean.RoomNewbieInfo; +import com.chwl.library.base.IMvpBaseView; + +import java.util.List; + +public interface IRoomNewbieView extends IMvpBaseView { + void getRoomNewbieSuccess(List list); + void getRoomNewbieFails(String error); + void getRoomNewbieLoadMoreSuccess(List list); + void getRoomNewbieLoadMoreFails(String error); + +} diff --git a/app/src/main/java/com/chwl/app/module/RoomNewbieModel.java b/app/src/main/java/com/chwl/app/module/RoomNewbieModel.java new file mode 100644 index 0000000..b38817e --- /dev/null +++ b/app/src/main/java/com/chwl/app/module/RoomNewbieModel.java @@ -0,0 +1,103 @@ +package com.chwl.app.module; + +import com.chwl.core.auth.AuthModel; +import com.chwl.core.bean.RoomNewbieInfo; +import com.chwl.core.bean.RoomNewbieMessageInfo; +import com.chwl.core.bean.response.ServiceResult; +import com.chwl.core.community.CommunityConstant; +import com.chwl.core.utils.net.RxHelper; +import com.chwl.library.net.rxnet.RxNet; + +import org.json.JSONObject; + +import java.util.List; + +import io.reactivex.Single; +import retrofit2.http.GET; +import retrofit2.http.POST; +import retrofit2.http.Query; + +public class RoomNewbieModel { + + private final Api api = RxNet.create(Api.class); + + public Single> getRoomNewbieList(int page,int pageSize) { + return api.apiNewbieList(String.valueOf(AuthModel.get().getCurrentUid()), + CommunityConstant.VERSION_VALID_TYPE, + AuthModel.get().getTicket(), + page, + pageSize) + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()); + } + + public Single sayHello(int helloUid, String message) { + return api.apiHello(String.valueOf(AuthModel.get().getCurrentUid()), + CommunityConstant.VERSION_VALID_TYPE, + AuthModel.get().getTicket(), + helloUid, + message) + .compose(RxHelper.handleSchedulers()); + } + + public Single getMessageList(int start, int pageSize) { + return api.apiMessageList(String.valueOf(AuthModel.get().getCurrentUid()), + CommunityConstant.VERSION_VALID_TYPE, + AuthModel.get().getTicket(), + start, + pageSize) + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()); + } + + private static final class Helper { + public static final RoomNewbieModel INSTANCE = new RoomNewbieModel(); + } + + public static RoomNewbieModel get() { + return RoomNewbieModel.Helper.INSTANCE; + } + + + private interface Api { + + /** + * 首页动态 + * + * @return - + */ + @GET("/newbie/poolList") + Single>> apiNewbieList( + @Query("uid") String uid, + @Query("types") String types, + @Query("ticket") String ticket, + @Query("page") int page, + @Query("pageSize") int pageSize); + + /** + * 首页动态 + * + * @return - + */ + @POST("/newbie/hello") + Single apiHello( + @Query("uid") String uid, + @Query("types") String types, + @Query("ticket") String ticket, + @Query("helloUid") int helloUid, + @Query("message") String message); + + /** + * 首页动态 + * + * @return - + */ + @GET("/newbie/messageList") + Single> apiMessageList( + @Query("uid") String uid, + @Query("types") String types, + @Query("ticket") String ticket, + @Query("start") int start, + @Query("pageSize") int pageSize); + } +} diff --git a/app/src/main/java/com/chwl/app/monsterhunting/ImpactValueLayout.java b/app/src/main/java/com/chwl/app/monsterhunting/ImpactValueLayout.java new file mode 100644 index 0000000..8c072c6 --- /dev/null +++ b/app/src/main/java/com/chwl/app/monsterhunting/ImpactValueLayout.java @@ -0,0 +1,71 @@ +package com.chwl.app.monsterhunting; + +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.RelativeLayout; + +import com.chwl.app.R; +import com.chwl.app.ui.gift.widget.StrokeTextView; +import com.chwl.library.animator.AbstractPathAnimator; +import com.chwl.library.animator.PathAnimator; + +public class ImpactValueLayout extends RelativeLayout { + + private AbstractPathAnimator mAnimator; + + public ImpactValueLayout(Context context) { + super(context); + init(null, 0); + } + + public ImpactValueLayout(Context context, AttributeSet attrs) { + super(context, attrs); + init(attrs, 0); + } + + public ImpactValueLayout(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(attrs, defStyleAttr); + } + + private void init(AttributeSet attrs, int defStyleAttr) { + + final TypedArray a = getContext().obtainStyledAttributes( + attrs, R.styleable.HeartLayout, defStyleAttr, 0); + + mAnimator = new PathAnimator(AbstractPathAnimator.Config.fromTypeArray(a)); + + a.recycle(); + } + + public AbstractPathAnimator getAnimator() { + return mAnimator; + } + + public void setAnimator(AbstractPathAnimator animator) { + clearAnimation(); + mAnimator = animator; + } + + public void clearAnimation() { + for (int i = 0; i < getChildCount(); i++) { + getChildAt(i).clearAnimation(); + } + removeAllViews(); + } + + public void addImpact(int impactValue) { + View view = LayoutInflater.from(getContext()).inflate(R.layout.monster_impact_value_view, null); + StrokeTextView impactValueView = view.findViewById(R.id.room_monster_impact_value); + LayoutParams layoutParams= new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT); + layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT,RelativeLayout.TRUE); + impactValueView.setLayoutParams(layoutParams); + impactValueView.setText("-" + String.valueOf(impactValue)); + mAnimator.start(impactValueView, this); + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/monsterhunting/MonsterEscapeDialog.java b/app/src/main/java/com/chwl/app/monsterhunting/MonsterEscapeDialog.java new file mode 100644 index 0000000..e56d681 --- /dev/null +++ b/app/src/main/java/com/chwl/app/monsterhunting/MonsterEscapeDialog.java @@ -0,0 +1,80 @@ +package com.chwl.app.monsterhunting; + +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.DialogFragment; +import androidx.fragment.app.FragmentManager; + +import com.chwl.app.R; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.monsterhunting.bean.MonsterInfo; +import com.chwl.core.monsterhunting.manager.MonsterDataManager; + +/** + * Created by MadisonRong on 03/04/2018. + */ + +public class MonsterEscapeDialog extends DialogFragment implements View.OnClickListener { + + private static final String TAG = "MonsterEscapeDialog"; + + private ImageView monsterImageView; + private TextView confirmView; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + Window window = getDialog().getWindow(); + // setup window and width + View view = inflater.inflate(R.layout.dialog_monster_escape, window.findViewById(android.R.id.content), false); + window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); +// window.setLayout(ViewGroup.LayoutParams.WRAP_CONTENT, UIUtil.dip2px(getContext(), 327)); + setCancelable(false); + init(view); + return view; + } + + private void init(View view) { + monsterImageView = view.findViewById(R.id.iv_monster_image); + confirmView = view.findViewById(R.id.tv_operation_ok); + confirmView.setOnClickListener(this); + + MonsterInfo monsterInfo = MonsterDataManager.get().getCurrentRoomMonsterInfo(); + ImageLoadUtils.loadImage(getContext(), monsterInfo.getMonsterImg(), monsterImageView); + } + + public void show(FragmentManager fragmentManager) { + this.show(fragmentManager, TAG); + } + + @Override + public void show(FragmentManager manager, String tag) { + if (manager.findFragmentByTag(tag) == null) { + manager.beginTransaction() + .add(this, tag) + .commitAllowingStateLoss(); + } + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.tv_operation_ok: + dismissAllowingStateLoss(); + if (getActivity() != null) { + getActivity().finish(); + } + break; + } + } +} diff --git a/app/src/main/java/com/chwl/app/monsterhunting/MonsterHuntingAnimationManager.java b/app/src/main/java/com/chwl/app/monsterhunting/MonsterHuntingAnimationManager.java new file mode 100644 index 0000000..98b9e35 --- /dev/null +++ b/app/src/main/java/com/chwl/app/monsterhunting/MonsterHuntingAnimationManager.java @@ -0,0 +1,259 @@ +package com.chwl.app.monsterhunting; + +import android.content.Context; +import android.view.View; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.chwl.app.R; +import com.chwl.core.manager.IMNetEaseManager; +import com.chwl.core.monsterhunting.SimpleAnimationListener; +import com.chwl.core.monsterhunting.bean.MonsterEvent; + +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.processors.PublishProcessor; +import io.reactivex.schedulers.Schedulers; + +/** + * Created by MadisonRong on 03/04/2018. + */ + +public class MonsterHuntingAnimationManager { + + private PublishProcessor monsterEventPublishProcessor; + + private static class MonsterHuntingAnimationManagerHolder { + private static final MonsterHuntingAnimationManager instance = new MonsterHuntingAnimationManager(); + } + + public static MonsterHuntingAnimationManager get() { + return MonsterHuntingAnimationManagerHolder.instance; + } + + public PublishProcessor getMonsterEventObservable() { + if (monsterEventPublishProcessor == null) { + synchronized (IMNetEaseManager.class) { + if (monsterEventPublishProcessor == null) { + monsterEventPublishProcessor = PublishProcessor.create(); + monsterEventPublishProcessor.subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()); + } + } + } + return monsterEventPublishProcessor; + } + + public void monsterLayoutShowIn(Context context, RelativeLayout monsterLayout) { + Animation leftInAnimation = AnimationUtils.loadAnimation(context, R.anim.anim_left_in); + leftInAnimation.setAnimationListener(new SimpleAnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + super.onAnimationStart(animation); + getMonsterEventObservable().onNext(new MonsterEvent(MonsterEvent.MONSTER_LAYOUT_SHOW_IN_ANIMATION_START)); + } + + @Override + public void onAnimationEnd(Animation animation) { + super.onAnimationEnd(animation); + getMonsterEventObservable().onNext(new MonsterEvent(MonsterEvent.MONSTER_LAYOUT_SHOW_IN_ANIMATION_FINISHED)); + } + }); + monsterLayout.clearAnimation(); + monsterLayout.startAnimation(leftInAnimation); + } + + public void monsterLayoutShowOut(Context context, RelativeLayout monsterLayout) { + Animation leftOutAnimation = AnimationUtils.loadAnimation(context, R.anim.anim_left_out); + leftOutAnimation.setAnimationListener(new SimpleAnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + super.onAnimationStart(animation); + getMonsterEventObservable().onNext(new MonsterEvent(MonsterEvent.MONSTER_LAYOUT_SHOW_OUT_ANIMATION_START)); + } + + @Override + public void onAnimationEnd(Animation animation) { + super.onAnimationEnd(animation); + getMonsterEventObservable().onNext(new MonsterEvent(MonsterEvent.MONSTER_LAYOUT_SHOW_OUT_ANIMATION_FINISHED)); + } + }); + monsterLayout.clearAnimation(); + monsterLayout.startAnimation(leftOutAnimation); + } + + public void monsterInfoLayoutShowIn(Context context, RelativeLayout monsterInfoLayout) { + Animation leftInAnimation = AnimationUtils.loadAnimation(context, R.anim.anim_left_in); + leftInAnimation.setAnimationListener(new SimpleAnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + super.onAnimationStart(animation); + getMonsterEventObservable().onNext(new MonsterEvent(MonsterEvent.MONSTER_INFO_LAYOUT_SHOW_IN_ANIMATION_START)); + } + + @Override + public void onAnimationEnd(Animation animation) { + super.onAnimationEnd(animation); + getMonsterEventObservable().onNext(new MonsterEvent(MonsterEvent.MONSTER_INFO_LAYOUT_SHOW_IN_ANIMATION_FINISHED)); + } + }); + monsterInfoLayout.clearAnimation(); + monsterInfoLayout.startAnimation(leftInAnimation); + } + + public void monsterInfoLayoutShowOut(Context context, RelativeLayout monsterInfoLayout) { + Animation leftOutAnimation = AnimationUtils.loadAnimation(context, R.anim.anim_left_out); + leftOutAnimation.setAnimationListener(new SimpleAnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + super.onAnimationStart(animation); + getMonsterEventObservable().onNext(new MonsterEvent(MonsterEvent.MONSTER_INFO_LAYOUT_SHOW_OUT_ANIMATION_START)); + } + + @Override + public void onAnimationEnd(Animation animation) { + super.onAnimationEnd(animation); + getMonsterEventObservable().onNext(new MonsterEvent(MonsterEvent.MONSTER_INFO_LAYOUT_SHOW_OUT_ANIMATION_FINISHED)); + } + }); + monsterInfoLayout.clearAnimation(); + monsterInfoLayout.startAnimation(leftOutAnimation); + } + + public void magicLayoutShowIn(Context context, RelativeLayout magicLayout) { + Animation bottomInAnimation = AnimationUtils.loadAnimation(context, R.anim.anim_bottom_in); + bottomInAnimation.setAnimationListener(new SimpleAnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + super.onAnimationStart(animation); + getMonsterEventObservable().onNext(new MonsterEvent(MonsterEvent.MONSTER_MAGIC_LAYOUT_SHOW_IN_ANIMATION_START)); + } + + @Override + public void onAnimationEnd(Animation animation) { + super.onAnimationEnd(animation); + getMonsterEventObservable().onNext(new MonsterEvent(MonsterEvent.MONSTER_MAGIC_LAYOUT_SHOW_IN_ANIMATION_FINISHED)); + } + }); + magicLayout.clearAnimation(); + magicLayout.startAnimation(bottomInAnimation); + } + + public void magicLayoutShowOut(Context context, RelativeLayout magicLayout) { + Animation bottomOutAnimation = AnimationUtils.loadAnimation(context, R.anim.anim_bottom_out); + bottomOutAnimation.setAnimationListener(new SimpleAnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + super.onAnimationStart(animation); + getMonsterEventObservable().onNext(new MonsterEvent(MonsterEvent.MONSTER_MAGIC_LAYOUT_SHOW_OUT_ANIMATION_START)); + } + + @Override + public void onAnimationEnd(Animation animation) { + super.onAnimationEnd(animation); + getMonsterEventObservable().onNext(new MonsterEvent(MonsterEvent.MONSTER_MAGIC_LAYOUT_SHOW_OUT_ANIMATION_FINISHED)); + } + }); + magicLayout.clearAnimation(); + magicLayout.startAnimation(bottomOutAnimation); + } + + public void countDownTimerShowIn(Context context, TextView countDownTimer) { + Animation topInAnimation = AnimationUtils.loadAnimation(context, R.anim.anim_top_in); + topInAnimation.setAnimationListener(new SimpleAnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + super.onAnimationStart(animation); + getMonsterEventObservable().onNext(new MonsterEvent(MonsterEvent.MONSTER_COUNT_DOWN_SHOW_IN_ANIMATION_START)); + } + + @Override + public void onAnimationEnd(Animation animation) { + super.onAnimationEnd(animation); + getMonsterEventObservable().onNext(new MonsterEvent(MonsterEvent.MONSTER_COUNT_DOWN_SHOW_IN_ANIMATION_FINISHED)); + } + }); + countDownTimer.clearAnimation(); + countDownTimer.startAnimation(topInAnimation); + } + + public void countDownTimerShowOut(Context context, TextView countDownTimer) { + Animation topOutAnimation = AnimationUtils.loadAnimation(context, R.anim.anim_top_out); + topOutAnimation.setAnimationListener(new SimpleAnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + super.onAnimationStart(animation); + getMonsterEventObservable().onNext(new MonsterEvent(MonsterEvent.MONSTER_COUNT_DOWN_SHOW_OUT_ANIMATION_START)); + } + + @Override + public void onAnimationEnd(Animation animation) { + super.onAnimationEnd(animation); + getMonsterEventObservable().onNext(new MonsterEvent(MonsterEvent.MONSTER_COUNT_DOWN_SHOW_OUT_ANIMATION_FINISHED)); + } + }); + countDownTimer.clearAnimation(); + countDownTimer.startAnimation(topOutAnimation); + } + + public void closeImgShowIn(Context context, ImageView closeImg) { + Animation topInAnimation = AnimationUtils.loadAnimation(context, R.anim.anim_top_in); + topInAnimation.setAnimationListener(new SimpleAnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + super.onAnimationStart(animation); + getMonsterEventObservable().onNext(new MonsterEvent(MonsterEvent.MONSTER_CLOSE_SHOW_IN_ANIMATION_START)); + } + + @Override + public void onAnimationEnd(Animation animation) { + super.onAnimationEnd(animation); + getMonsterEventObservable().onNext(new MonsterEvent(MonsterEvent.MONSTER_CLOSE_SHOW_IN_ANIMATION_FINISHED)); + } + }); + closeImg.clearAnimation(); + closeImg.startAnimation(topInAnimation); + } + + public void closeImgShowOut(Context context, ImageView closeImg) { + Animation topOutAnimation = AnimationUtils.loadAnimation(context, R.anim.anim_top_out); + topOutAnimation.setAnimationListener(new SimpleAnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + super.onAnimationStart(animation); + getMonsterEventObservable().onNext(new MonsterEvent(MonsterEvent.MONSTER_CLOSE_SHOW_OUT_ANIMATION_START)); + } + + @Override + public void onAnimationEnd(Animation animation) { + super.onAnimationEnd(animation); + getMonsterEventObservable().onNext(new MonsterEvent(MonsterEvent.MONSTER_CLOSE_SHOW_OUT_ANIMATION_FINISHED)); + } + }); + closeImg.clearAnimation(); + closeImg.startAnimation(topOutAnimation); + } + + public void impactViewShowOut(Context context, TextView impactView) { + Animation topOutAnimation = AnimationUtils.loadAnimation(context, R.anim.monster_hunting_impact); + topOutAnimation.setAnimationListener(new SimpleAnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + super.onAnimationStart(animation); + impactView.setVisibility(View.VISIBLE); + getMonsterEventObservable().onNext(new MonsterEvent(MonsterEvent.MONSTER_IMPACT_SHOW_OUT_ANIMATION_START)); + } + + @Override + public void onAnimationEnd(Animation animation) { + super.onAnimationEnd(animation); + impactView.setVisibility(View.GONE); + getMonsterEventObservable().onNext(new MonsterEvent(MonsterEvent.MONSTER_IMPACT_SHOW_OUT_ANIMATION_FINISHED)); + } + }); + impactView.clearAnimation(); + impactView.startAnimation(topOutAnimation); + } +} diff --git a/app/src/main/java/com/chwl/app/monsterhunting/MonsterHuntingIntroductionDialog.java b/app/src/main/java/com/chwl/app/monsterhunting/MonsterHuntingIntroductionDialog.java new file mode 100644 index 0000000..206898a --- /dev/null +++ b/app/src/main/java/com/chwl/app/monsterhunting/MonsterHuntingIntroductionDialog.java @@ -0,0 +1,63 @@ +package com.chwl.app.monsterhunting; + +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.DialogFragment; +import androidx.fragment.app.FragmentManager; + +import com.chwl.app.R; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; + +/** + * Created by MadisonRong on 02/04/2018. + */ + +public class MonsterHuntingIntroductionDialog extends DialogFragment implements View.OnClickListener { + + private static final String TAG = "MonsterHuntingIntroduct"; + + private TextView confirmTextView; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + Window window = getDialog().getWindow(); + // setup window and width + View view = inflater.inflate(R.layout.dialog_monster_hunting_introduction, window.findViewById(android.R.id.content), false); + window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); + window.setLayout(ViewGroup.LayoutParams.WRAP_CONTENT, UIUtil.dip2px(getContext(), 431)); + setCancelable(true); + confirmTextView = view.findViewById(R.id.iv_operation_ok); + confirmTextView.setOnClickListener(this); + return view; + } + + public void show(FragmentManager fragmentManager) { + this.show(fragmentManager, TAG); + } + + @Override + public void show(FragmentManager manager, String tag) { + manager.beginTransaction() + .add(this, tag) + .commitAllowingStateLoss(); + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.iv_operation_ok: + dismissAllowingStateLoss(); + break; + } + } +} diff --git a/app/src/main/java/com/chwl/app/monsterhunting/MonsterHuntingRewardDialog.java b/app/src/main/java/com/chwl/app/monsterhunting/MonsterHuntingRewardDialog.java new file mode 100644 index 0000000..236b138 --- /dev/null +++ b/app/src/main/java/com/chwl/app/monsterhunting/MonsterHuntingRewardDialog.java @@ -0,0 +1,156 @@ +package com.chwl.app.monsterhunting; + +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.DialogFragment; +import androidx.fragment.app.FragmentManager; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.OrientationHelper; +import androidx.recyclerview.widget.RecyclerView; + +import com.chwl.app.R; +import com.chwl.app.UIHelper; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.monsterhunting.bean.MonsterHunter; +import com.chwl.core.monsterhunting.bean.MonsterHuntingResult; +import com.chwl.core.monsterhunting.bean.MonsterHuntingReward; +import com.chwl.core.monsterhunting.bean.MonsterInfo; +import com.chwl.core.monsterhunting.manager.MonsterDataManager; +import com.chwl.core.monsterhunting.model.MonsterHuntingModel; +import com.chwl.library.utils.SingleToastUtil; + +import java.util.List; +import java.util.Locale; + +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; + +/** + * Created by MadisonRong on 02/04/2018. + */ + +public class MonsterHuntingRewardDialog extends DialogFragment implements View.OnClickListener { + + private static final String TAG = "MonsterHuntingRewardDia"; + + private ImageView closeView; + private ImageView avatarView; + private TextView usernameView; + private TextView userIdView; + private TextView impactValueView; + private TextView rewardCountView; + private RecyclerView rewardRecyclerView; + private ImageView moreRewardView; + private TextView checkDamageView; + private MonsterHuntingRewardsAdapter rewardsAdapter; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + Window window = getDialog().getWindow(); + // setup window and width + View view = inflater.inflate(R.layout.dialog_monster_hunting_reward, window.findViewById(android.R.id.content), false); + window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); +// window.setLayout(ViewGroup.LayoutParams.WRAP_CONTENT, UIUtil.dip2px(getContext(), 375)); + setCancelable(false); + init(view); + return view; + } + + private void init(View view) { + closeView = view.findViewById(R.id.iv_monster_hunting_exit); + avatarView = view.findViewById(R.id.iv_luck_man_avatar); + usernameView = view.findViewById(R.id.tv_luck_man_name); + userIdView = view.findViewById(R.id.tv_luck_man_id); + impactValueView = view.findViewById(R.id.tv_impact_value); + rewardCountView = view.findViewById(R.id.tv_reward_title); + rewardRecyclerView = view.findViewById(R.id.rv_reward_things); + moreRewardView = view.findViewById(R.id.iv_reward_things_more); + checkDamageView = view.findViewById(R.id.rl_check_damage); + + closeView.setOnClickListener(this); + moreRewardView.setOnClickListener(this); + checkDamageView.setOnClickListener(this); + + MonsterInfo monsterInfo = MonsterDataManager.get().getCurrentRoomMonsterInfo(); + if (monsterInfo != null) { + MonsterHuntingModel.get().getRoomMonsterHuntingResult(String.valueOf(monsterInfo.getMonsterId())) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe((monsterHuntingResultServiceResult, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + } else if (monsterHuntingResultServiceResult != null && monsterHuntingResultServiceResult.isSuccess()) { + if (monsterHuntingResultServiceResult.getData() != null) { + displayResult(monsterHuntingResultServiceResult.getData()); + } + } else if (monsterHuntingResultServiceResult != null && !monsterHuntingResultServiceResult.isSuccess()) { + SingleToastUtil.showToast(monsterHuntingResultServiceResult.getMessage()); + } + }); + } + } + + public void displayResult(MonsterHuntingResult monsterHuntingResult) { + Log.e(TAG, "displayResult() called with: monsterHuntingReward = [" + monsterHuntingResult + "]"); + // 幸运儿 + MonsterHunter luckDog = monsterHuntingResult.getLuckyDog(); + if (luckDog != null) { + ImageLoadUtils.loadAvatar(getContext(), luckDog.getAvatar(), avatarView); + usernameView.setText(luckDog.getNick()); + userIdView.setText(String.format(Locale.getDefault(), getContext().getString(R.string.text_user_id), + luckDog.getErbanNo())); + impactValueView.setText(luckDog.getHurt()); + } + // 获得的奖励 + List awards = monsterHuntingResult.getAwards(); + if (awards != null) { + rewardCountView.setText(String.format(Locale.getDefault(), + rewardCountView.getText().toString(), awards.size())); + rewardsAdapter = new MonsterHuntingRewardsAdapter(awards, getContext()); + rewardRecyclerView.setAdapter(rewardsAdapter); + rewardRecyclerView.setLayoutManager(new LinearLayoutManager(getContext(), OrientationHelper.HORIZONTAL, false)); + moreRewardView.setVisibility(View.GONE); + } + } + + public void show(FragmentManager fragmentManager) { + this.show(fragmentManager, TAG); + } + + @Override + public void show(FragmentManager manager, String tag) { + if (manager.findFragmentByTag(tag) == null) { + manager.beginTransaction() + .add(this, tag) + .commitAllowingStateLoss(); + } + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.iv_monster_hunting_exit: + dismissAllowingStateLoss(); + if (getActivity() != null) { + getActivity().finish(); + } + break; + + case R.id.rl_check_damage: + UIHelper.showMonsterResult(getContext(), String.valueOf(MonsterDataManager.get().getCurrentRoomMonsterInfo().getMonsterId())); + break; + } + } +} diff --git a/app/src/main/java/com/chwl/app/monsterhunting/MonsterHuntingRewardsAdapter.java b/app/src/main/java/com/chwl/app/monsterhunting/MonsterHuntingRewardsAdapter.java new file mode 100644 index 0000000..9cb1c81 --- /dev/null +++ b/app/src/main/java/com/chwl/app/monsterhunting/MonsterHuntingRewardsAdapter.java @@ -0,0 +1,96 @@ +package com.chwl.app.monsterhunting; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.recyclerview.widget.RecyclerView; + +import com.chwl.app.R; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.core.monsterhunting.bean.MonsterHuntingReward; +import com.chwl.library.adapters.BaseListRecyclerViewAdapter; +import com.chwl.library.utils.ResUtil; + +import java.util.Collection; + +/** + * Created by MadisonRong on 03/04/2018. + */ + +public class MonsterHuntingRewardsAdapter extends BaseListRecyclerViewAdapter { + + private Context context; + + public MonsterHuntingRewardsAdapter(Context context) { + this.context = context; + } + + public MonsterHuntingRewardsAdapter(int capacity, Context context) { + super(capacity); + this.context = context; + } + + public MonsterHuntingRewardsAdapter(Collection collection, Context context) { + super(collection); + this.context = context; + } + + @Override + public MonsterHuntingRewardViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return new MonsterHuntingRewardViewHolder(LayoutInflater.from(context) + .inflate(R.layout.list_item_monster_hunting_reward, parent, false)); + } + + @Override + public void onBindViewHolder(MonsterHuntingRewardViewHolder holder, int position) { + int pos = holder.getAdapterPosition(); + MonsterHuntingReward reward = get(pos); + ImageLoadUtils.loadRectImage(context, reward.getProdImage(), holder.rewardImageView, + R.drawable.default_cover, UIUtil.dip2px(context, 10)); + switch (Integer.parseInt(reward.getProdType())) { + case MonsterHuntingReward.REWARD_GOLD: + holder.rewardNameView.setText(context.getString(R.string.diamonds)); + holder.rewardValueView.setVisibility(View.VISIBLE); + holder.rewardValueView.setText(reward.getProdValue()); + break; + case MonsterHuntingReward.REWARD_CAR: + holder.rewardNameView.setText(reward.getProdName()); + holder.rewardValueView.setVisibility(View.VISIBLE); + holder.rewardValueView.setText(reward.getExpireDays() + ResUtil.getString(R.string.erban_monsterhunting_monsterhuntingrewardsadapter_01)); + break; + + case MonsterHuntingReward.REWARD_ACCOUNT: + holder.rewardNameView.setText(ResUtil.getString(R.string.erban_monsterhunting_monsterhuntingrewardsadapter_02)); + holder.rewardValueView.setVisibility(View.VISIBLE); + holder.rewardValueView.setText(reward.getProdValue()); + break; + + case MonsterHuntingReward.REWARD_PHYSICAL: + holder.rewardNameView.setText(reward.getProdName()); + holder.rewardValueView.setVisibility(View.VISIBLE); + holder.rewardValueView.setText(reward.getProdValue()); + break; + } + } + + class MonsterHuntingRewardViewHolder extends RecyclerView.ViewHolder { + + TextView rewardValueView; + ImageView rewardImageView; + TextView rewardNameView; + + public MonsterHuntingRewardViewHolder(View itemView) { + super(itemView); + + rewardValueView = itemView.findViewById(R.id.tv_reward_value); + rewardImageView = itemView.findViewById(R.id.iv_reward); + rewardNameView = itemView.findViewById(R.id.tv_reward_name); + + } + } +} diff --git a/app/src/main/java/com/chwl/app/monsterhunting/MonsterHuntingSvgaManager.java b/app/src/main/java/com/chwl/app/monsterhunting/MonsterHuntingSvgaManager.java new file mode 100644 index 0000000..e49bce6 --- /dev/null +++ b/app/src/main/java/com/chwl/app/monsterhunting/MonsterHuntingSvgaManager.java @@ -0,0 +1,209 @@ +package com.chwl.app.monsterhunting; + +import android.content.Context; +import android.text.TextUtils; +import android.util.Log; + +import com.opensource.svgaplayer.SVGACallback; +import com.opensource.svgaplayer.SVGADrawable; +import com.opensource.svgaplayer.SVGAImageView; +import com.opensource.svgaplayer.SVGAParser; +import com.opensource.svgaplayer.SVGAVideoEntity; +import com.chwl.app.common.svga.SimpleSvgaCallback; +import com.chwl.app.common.svga.SimpleSvgaParseCompletion; +import com.chwl.core.monsterhunting.bean.MonsterEvent; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Hashtable; +import java.util.Map; + +/** + * Created by MadisonRong on 01/04/2018. + */ + +public class MonsterHuntingSvgaManager { + + private static final String TAG = "MonsterHuntingSvgaManag"; + + public static final int MONSTER_HUNTING_ANIMATION_APPEAR = 0; + public static final int MONSTER_HUNTING_ANIMATION_NORMAL = 1; + public static final int MONSTER_HUNTING_ANIMATION_ATTACK = 2; + public static final int MONSTER_HUNTING_ANIMATION_DEFEAT = 3; + public static final int MONSTER_HUNTING_ANIMATION_LOTTERY = 4; + + private SVGAParser mSVGAParser; + private SVGAImageView monsterView; + private Map cacheSvgaMap = new Hashtable<>(); + private Map cacheSvgaDrawableMap = new Hashtable<>(); + private Map taskMap = new Hashtable<>(); + + private static final class MonsterHuntingSvgaManagerHolder { + private static final MonsterHuntingSvgaManager instance = new MonsterHuntingSvgaManager(); + } + + public static MonsterHuntingSvgaManager get() { + return MonsterHuntingSvgaManagerHolder.instance; + } + + public void initParser(Context context, SVGAImageView svgaImageView) { + mSVGAParser = new SVGAParser(context); + this.monsterView = svgaImageView; + } + + public void release() { + mSVGAParser = null; + monsterView = null; + cacheSvgaMap.clear(); + cacheSvgaDrawableMap.clear(); + taskMap.clear(); + } + + /** + * 预加载 SVGA 资源 + * + * @param appearUrl 怪兽进场动画 + * @param normalUrl 怪兽正常动画 + * @param attackUrl 怪兽被打动画 + * @param defeatUrl 怪兽打爆动画 + */ + public void preLoadMonsterAnimation(String appearUrl, String normalUrl, String attackUrl, String defeatUrl) { +// appearUrl = "https://image.zhongjialx.com/appear3.svga"; +// normalUrl = "https://image.zhongjialx.com/normal3.svga"; +// attackUrl = "https://image.zhongjialx.com/attack5.svga"; +// defeatUrl = "https://image.zhongjialx.com/defeat3.svga"; + String drawUrl = "https://image.zhongjialx.com/luckDrawnew.svga"; + loadAnimation(MONSTER_HUNTING_ANIMATION_APPEAR, appearUrl); + loadAnimation(MONSTER_HUNTING_ANIMATION_NORMAL, normalUrl); + loadAnimation(MONSTER_HUNTING_ANIMATION_ATTACK, attackUrl); + loadAnimation(MONSTER_HUNTING_ANIMATION_DEFEAT, defeatUrl); + loadAnimation(MONSTER_HUNTING_ANIMATION_LOTTERY, drawUrl); + } + + /** + * 加载 SVGA 动画,并缓存到内存中 + * + * @param type 动画的类型 + * @see #MONSTER_HUNTING_ANIMATION_APPEAR 怪兽出现动画 + * @see #MONSTER_HUNTING_ANIMATION_NORMAL 怪兽正常动画 + * @see #MONSTER_HUNTING_ANIMATION_ATTACK 怪兽被打动画 + * @see #MONSTER_HUNTING_ANIMATION_DEFEAT 怪兽打爆动画 + * @param url 动画对应的 URL + */ + public void loadAnimation(int type, String url) { + if (TextUtils.isEmpty(url)) { + return; + } + try { + Task task = new Task(type); + taskMap.put(type, task); + mSVGAParser.parse(new URL(url), new SimpleSvgaParseCompletion() { + @Override + public void onComplete(SVGAVideoEntity svgaVideoEntity) { + // 缓存好 SVGA + cacheSvgaMap.put(url, svgaVideoEntity); + SVGADrawable drawable = new SVGADrawable(svgaVideoEntity); + cacheSvgaDrawableMap.put(type, drawable); + // 从任务队列中减员 + taskMap.remove(type); + // 任务队列为空,表明所有资源都已经加载完毕 + if (taskMap.size() == 0) { + MonsterHuntingAnimationManager.get().getMonsterEventObservable() + .onNext(new MonsterEvent(MonsterEvent.ANIMATION_LOADED)); + } + } + + @Override + public void onError() { + super.onError(); + Log.e(TAG, "onError: load SVGA failed"); + } + }); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + } + + /** + * 播放怪兽的 SVGA + * + * @param drawable + * @param loopCount 循环次数,取值为 0 时无限循环 + * @param svgaCallback + */ + public void displayAnimation(SVGADrawable drawable, + int loopCount, SVGACallback svgaCallback) { + monsterView.setLoops(loopCount); + monsterView.setImageDrawable(drawable); + monsterView.setClearsAfterStop(true); + monsterView.startAnimation(); + monsterView.setCallback(svgaCallback); + } + + public void displayAppearAnimation() { + displayAnimation(cacheSvgaDrawableMap.get(MONSTER_HUNTING_ANIMATION_APPEAR), + 1, new SimpleSvgaCallback() { + @Override + public void onFinished() { + super.onFinished(); + // 进场动画结束后,立马播放正常动画 + MonsterHuntingAnimationManager.get().getMonsterEventObservable() + .onNext(new MonsterEvent(MonsterEvent.MONSTER_APPEAR_ANIMATION_FINISHED)); + } + }); + } + + public void displayNormalAnimation() { + displayAnimation(cacheSvgaDrawableMap.get(MONSTER_HUNTING_ANIMATION_NORMAL), + 0, new SimpleSvgaCallback()); + } + + public void displayAttackAnimation() { + displayAnimation(cacheSvgaDrawableMap.get(MONSTER_HUNTING_ANIMATION_ATTACK), + 1, new SimpleSvgaCallback() { + @Override + public void onFinished() { + super.onFinished(); + // 攻击动画结束后,回到正常动画上 + MonsterHuntingAnimationManager.get().getMonsterEventObservable() + .onNext(new MonsterEvent(MonsterEvent.MONSTER_ATTACK_ANIMATION_FINISHED)); + } + }); + } + + public void displayDefeatAnimation() { + displayAnimation(cacheSvgaDrawableMap.get(MONSTER_HUNTING_ANIMATION_DEFEAT), + 1, new SimpleSvgaCallback() { + @Override + public void onFinished() { + super.onFinished(); + // 怪兽被打爆,准备播放抽奖动画,出来抽奖结果 + MonsterHuntingAnimationManager.get().getMonsterEventObservable() + .onNext(new MonsterEvent(MonsterEvent.MONSTER_DEFEAT_ANIMATION_FINISHED)); + } + }); + } + + public void displayDrawAnimation() { + displayAnimation(cacheSvgaDrawableMap.get(MONSTER_HUNTING_ANIMATION_LOTTERY), + 1, new SimpleSvgaCallback() { + @Override + public void onFinished() { + super.onFinished(); + // 抽奖动画播完,准备弹出结果窗口 + MonsterHuntingAnimationManager.get().getMonsterEventObservable() + .onNext(new MonsterEvent(MonsterEvent.MONSTER_LOTTERY_ANIMATION_FINISHED)); + } + }); + } + + class Task { + // 内部类,占位而已 + public int taskId; + + public Task(int taskId) { + this.taskId = taskId; + } + } + +} diff --git a/app/src/main/java/com/chwl/app/monsterhunting/QuitConfirmDialog.java b/app/src/main/java/com/chwl/app/monsterhunting/QuitConfirmDialog.java new file mode 100644 index 0000000..6797370 --- /dev/null +++ b/app/src/main/java/com/chwl/app/monsterhunting/QuitConfirmDialog.java @@ -0,0 +1,69 @@ +package com.chwl.app.monsterhunting; + +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.DialogFragment; +import androidx.fragment.app.FragmentManager; + +import com.chwl.app.R; + +/** + * Created by MadisonRong on 02/04/2018. + */ + +public class QuitConfirmDialog extends DialogFragment implements View.OnClickListener { + + private static final String TAG = "QuitConfirmDialog"; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + Window window = getDialog().getWindow(); + // setup window and width + View view = inflater.inflate(R.layout.dialog_quit_monster_hunting, container, false); + window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); +// window.setLayout(UIUtil.dip2px(getContext(), 316), UIUtil.dip2px(getContext(), 168)); + setCancelable(true); + TextView confirmTextView = view.findViewById(R.id.iv_operation_confirm); + TextView cancelTextView = view.findViewById(R.id.iv_operation_cancel); + confirmTextView.setOnClickListener(this); + cancelTextView.setOnClickListener(this); + return view; + } + + public void show(FragmentManager fragmentManager) { + this.show(fragmentManager, TAG); + } + + @Override + public void show(FragmentManager manager, String tag) { + if (manager.findFragmentByTag(tag) == null) { + manager.beginTransaction() + .add(this, tag) + .commitAllowingStateLoss(); + } + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.iv_operation_confirm: + getActivity().finish(); + break; + + case R.id.iv_operation_cancel: + dismissAllowingStateLoss(); + break; + } + } + +} diff --git a/app/src/main/java/com/chwl/app/monsterhunting/SimpleCountDownTimer.java b/app/src/main/java/com/chwl/app/monsterhunting/SimpleCountDownTimer.java new file mode 100644 index 0000000..b420208 --- /dev/null +++ b/app/src/main/java/com/chwl/app/monsterhunting/SimpleCountDownTimer.java @@ -0,0 +1,31 @@ +package com.chwl.app.monsterhunting; + +import android.os.CountDownTimer; + +/** + * Created by MadisonRong on 02/04/2018. + */ + +public class SimpleCountDownTimer extends CountDownTimer { + + /** + * @param millisInFuture The number of millis in the future from the call + * to {@link #start()} until the countdown is done and {@link #onFinish()} + * is called. + * @param countDownInterval The interval along the way to receive + * {@link #onTick(long)} callbacks. + */ + public SimpleCountDownTimer(long millisInFuture, long countDownInterval) { + super(millisInFuture, countDownInterval); + } + + @Override + public void onTick(long millisUntilFinished) { + + } + + @Override + public void onFinish() { + + } +} diff --git a/app/src/main/java/com/chwl/app/monsterhunting/bean/AttackMonsterResultInfo.java b/app/src/main/java/com/chwl/app/monsterhunting/bean/AttackMonsterResultInfo.java new file mode 100644 index 0000000..38f3642 --- /dev/null +++ b/app/src/main/java/com/chwl/app/monsterhunting/bean/AttackMonsterResultInfo.java @@ -0,0 +1,53 @@ +package com.chwl.app.monsterhunting.bean; + + +import androidx.databinding.BaseObservable; + +import com.chwl.core.monsterhunting.bean.MonsterAttackInfo; + +public class AttackMonsterResultInfo extends BaseObservable{ + + private int status; + + private int code; + + private String errorMessage = ""; + + private MonsterAttackInfo monsterAttackInfo; + + public AttackMonsterResultInfo() { + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + notifyChange(); + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public MonsterAttackInfo getMonsterAttackInfo() { + return monsterAttackInfo; + } + + public void setMonsterAttackInfo(MonsterAttackInfo monsterAttackInfo) { + this.monsterAttackInfo = monsterAttackInfo; + } +} diff --git a/app/src/main/java/com/chwl/app/monsterhunting/bean/UpdateMyGoldInfo.java b/app/src/main/java/com/chwl/app/monsterhunting/bean/UpdateMyGoldInfo.java new file mode 100644 index 0000000..d33eb5c --- /dev/null +++ b/app/src/main/java/com/chwl/app/monsterhunting/bean/UpdateMyGoldInfo.java @@ -0,0 +1,32 @@ +package com.chwl.app.monsterhunting.bean; + +import androidx.databinding.BaseObservable; + +import com.chwl.core.pay.bean.WalletInfo; + +public class UpdateMyGoldInfo extends BaseObservable { + + private boolean isSucceed; + + private WalletInfo walletInfo; + + public UpdateMyGoldInfo() { + } + + public boolean isSucceed() { + return isSucceed; + } + + public void setSucceed(boolean succeed) { + isSucceed = succeed; + notifyChange(); + } + + public WalletInfo getWalletInfo() { + return walletInfo; + } + + public void setWalletInfo(WalletInfo walletInfo) { + this.walletInfo = walletInfo; + } +} diff --git a/app/src/main/java/com/chwl/app/notify/GlobalNotifyManager.kt b/app/src/main/java/com/chwl/app/notify/GlobalNotifyManager.kt new file mode 100644 index 0000000..a9043a8 --- /dev/null +++ b/app/src/main/java/com/chwl/app/notify/GlobalNotifyManager.kt @@ -0,0 +1,270 @@ +package com.chwl.app.notify + +import androidx.fragment.app.FragmentActivity +import androidx.lifecycle.lifecycleScope +import com.alibaba.fastjson2.JSON +import com.chwl.app.NimMiddleActivity +import com.chwl.app.avroom.activity.AVRoomActivity +import com.chwl.app.avroom.anotherroompk.RoomPKCreateActivity +import com.chwl.app.avroom.singleroompk.SingleRoomPKCreateActivity +import com.chwl.app.base.TitleBar +import com.chwl.app.other.activity.SplashActivity +import com.chwl.app.room_chat.activity.NimRoomP2PMessageActivity +import com.chwl.app.room_chat.activity.RoomMsgActivity +import com.chwl.app.support.float.FloatWindowEngine +import com.chwl.app.support.float.SimpleFloatQueue +import com.chwl.app.support.float.SimpleFloatWindow +import com.chwl.app.treasure_box.activity.BoxRankingActivity +import com.chwl.app.treasure_box.activity.TreasureBoxActivity +import com.chwl.app.treasure_box.activity.TreasureBoxHonourActivity +import com.chwl.app.ui.login.AddUserInfoActivity +import com.chwl.app.ui.login.LoginCodeActivity +import com.chwl.app.ui.login.LoginPhoneActivity +import com.chwl.app.ui.setting.ResetPasswordActivity +import com.chwl.app.ui.webview.room_banner.RoomBannerWebDialogActivity +import com.chwl.app.ui.widget.LevelUpDialog +import com.chwl.core.auth.AuthModel +import com.chwl.core.bean.BaseProtocol +import com.chwl.core.gift.bean.LuckyBagNoticeInfo +import com.chwl.core.im.custom.bean.CustomAttachment +import com.chwl.core.im.custom.bean.RoomBoxPrizeAttachment +import com.chwl.core.im.custom.bean.RoomBoxPrizeInfo +import com.chwl.core.im.custom.bean.RoomReceivedLuckyGiftAttachment +import com.chwl.core.im.custom.bean.RoomTemplateNotifyMsgBean +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.manager.IMNetEaseManager +import com.chwl.core.noble.bean.AllServiceGiftProtocol +import com.chwl.core.user.UserModel +import com.chwl.library.common.util.doLog +import com.example.lib_utils.log.ILog +import com.google.gson.Gson +import com.netease.nim.uikit.common.util.sys.ScreenUtil +import com.netease.nimlib.sdk.NIMSDK +import com.netease.nimlib.sdk.Observer +import com.netease.nimlib.sdk.chatroom.ChatRoomMessageBuilder +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage +import com.netease.nimlib.sdk.msg.model.BroadcastMessage +import kotlinx.coroutines.cancel + +/** + * Created by Max on 2024/3/20 19:30 + * Desc: + **/ +object GlobalNotifyManager : Observer, ILog { + + private val blackActivityList = listOf( + SplashActivity::class.java, + LoginPhoneActivity::class.java, + LoginCodeActivity::class.java, + ResetPasswordActivity::class.java, + AddUserInfoActivity::class.java, + NimMiddleActivity::class.java, + // 房间页面单独处理 + AVRoomActivity::class.java, + // 房间内玩法(该Activity用了透明主题且顶部区域还能看到房间页面,那就在房间页面展示飘屏即可) + TreasureBoxActivity::class.java, + BoxRankingActivity::class.java, + TreasureBoxHonourActivity::class.java, + RoomPKCreateActivity::class.java, + SingleRoomPKCreateActivity::class.java, + // 房间内私聊(该Activity用了透明主题且顶部区域还能看到房间页面,那就在房间页面展示飘屏即可) + NimRoomP2PMessageActivity::class.java, + RoomMsgActivity::class.java, + // 房间内webDialog(该Activity用了透明主题且顶部区域还能看到房间页面,那就在房间页面展示飘屏即可) + RoomBannerWebDialogActivity::class.java, + // 升级弹窗 + LevelUpDialog::class.java + ) + + val queue = SimpleFloatQueue() + + init { + start() + } + + fun start() { + NIMSDK.getMsgServiceObserve().observeBroadcastMessage(this, true) + } + + fun stop() { + NIMSDK.getMsgServiceObserve().observeBroadcastMessage(this, false) + } + + fun bindActivity(activity: FragmentActivity) { + if (!filter(activity)) { + logD("bindActivity() 被过滤掉") + return + } + activity.lifecycleScope.launchWhenStarted { + bindActivityImpl(activity) + this.cancel() + } + } + + private fun filter(activity: FragmentActivity): Boolean { + if (blackActivityList.firstOrNull { it == activity::class.java } != null) { + return false + } + if (!AuthModel.get().isLogin) { + return false + } + return true + } + + private fun bindActivityImpl(activity: FragmentActivity) { + val widget = SimpleFloatWindow(activity) + widget.maxVisibleCount = 1 + widget.bindActivity(activity) + widget.adapter = NotifyAdapter() + var statusHeight = TitleBar.getStatusBarHeight() + if (statusHeight <= 0) { + statusHeight = ScreenUtil.getStatusBarHeight(activity) + } + widget.getView().setPadding(0, statusHeight, 0, 0) + val engine = FloatWindowEngine(widget, queue) + engine.bindLifecycle(activity.lifecycle) + engine.start() + } + + override fun onEvent(message: BroadcastMessage?) { + if (message == null) { + return + } + try { + val contentJsonStr: String = message.content + val jsonObject = JSON.parseObject(contentJsonStr) ?: return + if (jsonObject.containsKey("body")) { + val body = jsonObject.getString("body") + if (body.isNullOrEmpty()) { + return + } + val baseProtocol: BaseProtocol<*> = try { + JSON.parseObject(body, BaseProtocol::class.java) + } catch (e: java.lang.Exception) { + null + } ?: return + onReceivedNimBroadcastMessage(baseProtocol) + } + } catch (e: Exception) { + e.printStackTrace() + } + } + + private fun onReceivedNimBroadcastMessage(protocol: BaseProtocol<*>) { + if (!AvRoomDataManager.get().hasAvRoomAct) return +// if (BuildConfig.DEBUG) { +// "通用飘屏 监听器 GlobalNotifyManager 全局 ${JSON.toJSONString(protocol)}".doLog() +// } + + when (protocol.first) { + // 通用飘屏 + CustomAttachment.CUSTOM_MSG_TEMPLATE_NOTIFY -> { + if (protocol.second == CustomAttachment.CUSTOM_MSG_TEMPLATE_NOTIFY_ALL) { + val data = Gson().fromJson(protocol.data.toString(), RoomTemplateNotifyMsgBean::class.java) + if (UserModel.get().isSamePartition(data.partitionId ?: 0)) { + queue.addLast(data) + "通用飘屏 监听器 GlobalNotifyManager 全局 通用飘屏".doLog() + } + } + } + // 礼物 +// CustomAttachment.CUSTOM_MSG_HEADER_TYPE_GIFT -> { +// if (protocol.second == CustomAttachment.CUSTOM_MSG_ALL_SERVICE_GIFT) { +// val data = Gson().fromJson( +// protocol.data.toString(), +// AllServiceGiftProtocol.DataBean::class.java +// ) +// if (UserModel.get().isSamePartition(data.partitionId)) { +// queue.addLast(data) +// } +// } +// } + // 寻爱之旅 + CustomAttachment.CUSTOM_MSG_BOX -> { + if (protocol.second == CustomAttachment.CUSTOM_MSG_SUB_BOX_ALL_ROOM_NOTIFY_BY_SVGA) { + handleFindLive(protocol) + } + } + // 福袋礼物 + CustomAttachment.CUSTOM_MSG_LUCKY_GIFT -> { + if (protocol.second == CustomAttachment.CUSTOM_MSG_LUCKY_GIFT_SERVER_ALL) { + val data = Gson().fromJson( + protocol.data.toString(), + LuckyBagNoticeInfo::class.java + ) + if (UserModel.get().isSamePartition(data.partitionId)) { + // 添加飘屏 + queue.addLast(data) + "通用飘屏 监听器 GlobalNotifyManager 全局 福袋礼物".doLog() + // 添加公屏 + val attachment = RoomReceivedLuckyGiftAttachment(CustomAttachment.CUSTOM_MSG_LUCKY_GIFT_SERVER_NOTIFY) + attachment.luckyBagNoticeInfo = data + val message = ChatRoomMessageBuilder.createChatRoomCustomMessage( + AvRoomDataManager.get().roomId.toString(), + attachment + ) + IMNetEaseManager.get().addMessages(message) + } + } + } + } + } + + public fun onReceiveGiftMsgAllServiceNotify(anyData:Any?) { + if (!AvRoomDataManager.get().hasAvRoomAct) return + if (anyData != null) { + //全服礼物 + if (anyData is AllServiceGiftProtocol.DataBean) { + if (UserModel.get().isSamePartition(anyData.partitionId)) { + queue.addLast(anyData) + "通用飘屏 监听器 GlobalNotifyManager 全局 AllServiceGiftProtocol".doLog() + } + } + } + } + + private fun handleFindLive(protocol: BaseProtocol<*>) { + val data = Gson().fromJson( + protocol.data.toString(), + RoomBoxPrizeInfo::class.java + ) + if (!UserModel.get().isSamePartition(data.partitionId)) { + return + } + val roomBoxPrizeAttachment = RoomBoxPrizeAttachment( + CustomAttachment.CUSTOM_MSG_BOX, + CustomAttachment.CUSTOM_MSG_SUB_BOX_ALL_ROOM_NOTIFY_BY_SVGA + ) + roomBoxPrizeAttachment.uid = data.uid + roomBoxPrizeAttachment.prizeName = data.prizeName + roomBoxPrizeAttachment.nick = data.nick + roomBoxPrizeAttachment.boxTypeStr = data.boxTypeStr + roomBoxPrizeAttachment.roomUid = data.roomUid + roomBoxPrizeAttachment.prizeNum = data.prizeNum + roomBoxPrizeAttachment.userLevelLimit = data.userLevelLimit + val roomId = AvRoomDataManager.get().roomId + var message: ChatRoomMessage? = null + if (roomId > 0) { + message = ChatRoomMessageBuilder.createChatRoomCustomMessage( + roomId.toString(), + roomBoxPrizeAttachment + ) + } + if (AvRoomDataManager.get().isOpenPureMode) { + // 純凈模式打開後,僅能看跟自己相關的砸蛋消息 + if (message != null && roomBoxPrizeAttachment.uid == AuthModel.get().currentUid) { + IMNetEaseManager.get().addMessages(message) + } + } else { + if (message != null) { + IMNetEaseManager.get().addMessages(message) + } + queue.addLast(roomBoxPrizeAttachment) + "通用飘屏 监听器 GlobalNotifyManager 全局 寻爱之旅 ".doLog() + } + } + + fun clearQueue() { + queue.clear() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/notify/GlobalNotifyManagerNew.kt b/app/src/main/java/com/chwl/app/notify/GlobalNotifyManagerNew.kt new file mode 100644 index 0000000..4eb7d74 --- /dev/null +++ b/app/src/main/java/com/chwl/app/notify/GlobalNotifyManagerNew.kt @@ -0,0 +1,248 @@ +//package com.chwl.app.notify +// +//import androidx.fragment.app.FragmentActivity +//import androidx.lifecycle.lifecycleScope +//import com.chwl.app.NimMiddleActivity +//import com.chwl.app.avroom.activity.AVRoomActivity +//import com.chwl.app.avroom.anotherroompk.RoomPKCreateActivity +//import com.chwl.app.avroom.singleroompk.SingleRoomPKCreateActivity +//import com.chwl.app.base.TitleBar +//import com.chwl.app.other.activity.SplashActivity +//import com.chwl.app.support.float.FloatWindowEngine +//import com.chwl.app.support.float.SimpleFloatQueue +//import com.chwl.app.support.float.SimpleFloatWindow +//import com.chwl.app.treasure_box.activity.BoxRankingActivity +//import com.chwl.app.treasure_box.activity.TreasureBoxActivity +//import com.chwl.app.treasure_box.activity.TreasureBoxHonourActivity +//import com.chwl.app.ui.login.AddUserInfoActivity +//import com.chwl.app.ui.login.LoginCodeActivity +//import com.chwl.app.ui.login.LoginPhoneActivity +//import com.chwl.app.ui.setting.ResetPasswordActivity +//import com.chwl.app.ui.widget.LevelUpDialog +//import com.chwl.core.auth.AuthModel +//import com.chwl.core.gift.bean.LuckyBagNoticeInfo +//import com.chwl.core.im.custom.bean.CustomAttachment +//import com.chwl.core.im.custom.bean.RoomBoxPrizeAttachment +//import com.chwl.core.im.custom.bean.RoomBoxPrizeInfo +//import com.chwl.core.im.custom.bean.RoomReceivedLuckyGiftAttachment +//import com.chwl.core.im.custom.bean.RoomTemplateNotifyMsgBean +//import com.chwl.core.manager.AvRoomDataManager +//import com.chwl.core.manager.IMNetEaseManager +//import com.chwl.core.noble.bean.AllServiceGiftProtocol +//import com.chwl.core.user.UserModel +//import com.chwl.library.common.util.doLog +//import com.chwl.library.utils.ListUtils +//import com.example.lib_utils.log.ILog +//import com.google.gson.Gson +//import com.netease.nim.uikit.common.util.sys.ScreenUtil +//import com.netease.nimlib.sdk.NIMChatRoomSDK +//import com.netease.nimlib.sdk.Observer +//import com.netease.nimlib.sdk.chatroom.ChatRoomMessageBuilder +//import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage +//import com.netease.nimlib.sdk.msg.constant.MsgTypeEnum +//import kotlinx.coroutines.cancel +// +///** +// * Created by Max on 2024/3/20 19:30 +// * Desc: +// **/ +//object GlobalNotifyManagerNew : Observer>, ILog { +// +// private fun readResolve(): Any = GlobalNotifyManagerNew +// +// private val blackActivityList = listOf( +// SplashActivity::class.java, +// LoginPhoneActivity::class.java, +// LoginCodeActivity::class.java, +// ResetPasswordActivity::class.java, +// AddUserInfoActivity::class.java, +// NimMiddleActivity::class.java, +// // 房间页面单独处理 +// AVRoomActivity::class.java, +// // 房间内玩法(该Activity用了透明主题且顶部区域还能看到房间页面,那就在房间页面展示飘屏即可) +// TreasureBoxActivity::class.java, +// BoxRankingActivity::class.java, +// TreasureBoxHonourActivity::class.java, +// RoomPKCreateActivity::class.java, +// SingleRoomPKCreateActivity::class.java, +// // 房间内私聊(该Activity用了透明主题且顶部区域还能看到房间页面,那就在房间页面展示飘屏即可) +//// NimRoomP2PMessageActivity::class.java, +//// RoomMsgActivity::class.java, +// // 房间内webDialog(该Activity用了透明主题且顶部区域还能看到房间页面,那就在房间页面展示飘屏即可) +//// RoomBannerWebDialogActivity::class.java, +// // 升级弹窗 +// LevelUpDialog::class.java +// ) +// +// val queue = SimpleFloatQueue() +// +// init { +// start() +// } +// +// fun start() { +// NIMChatRoomSDK.getChatRoomServiceObserve().observeReceiveMessage(this, true) +// } +// +// fun stop() { +// NIMChatRoomSDK.getChatRoomServiceObserve().observeReceiveMessage(this, false) +// } +// +// fun bindActivity(activity: FragmentActivity) { +// if (!filter(activity)) { +// logD("bindActivity() 被过滤掉") +// return +// } +// activity.lifecycleScope.launchWhenStarted { +// bindActivityImpl(activity) +// this.cancel() +// } +// } +// +// private fun filter(activity: FragmentActivity): Boolean { +// if (blackActivityList.firstOrNull { it == activity::class.java } != null) { +// return false +// } +// if (!AuthModel.get().isLogin) { +// return false +// } +// return true +// } +// +// private fun bindActivityImpl(activity: FragmentActivity) { +// val widget = SimpleFloatWindow(activity) +// widget.maxVisibleCount = 1 +// widget.bindActivity(activity) +// widget.adapter = NotifyAdapter() +// var statusHeight = TitleBar.getStatusBarHeight() +// if (statusHeight <= 0) { +// statusHeight = ScreenUtil.getStatusBarHeight(activity) +// } +// widget.getView().setPadding(0, statusHeight, 0, 0) +// val engine = FloatWindowEngine(widget, queue) +// engine.bindLifecycle(activity.lifecycle) +// engine.start() +// } +// +// override fun onEvent(chatRoomMessages: List?) { +// if (ListUtils.isListEmpty(chatRoomMessages)) return +// if (!AvRoomDataManager.get().hasAvRoomAct) return +// chatRoomMessages?.forEach { msg-> +// if (msg.msgType == MsgTypeEnum.custom) { +// val attachment = msg.attachment ?: return +// val customAttachment = attachment as CustomAttachment +// val first = customAttachment.first +// val second = customAttachment.second +// when (first) { +// +// // 通用飘屏 +// CustomAttachment.CUSTOM_MSG_TEMPLATE_NOTIFY -> { +// if (second == CustomAttachment.CUSTOM_MSG_TEMPLATE_NOTIFY_ALL) { +// val data = Gson().fromJson( +// customAttachment.data.toString(), +// RoomTemplateNotifyMsgBean::class.java +// ) +// if (UserModel.get().isSamePartition(data.partitionId ?: 0)) { +// queue.addLast(data) +// } +// } +// } +// +// +// +// // 礼物 +// CustomAttachment.CUSTOM_MSG_HEADER_TYPE_GIFT -> { +// if (second == CustomAttachment.CUSTOM_MSG_ALL_SERVICE_GIFT) { +// " 全服礼物-32 notify ".doLog() +// val data = Gson().fromJson( +// customAttachment.data.toString(), +// AllServiceGiftProtocol.DataBean::class.java +// ) +// if (UserModel.get().isSamePartition(data.partitionId)) { +// queue.addLast(data) +// } +// } +// } +// // 寻爱之旅 +// CustomAttachment.CUSTOM_MSG_BOX -> { +// if (second == CustomAttachment.CUSTOM_MSG_SUB_BOX_ALL_ROOM_NOTIFY_BY_SVGA) { +// handleFindLive(customAttachment) +// } +// } +// // 福袋礼物 +// CustomAttachment.CUSTOM_MSG_LUCKY_GIFT -> { +// if (second == CustomAttachment.CUSTOM_MSG_LUCKY_GIFT_SERVER_ALL) { +// val data = Gson().fromJson( +// customAttachment.data.toString(), +// LuckyBagNoticeInfo::class.java +// ) +// +// if (UserModel.get().isSamePartition(data.partitionId)) { +// // 添加飘屏 +// queue.addLast(data) +// // 添加公屏 +// val attachmentNew = RoomReceivedLuckyGiftAttachment(CustomAttachment.CUSTOM_MSG_LUCKY_GIFT_SERVER_NOTIFY) +// attachmentNew.luckyBagNoticeInfo = data +// val message = ChatRoomMessageBuilder.createChatRoomCustomMessage( +// AvRoomDataManager.get().roomId.toString(), +// attachment +// ) +// IMNetEaseManager.get().addMessages(message) +// } +// } +// } +// +// +// +// } +// } +// } +// } +// +// +// +// +// private fun handleFindLive(customAttachment: CustomAttachment) { +// val data = Gson().fromJson( +// customAttachment.data.toString(), +// RoomBoxPrizeInfo::class.java +// ) +// if (!UserModel.get().isSamePartition(data.partitionId)) { +// return +// } +// val roomBoxPrizeAttachment = RoomBoxPrizeAttachment( +// CustomAttachment.CUSTOM_MSG_BOX, +// CustomAttachment.CUSTOM_MSG_SUB_BOX_ALL_ROOM_NOTIFY_BY_SVGA +// ) +// roomBoxPrizeAttachment.uid = data.uid +// roomBoxPrizeAttachment.prizeName = data.prizeName +// roomBoxPrizeAttachment.nick = data.nick +// roomBoxPrizeAttachment.boxTypeStr = data.boxTypeStr +// roomBoxPrizeAttachment.roomUid = data.roomUid +// roomBoxPrizeAttachment.prizeNum = data.prizeNum +// roomBoxPrizeAttachment.userLevelLimit = data.userLevelLimit +// val roomId = AvRoomDataManager.get().roomId +// var message: ChatRoomMessage? = null +// if (roomId > 0) { +// message = ChatRoomMessageBuilder.createChatRoomCustomMessage( +// roomId.toString(), +// roomBoxPrizeAttachment +// ) +// } +// if (AvRoomDataManager.get().isOpenPureMode) { +// // 純凈模式打開後,僅能看跟自己相關的砸蛋消息 +// if (message != null && roomBoxPrizeAttachment.uid == AuthModel.get().currentUid) { +// IMNetEaseManager.get().addMessages(message) +// } +// } else { +// if (message != null) { +// IMNetEaseManager.get().addMessages(message) +// } +// queue.addLast(roomBoxPrizeAttachment) +// } +// } +// +// fun clearQueue() { +// queue.clear() +// } +//} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/notify/NotifyAdapter.kt b/app/src/main/java/com/chwl/app/notify/NotifyAdapter.kt new file mode 100644 index 0000000..1147f60 --- /dev/null +++ b/app/src/main/java/com/chwl/app/notify/NotifyAdapter.kt @@ -0,0 +1,80 @@ +package com.chwl.app.notify + +import android.content.Context +import com.chwl.app.notify.views.BaiShunGameNotify +import com.chwl.app.notify.views.FindLoveImageNotify +import com.chwl.app.notify.views.TemplateImageNotify +import com.chwl.app.notify.views.TemplateSvgaNotify +import com.chwl.app.notify.views.GiftNotify +import com.chwl.app.notify.views.LuckyBagGiftNotify +import com.chwl.app.notify.views.TestNotify +import com.chwl.app.support.float.FloatView +import com.chwl.app.support.float.FloatViewAdapter +import com.chwl.app.support.float.FloatWindow +import com.chwl.core.gift.bean.LuckyBagNoticeInfo +import com.chwl.core.home.bean.BannerInfo.SKIP_TYPE_ROOM_BAI_SHUN +import com.chwl.core.im.custom.bean.CustomAttachment +import com.chwl.core.im.custom.bean.RoomBoxPrizeAttachment +import com.chwl.core.im.custom.bean.RoomTemplateNotifyMsgBean +import com.chwl.core.noble.bean.AllServiceGiftProtocol + + +class NotifyAdapter : FloatViewAdapter { + var onShowUserCard: ((String) -> Unit)? = null + //xxx 通用飘屏 + override fun onCreateFloatView(context: Context, item: Any): FloatView? { + when (item) { + // 通用飘屏 + is RoomTemplateNotifyMsgBean -> { + if (item.skipType == SKIP_TYPE_ROOM_BAI_SHUN) { + return BaiShunGameNotify(context).apply { + onShowUserCard = this@NotifyAdapter.onShowUserCard + } + }else if (item.resourceType == RoomTemplateNotifyMsgBean.TYPE_IMAGE) { + return TemplateImageNotify(context).apply { + onShowUserCard = this@NotifyAdapter.onShowUserCard + } + } else if (item.resourceType == RoomTemplateNotifyMsgBean.TYPE_SVGA) { + return TemplateSvgaNotify(context).apply { + onShowUserCard = this@NotifyAdapter.onShowUserCard + } + } + } + + // 寻爱 + is RoomBoxPrizeAttachment -> { + if (item.second == CustomAttachment.CUSTOM_MSG_SUB_BOX_ALL_ROOM_NOTIFY_BY_SVGA) { + return FindLoveImageNotify(context, true) + } else if (item.second == CustomAttachment.CUSTOM_MSG_SUB_BOX_ALL_ROOM_NOTIFY) { + return FindLoveImageNotify(context, false) + } else { + return null + } + } + + // 礼物 + is AllServiceGiftProtocol.DataBean -> { + return GiftNotify(context) + } + + // 福袋礼物 + is LuckyBagNoticeInfo -> { + return LuckyBagGiftNotify(context) + } + + // 测试用 + is String -> { + return TestNotify(context) + } + + else -> { + return null + } + } + return null + } + + override fun onBindFloatView(window: FloatWindow, floatView: FloatView, item: Any) { + floatView.onAttached(window, item) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/notify/RoomNotifyManager.kt b/app/src/main/java/com/chwl/app/notify/RoomNotifyManager.kt new file mode 100644 index 0000000..8a5f8b7 --- /dev/null +++ b/app/src/main/java/com/chwl/app/notify/RoomNotifyManager.kt @@ -0,0 +1,131 @@ +package com.chwl.app.notify + +import androidx.fragment.app.FragmentActivity +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleEventObserver +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.lifecycleScope +import com.chwl.app.base.TitleBar +import com.chwl.app.support.float.DoubleQueue +import com.chwl.app.support.float.FloatWindowEngine +import com.chwl.app.support.float.SimpleFloatQueue +import com.chwl.app.support.float.SimpleFloatWindow +import com.chwl.core.im.custom.bean.RoomBoxPrizeAttachment +import com.chwl.core.im.custom.bean.RoomReceivedLuckyGiftAttachment +import com.chwl.core.im.custom.bean.RoomTemplateNotifyAttachment +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.manager.IMNetEaseManager +import com.chwl.core.manager.RoomEvent +import com.chwl.library.common.util.doLog +import com.example.lib_utils.log.ILog +import com.netease.nim.uikit.common.util.sys.ScreenUtil +import io.reactivex.disposables.CompositeDisposable +import kotlinx.coroutines.cancel + +/** + * Created by Max on 2024/3/22 14:47 + * Desc: + **/ +class RoomNotifyManager(activity: FragmentActivity) : LifecycleEventObserver, ILog { + val queue = SimpleFloatQueue() + + private val compositeDisposable: CompositeDisposable = CompositeDisposable() + + var onShowUserCard: ((String) -> Unit)? = null + + init { + bindActivity(activity) + } + + private fun bindActivity(activity: FragmentActivity) { + activity.lifecycleScope.launchWhenStarted { + bindActivityImpl(activity) + this.cancel() + } + activity.lifecycle.addObserver(this) + } + + private fun bindActivityImpl(activity: FragmentActivity) { + val widget = SimpleFloatWindow(activity) + widget.maxVisibleCount = 1 + widget.bindActivity(activity) + widget.adapter = NotifyAdapter() + var statusHeight = TitleBar.getStatusBarHeight() + if (statusHeight <= 0) { + statusHeight = ScreenUtil.getStatusBarHeight(activity) + } + widget.getView().setPadding(0, statusHeight, 0, 0) + val queue = DoubleQueue(GlobalNotifyManager.queue, queue) + val engine = FloatWindowEngine(widget, queue) + engine.interceptor = { _ -> + if (AvRoomDataManager.get().isSelfGamePlaying) { + -1 + } else { + 0 + } + } + engine.bindLifecycle(activity.lifecycle) + engine.start() + } + + fun start() { + compositeDisposable.add( + IMNetEaseManager.get().chatRoomEventObservable + .subscribe { roomEvent: RoomEvent? -> + if (roomEvent == null) return@subscribe + try { + onReceiveChatRoomEvent(roomEvent) + } catch (e: Exception) { + e.printStackTrace() + } + }) + } + + fun stop() { + if (!compositeDisposable.isDisposed) { + compositeDisposable.dispose() + } + } + + override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) { + when (event) { + Lifecycle.Event.ON_DESTROY -> { + stop() + } + + else -> { + + } + } + } + + private fun onReceiveChatRoomEvent(roomEvent: RoomEvent) { +// if (BuildConfig.DEBUG) { +// "通用飘屏 监听器 RoomNotifyManager 房间内 ${JSON.toJSONString(roomEvent)}".doLog() +// } + //xxx 通用飘屏 房间内 + when (roomEvent.event) { + // 通用模版 + RoomEvent.TEMPLATE_NOTIFY -> { + val attachment = roomEvent.chatRoomMessage.attachment as? RoomTemplateNotifyAttachment + val data = attachment?.getTemplateMsg() ?: return + queue.addLast(data) + "通用飘屏 监听器 RoomNotifyManager 房间内 通用模版".doLog() + } + + // 寻爱 + RoomEvent.BOX_NOTIFY, RoomEvent.BOX_NOTIFY_SVGA -> { + val attachment = roomEvent.chatRoomMessage.attachment as? RoomBoxPrizeAttachment ?: return + queue.addLast(attachment) + "通用飘屏 监听器 RoomNotifyManager 房间内 寻爱".doLog() + } + + // 福袋 + RoomEvent.RECEIVE_ROOM_LUCKY_BAG_NOTICE, RoomEvent.RECEIVE_SERVICE_LUCKY_BAG_NOTICE -> { + val message = (roomEvent.chatRoomMessage.attachment as? RoomReceivedLuckyGiftAttachment)?.luckyBagNoticeInfo ?: return + queue.addLast(message) + "通用飘屏 监听器 RoomNotifyManager 房间内 福袋".doLog() + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/notify/views/BaiShunGameNotify.kt b/app/src/main/java/com/chwl/app/notify/views/BaiShunGameNotify.kt new file mode 100644 index 0000000..d353735 --- /dev/null +++ b/app/src/main/java/com/chwl/app/notify/views/BaiShunGameNotify.kt @@ -0,0 +1,180 @@ +package com.chwl.app.notify.views + +import android.content.Context +import android.graphics.Color +import android.view.LayoutInflater +import android.widget.ImageView +import android.widget.TextView +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.constraintlayout.widget.Group +import com.chwl.app.R +import com.chwl.app.avroom.widget.TemplateMessageAdapter +import com.chwl.app.avroom.widget.VDHLayout +import com.chwl.app.common.widget.CircleImageView +import com.chwl.app.support.float.BaseFloatView +import com.chwl.app.ui.utils.loadImage +import com.chwl.core.gift.event.NotifyEvent +import com.chwl.core.im.custom.bean.RoomTemplateNotifyMsgBean +import com.chwl.core.im.custom.bean.TemplateMessage.Content +import com.chwl.library.common.util.isVerify +import com.chwl.library.common.util.setVis +import com.chwl.library.widget.SVGAView +import com.opensource.svgaplayer.SVGADrawable +import com.opensource.svgaplayer.SVGAParser +import com.opensource.svgaplayer.SVGAVideoEntity +import org.greenrobot.eventbus.EventBus +import java.net.URL + +class BaiShunGameNotify(context: Context) : BaseFloatView(context), + TemplateMessageAdapter.Listener { + + private val templateMessageAdapter = TemplateMessageAdapter(this) + + var onShowUserCard: ((String) -> Unit)? = null + + init { + LayoutInflater.from(context).inflate(R.layout.layout_template_notify_baishun, this, true) + } + + override fun onBind(item: Any) { + val data = item as? RoomTemplateNotifyMsgBean + if (data == null) { + requestRemoveSelf() + return + } + + val svgaView = findViewById(R.id.iv_bg) + val textView = findViewById(R.id.tv_text) + + if (data.resourceType == RoomTemplateNotifyMsgBean.TYPE_SVGA && data.resourceContent.isVerify()) { + SVGAParser.shareParser().decodeFromURL( + URL(data.resourceContent), + object : SVGAParser.ParseCompletion { + override fun onComplete(videoItem: SVGAVideoEntity) { + val width = videoItem.videoSize.width + val height = videoItem.videoSize.height + var dimensionRatio = "75:11" + if (width > 0 && height > 0) { + dimensionRatio = "$width:$height" + } + val params = svgaView.layoutParams as ConstraintLayout.LayoutParams + params.dimensionRatio = dimensionRatio + svgaView.layoutParams = params + val drawable = SVGADrawable(videoItem) + svgaView.setImageDrawable(drawable) + svgaView.startAnimation() + setView2(data,textView) + } + + override fun onError() { + requestRemoveSelf() + } + }, + null + ) + } else { + svgaView.loadFile("svga/baishun_notify_bg.svga") + setView2(data,textView) + } + + + findViewById(R.id.vdhLayout).setListener { + requestRemoveSelf() + } + } + +// private fun setView(data:RoomTemplateNotifyMsgBean,textView:TextView) { +// val textSize = data.fontSize?.toFloat() ?: 12f +// val textColor = templateMessageAdapter.parseColor(data.textColor) ?: Color.WHITE +// textView.textSize = textSize +// textView.setTextColor(textColor) +// startEnterAnim() +// templateMessageAdapter.convert(textView, data) +// val go = findViewById(R.id.go) +// go.setVis(true) +// go.setOnClickListener { +// val event = NotifyEvent() +// event.action = NotifyEvent.Action.ACT_BAI_SHUN_GAME +// event.data = data.skipContent +// EventBus.getDefault().post(event) +// } +// startDelayRemove() +// } + + private fun setView2(data:RoomTemplateNotifyMsgBean,textView:TextView) { + + + var gameIcon = "" + var avatar = "" + var nick = "" + var diamondNum = "" + val contents = data.contents + val firstText = data.template?.getFirstText() + if (contents.isVerify()) { + contents?.forEachIndexed { index, content -> + if (content.type == Content.TEXT){ + if (content.key == "nick"){ + nick = content.text?.getFirstText()?:"" + }else if (content.key == "diamondNum"){ + diamondNum = content.text?.getFirstText()?:"" + } + }else if (content.type == Content.IMAGE){ + if (content.key == "gameIcon"){ + gameIcon = content.image ?:"" + }else if (content.key == "avatar"){ + avatar = content.image ?:"" + } + } + } + } + + if (gameIcon.isVerify()) { + val gameIconView = findViewById(R.id.gameIcon) + gameIconView.loadImage(gameIcon) + } + + if (avatar.isVerify()) { + val avatarView = findViewById(R.id.avatar) + avatarView.loadImage(avatar) + } + + // "{gameIcon} {avatar} {nick} Win {diamondNum} Coins" +// if (firstText.isVerify()) { +// val replaceGameIcon = firstText?.replace("{gameIcon}","") +// val replaceAvatar = replaceGameIcon?.replace("{avatar}","") +// val replaceNick = replaceAvatar?.replace("{nick}",nick) +// val replaceDiamondNum = replaceNick?.replace("{diamondNum}",diamondNum) +// var newText = replaceDiamondNum +// if (newText.isVerify()) { +// val spStr = SpannableString(newText) +// val start: Int = newText!!.indexOf(nick) +// val end = start + nick.length +// val colorSpan = ForegroundColorSpan(Color.parseColor("#FF3b3b")) +// spStr.setSpan(colorSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) +// } +// } + + val textSize = data.fontSize?.toFloat() ?: 12f + val textColor = templateMessageAdapter.parseColor(data.textColor) ?: Color.WHITE + textView.textSize = textSize + textView.setTextColor(textColor) + templateMessageAdapter.convertText(textView, data) + + val go = findViewById(R.id.go) + go.setVis(true) + go.setOnClickListener { + val event = NotifyEvent() + event.action = NotifyEvent.Action.ACT_BAI_SHUN_GAME + event.data = data.skipContent + EventBus.getDefault().post(event) + } + val allView = findViewById(R.id.allView) + startEnterAnim() + allView.setVis(true) + startDelayRemove() + } + + override fun onShowUserCard(uid: String) { + onShowUserCard?.invoke(uid) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/notify/views/FindLoveImageNotify.kt b/app/src/main/java/com/chwl/app/notify/views/FindLoveImageNotify.kt new file mode 100644 index 0000000..7c50229 --- /dev/null +++ b/app/src/main/java/com/chwl/app/notify/views/FindLoveImageNotify.kt @@ -0,0 +1,62 @@ +package com.chwl.app.notify.views + +import android.content.Context +import android.graphics.Color +import android.text.style.ForegroundColorSpan +import android.view.LayoutInflater +import android.widget.ImageView +import android.widget.TextView +import com.chwl.app.R +import com.chwl.app.support.float.BaseFloatView +import com.chwl.app.utils.SpannableBuilder +import com.chwl.core.im.custom.bean.RoomBoxPrizeAttachment +import com.chwl.core.utils.extension.subAndReplaceDot +import com.example.lib_utils.UiUtils + + +class FindLoveImageNotify(context: Context, val isHeightLevel: Boolean) : BaseFloatView(context) { + + init { + LayoutInflater.from(context).inflate(R.layout.layout_template_notify_image, this, true) + } + + override fun onBind(item: Any) { + val data = item as? RoomBoxPrizeAttachment + if (data == null) { + requestRemoveSelf() + return + } + val textView = findViewById(R.id.tv_text) + textView.textSize = 12f + textView.setTextColor(Color.WHITE) + val text = SpannableBuilder() + .append( + "厲害了!", + ForegroundColorSpan(Color.WHITE) + ) + .append( + data.nick.subAndReplaceDot(8), + ForegroundColorSpan(resources.getColor(R.color.color_FFE44E)) + ) + .append( + "通過歡樂砸蛋獲得\n", ForegroundColorSpan(Color.WHITE) + ) + .append( + data.prizeName, + ForegroundColorSpan(resources.getColor(R.color.color_FFE44E)) + ) + if (data.prizeNum > 1) { + text.append("x" + data.prizeNum, ForegroundColorSpan(Color.WHITE)) + } + textView.text = text.build() + textView.setPadding(0, UiUtils.dip2px(2f), 0, 0) + val bgView = findViewById(R.id.iv_bg) + if (isHeightLevel) { + bgView.setImageResource(R.drawable.smash_eggs_notity_bg_5) + } else { + bgView.setImageResource(R.drawable.smash_eggs_notity_bg_4) + } + startEnterAnim() + startDelayRemove() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/notify/views/GiftNotify.kt b/app/src/main/java/com/chwl/app/notify/views/GiftNotify.kt new file mode 100644 index 0000000..39fb960 --- /dev/null +++ b/app/src/main/java/com/chwl/app/notify/views/GiftNotify.kt @@ -0,0 +1,132 @@ +package com.chwl.app.notify.views + +import android.content.Context +import android.view.LayoutInflater +import android.view.ViewConfiguration +import android.widget.TextView +import androidx.core.view.isVisible +import com.chwl.app.R +import com.chwl.app.avroom.activity.AVRoomActivity +import com.chwl.app.databinding.LayoutGiftNotifyBinding +import com.chwl.app.support.float.BaseFloatView +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.app.ui.widget.dialog.AllServiceGiftGoRoomTipsDialog +import com.chwl.core.noble.bean.AllServiceGiftProtocol +import com.chwl.core.utils.myutil.MySpanUtils +import com.example.lib_utils.ktx.getColorById +import com.example.lib_utils.ktx.getDimension +import com.example.lib_utils.ktx.singleClick +import com.example.lib_utils.spannable.SpannableTextBuilder + +//xxx VIP 送礼飘屏 +class GiftNotify(context: Context) : BaseFloatView(context) { + private val view = TextView(context) + + private var binding: LayoutGiftNotifyBinding? = null + + companion object { + private var marqueeError = false + } + + init { + binding = LayoutGiftNotifyBinding.inflate(LayoutInflater.from(context), this, true) + } + + override fun onBind(item: Any) { + view.text = item.toString() + val data = item as? AllServiceGiftProtocol.DataBean + val binding = binding + if (data == null || binding == null) { + requestRemoveSelf() + return + } + bindData(data, binding) + startEnterAnim() + var stayTime = (data.notifyStaySecond * 1000L).toLong() + if (stayTime <= 0) { + stayTime = 5000L + } + startDelayRemove(stayTime) + + binding.vdhLayout.setListener { + requestRemoveSelf() + } + } + + private fun bindData(data: AllServiceGiftProtocol.DataBean, binding: LayoutGiftNotifyBinding) { + + val svga = "svga/gift_notify_${data.bgLevel}.svga" + binding.rootBg.loadFile(svga) + + ImageLoadUtils.loadAvatar(data.sendUserAvatar ?: "", binding.ivAvatar) + + val message = context.getString(R.string.all_gift_message_format).format(data.sendUserNick ?: "", data.recvUserNick ?: "","") + SpannableTextBuilder(binding.tvNames).appendText(message) + .setTextStyle( + data.sendUserNick ?: "", + binding.tvNames.context.getColorById(R.color.color_FFE468) + ) + .setTextStyle( + data.recvUserNick + " ", + binding.tvNames.context.getColorById(R.color.color_FFE468) + ).apply() + setupTextMarquee(binding.tvNames) + + + MySpanUtils.with(binding.tvGiftCount) + .append(data.giftName).setFontSize(R.dimen.sp_11.getDimension().toInt(),false) + .append(" X") + .append(data.giftNum.toString()).setFontSize(17,true).setBold() + .create() + + ImageLoadUtils.loadImage(binding.ivGift.getContext(), data.giftUrl, binding.ivGift) + + + binding.tvRoomName.text = data.roomTitle + binding.groupRoom.isVisible = data.roomUid != 0L + + binding.tvRoomName.singleClick { + goRoom(data) + } + binding.tvRoomGo.singleClick { + goRoom(data) + } + + } + + /** + * 添加跑马灯 + * 以及反射一些参数影响跑马灯 + */ + private fun setupTextMarquee(view: TextView) { + view.isSelected = true + if (marqueeError) { + return + } + try { + val configuration = ViewConfiguration.get( + context + ) + val claz: Class<*> = configuration.javaClass + val field = claz.getDeclaredField("mFadingMarqueeEnabled") + field.isAccessible = true + field[configuration] = true + } catch (e: Exception) { + e.printStackTrace() + marqueeError = true + } + } + + private fun goRoom(data: AllServiceGiftProtocol.DataBean) { + if (data.roomUid <= 0L) { + // 非房间场景送的礼物 + return + } + if (AllServiceGiftGoRoomTipsDialog.isNeedTips()) { + AllServiceGiftGoRoomTipsDialog(context, data.roomTitle ?: "", data.roomUid).show() + } else { + AVRoomActivity.start(context, data.roomUid) + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/notify/views/LuckyBagGiftNotify.kt b/app/src/main/java/com/chwl/app/notify/views/LuckyBagGiftNotify.kt new file mode 100644 index 0000000..b5cb25e --- /dev/null +++ b/app/src/main/java/com/chwl/app/notify/views/LuckyBagGiftNotify.kt @@ -0,0 +1,108 @@ +package com.chwl.app.notify.views + +import android.content.Context +import android.view.LayoutInflater +import android.widget.TextView +import androidx.constraintlayout.widget.ConstraintLayout +import com.chwl.app.R +import com.chwl.app.avroom.activity.AVRoomActivity +import com.chwl.app.databinding.LayoutLuckyBagGiftNotifyBinding +import com.chwl.app.support.float.BaseFloatView +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.app.ui.widget.dialog.AllServiceGiftGoRoomTipsDialog +import com.chwl.core.gift.bean.LuckyBagNoticeInfo +import com.chwl.core.utils.extension.subAndReplaceDot +import com.example.lib_utils.ktx.getColorById +import com.example.lib_utils.ktx.singleClick +import com.example.lib_utils.spannable.SpannableTextBuilder +import java.text.MessageFormat + +class LuckyBagGiftNotify(context: Context) : BaseFloatView(context) { + private val view = TextView(context) + + private var binding: LayoutLuckyBagGiftNotifyBinding? = null + + init { + binding = LayoutLuckyBagGiftNotifyBinding.inflate(LayoutInflater.from(context), this, true) + val params = binding?.root?.layoutParams as? ConstraintLayout.LayoutParams + params?.dimensionRatio = "375:71" + binding?.root?.layoutParams = params + } + + override fun onBind(item: Any) { + view.text = item.toString() + val data = item as? LuckyBagNoticeInfo + val binding = binding + if (data == null || binding == null) { + requestRemoveSelf() + return + } + bindData(data, binding) + startEnterAnim() + startDelayRemove() + } + + private fun bindData( + data: LuckyBagNoticeInfo, + binding: LayoutLuckyBagGiftNotifyBinding + ) { + binding.ivBag.singleClick { + goRoom(data) + } + binding.ivGift.singleClick { + goRoom(data) + } + ImageLoadUtils.loadImage(binding.ivBag.context, data.luckyBagGiftPic, binding.ivBag) + ImageLoadUtils.loadImage(binding.ivGift.context, data.giftPic, binding.ivGift) + + val userName = data.nick.subAndReplaceDot(6) + val bagName = data.luckyBagName + val giftName = data.giftName + val price = data.goldPrice + val num = data.giftNum.toString() + val message = if (data.giftNum > 1) { + MessageFormat.format( + context.getString(R.string.gift_message_08), userName, bagName, price, giftName, num + ) + } else { + MessageFormat.format( + context.getString(R.string.gift_message_07), + userName, + bagName, + price, + giftName + ) + } + SpannableTextBuilder(binding.tvMessage).appendText(message) + .setTextStyle( + userName, + binding.tvMessage.context.getColorById(R.color.color_FFE468) + ) + .setTextStyle( + bagName, + binding.tvMessage.context.getColorById(R.color.color_FFE468) + ) + .setTextStyle( + price, + binding.tvMessage.context.getColorById(R.color.color_FFE468) + ).setTextStyle( + giftName, + binding.tvMessage.context.getColorById(R.color.color_FFE468) + ).apply() + } + + private fun goRoom( + data: LuckyBagNoticeInfo + ) { + if (data.roomUid <= 0L) { + // 非房间场景送的礼物 + return + } + if (AllServiceGiftGoRoomTipsDialog.isNeedTips()) { + AllServiceGiftGoRoomTipsDialog(context, data.roomTitle ?: "", data.roomUid).show() + } else { + AVRoomActivity.start(context, data.roomUid) + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/notify/views/TemplateImageNotify.kt b/app/src/main/java/com/chwl/app/notify/views/TemplateImageNotify.kt new file mode 100644 index 0000000..cc61412 --- /dev/null +++ b/app/src/main/java/com/chwl/app/notify/views/TemplateImageNotify.kt @@ -0,0 +1,100 @@ +package com.chwl.app.notify.views + +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.Drawable +import android.view.LayoutInflater +import android.view.View +import android.widget.ImageView +import android.widget.TextView +import com.bumptech.glide.request.target.CustomTarget +import com.bumptech.glide.request.transition.Transition +import com.chwl.app.R +import com.chwl.app.avroom.widget.TemplateMessageAdapter +import com.chwl.app.avroom.widget.VDHLayout +import com.chwl.app.support.float.BaseFloatView +import com.chwl.app.utils.CommonJumpHelper +import com.chwl.core.home.bean.BannerInfo +import com.chwl.core.im.custom.bean.RoomTemplateNotifyMsgBean +import com.netease.nim.uikit.support.glide.GlideApp + + +class TemplateImageNotify(context: Context) : BaseFloatView(context), + TemplateMessageAdapter.Listener { + + private val templateMessageAdapter = TemplateMessageAdapter(this) + + var onShowUserCard: ((String) -> Unit)? = null + + init { + LayoutInflater.from(context).inflate(R.layout.layout_template_notify_image, this, true) + } + + override fun onBind(item: Any) { + val data = item as? RoomTemplateNotifyMsgBean + if (data == null) { + requestRemoveSelf() + return + } + if (data.resourceType != RoomTemplateNotifyMsgBean.TYPE_IMAGE) { + requestRemoveSelf() + return + } + val resourceContent = data.resourceContent + if (resourceContent.isNullOrEmpty()) { + requestRemoveSelf() + return + } + + val textView = findViewById(R.id.tv_text) + val textSize = data.fontSize?.toFloat() ?: 12f + val textColor = + templateMessageAdapter.parseColor(data.textColor) ?: Color.WHITE + textView.textSize = textSize + textView.setTextColor(textColor) + + val bgView = findViewById(R.id.iv_bg) + GlideApp.with(bgView) + .load(resourceContent).into(object : CustomTarget() { + override fun onResourceReady( + resource: Drawable, + transition: Transition? + ) { + templateMessageAdapter.convert(textView, data) + bgView.setImageDrawable(resource) + startEnterAnim() + val skipType = data.skipType + if (skipType != null) { + val clickAction = View.OnClickListener { + if (skipType == BannerInfo.SKIP_TYPE_ROOM_USER_CARD) { + onShowUserCard?.invoke(data.skipContent ?: "") + } else { + CommonJumpHelper.bannerJump(context, skipType, data.skipContent) + } + } + setOnClickListener(clickAction) + textView.setOnClickListener(clickAction) + } + startDelayRemove() + } + + override fun onLoadCleared(placeholder: Drawable?) { + requestRemoveSelf() + } + + override fun onLoadFailed(errorDrawable: Drawable?) { + super.onLoadFailed(errorDrawable) + requestRemoveSelf() + } + }) + + + findViewById(R.id.vdhLayout).setListener { + requestRemoveSelf() + } + } + + override fun onShowUserCard(uid: String) { + onShowUserCard?.invoke(uid) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/notify/views/TemplateSvgaNotify.kt b/app/src/main/java/com/chwl/app/notify/views/TemplateSvgaNotify.kt new file mode 100644 index 0000000..0473256 --- /dev/null +++ b/app/src/main/java/com/chwl/app/notify/views/TemplateSvgaNotify.kt @@ -0,0 +1,106 @@ +package com.chwl.app.notify.views + +import android.content.Context +import android.graphics.Color +import android.view.LayoutInflater +import android.view.View +import android.widget.TextView +import androidx.constraintlayout.widget.ConstraintLayout +import com.chwl.app.R +import com.chwl.app.avroom.widget.TemplateMessageAdapter +import com.chwl.app.avroom.widget.VDHLayout +import com.chwl.app.support.float.BaseFloatView +import com.chwl.app.utils.CommonJumpHelper +import com.chwl.core.home.bean.BannerInfo +import com.chwl.core.im.custom.bean.RoomTemplateNotifyMsgBean +import com.example.lib_utils.log.ILog +import com.opensource.svgaplayer.SVGADrawable +import com.opensource.svgaplayer.SVGAImageView +import com.opensource.svgaplayer.SVGAParser +import com.opensource.svgaplayer.SVGAVideoEntity +import java.net.URL + + +class TemplateSvgaNotify(context: Context) : BaseFloatView(context), + TemplateMessageAdapter.Listener, ILog { + + private val templateMessageAdapter = TemplateMessageAdapter(this) + + var onShowUserCard: ((String) -> Unit)? = null + + init { + LayoutInflater.from(context).inflate(R.layout.layout_template_notify_svga, this, true) + } + + override fun onBind(item: Any) { + val data = item as? RoomTemplateNotifyMsgBean + if (data == null) { + requestRemoveSelf() + return + } + if (data.resourceType != RoomTemplateNotifyMsgBean.TYPE_SVGA) { + requestRemoveSelf() + return + } + val resourceContent = data.resourceContent + if (resourceContent.isNullOrEmpty()) { + requestRemoveSelf() + return + } + val textView = findViewById(R.id.tv_text) + val textSize = data.fontSize?.toFloat() ?: 12f + val textColor = + templateMessageAdapter.parseColor(data.textColor) ?: Color.WHITE + textView.textSize = textSize + textView.setTextColor(textColor) + + val svgaView = findViewById(R.id.iv_bg) + SVGAParser.shareParser().decodeFromURL( + URL(resourceContent), + object : SVGAParser.ParseCompletion { + override fun onComplete(videoItem: SVGAVideoEntity) { + val width = videoItem.videoSize.width + val height = videoItem.videoSize.height + var dimensionRatio = "75:11" + if (width > 0 && height > 0) { + dimensionRatio = "$width:$height" + } + val params = svgaView.layoutParams as ConstraintLayout.LayoutParams + params.dimensionRatio = dimensionRatio + svgaView.layoutParams = params + val skipType = data.skipType + if (skipType != null) { + val clickAction = View.OnClickListener { + if (skipType == BannerInfo.SKIP_TYPE_ROOM_USER_CARD) { + onShowUserCard?.invoke(data.skipContent ?: "") + } else { + CommonJumpHelper.bannerJump(context, skipType, data.skipContent) + } + } + setOnClickListener(clickAction) + textView.setOnClickListener(clickAction) + } + val drawable = SVGADrawable(videoItem) + svgaView.setImageDrawable(drawable) + svgaView.startAnimation() + templateMessageAdapter.convert(textView, data) + startEnterAnim() + startDelayRemove() + } + + override fun onError() { + requestRemoveSelf() + } + }, + null + ) + + findViewById(R.id.vdhLayout).setListener { + requestRemoveSelf() + } + } + + override fun onShowUserCard(uid: String) { + onShowUserCard?.invoke(uid) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/notify/views/TestNotify.kt b/app/src/main/java/com/chwl/app/notify/views/TestNotify.kt new file mode 100644 index 0000000..75a6dc1 --- /dev/null +++ b/app/src/main/java/com/chwl/app/notify/views/TestNotify.kt @@ -0,0 +1,30 @@ +package com.chwl.app.notify.views + +import android.content.Context +import android.graphics.Color +import android.view.ViewGroup +import android.widget.TextView +import com.chwl.app.support.float.BaseFloatView + +class TestNotify(context: Context) : BaseFloatView(context) { + private val view = TextView(context) + + init { + addView( + view, + ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ) + ) + setBackgroundColor(Color.parseColor("#44FFFFFF")) + view.setTextColor(Color.RED) + view.textSize = 30f + } + + override fun onBind(item: Any) { + view.text = item.toString() + startEnterAnim() + startDelayRemove() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/other/SplashBitmapTransformation.java b/app/src/main/java/com/chwl/app/other/SplashBitmapTransformation.java new file mode 100644 index 0000000..7709f2c --- /dev/null +++ b/app/src/main/java/com/chwl/app/other/SplashBitmapTransformation.java @@ -0,0 +1,54 @@ +package com.chwl.app.other; + +import android.graphics.Bitmap; + +import androidx.annotation.NonNull; + +import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; +import com.bumptech.glide.load.resource.bitmap.BitmapTransformation; + +import java.security.MessageDigest; + +/** + * splash 适配图片 + */ +public class SplashBitmapTransformation extends BitmapTransformation { + private static final String ID = "com.chwl.app.other.SplashBitmapTransformation"; + private static final byte[] ID_BYTES = ID.getBytes(CHARSET); + + public SplashBitmapTransformation() { + } + + @Override + protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) { + //glide 会自动计算好一边图片的大小(宽或者高) + int srcWidth = toTransform.getWidth(); + int srcHeight = toTransform.getHeight(); + int yOffset = srcHeight - outHeight; + int xOffset = (srcWidth - outWidth) / 2; + Bitmap bitmap; + if (yOffset > 0) { + bitmap = Bitmap.createBitmap(toTransform, 0, yOffset, outWidth, outHeight); + } else if (xOffset > 0) { + bitmap = Bitmap.createBitmap(toTransform, xOffset, 0, outWidth, outHeight); + } else { + bitmap = toTransform; + } + return bitmap; + } + + @Override + public void updateDiskCacheKey(MessageDigest messageDigest) { + messageDigest.update(ID_BYTES); + } + + @Override + public int hashCode() { + return ID.hashCode(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof SplashBitmapTransformation; + } +} diff --git a/app/src/main/java/com/chwl/app/other/activity/SplashActivity.java b/app/src/main/java/com/chwl/app/other/activity/SplashActivity.java new file mode 100644 index 0000000..91adb5b --- /dev/null +++ b/app/src/main/java/com/chwl/app/other/activity/SplashActivity.java @@ -0,0 +1,343 @@ +package com.chwl.app.other.activity; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.Intent; +import android.content.res.Configuration; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; +import android.view.animation.AlphaAnimation; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; +import androidx.databinding.DataBindingUtil; + +import com.chwl.app.MainActivity; +import com.chwl.app.NimMiddleActivity; +import com.chwl.app.R; +import com.chwl.app.databinding.ActivitySplashBinding; +import com.chwl.app.ui.login.LoginPasswordActivity; +import com.chwl.app.utils.HomeUIManager; +import com.chwl.core.DemoCache; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.auth.entity.AccountInfo; +import com.chwl.core.bean.response.result.TicketResult; +import com.chwl.core.gift.GiftModel; +import com.chwl.core.home.bean.ConfigInfo; +import com.chwl.core.initial.InitialModel; +import com.chwl.core.initial.bean.SplashComponent; +import com.chwl.core.utils.LogUtils; +import com.chwl.core.utils.OaidUtil; +import com.chwl.core.utils.SharedPreferenceUtils; +import com.chwl.library.common.util.DeviceUtil; +import com.chwl.library.common.util.OtherExtKt; +import com.chwl.library.language.LanguageHelper; +import com.chwl.library.net.rxnet.utils.NetworkLatencyChecker; +import com.chwl.library.utils.SingleToastUtil; +import com.example.lib_utils.log.LogUtil; +import com.netease.nim.uikit.StatusBarUtil; + +import java.util.concurrent.TimeUnit; + +import io.reactivex.SingleObserver; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.disposables.Disposable; +import io.reactivex.functions.Consumer; + +/** + * @author xiaoyu + * @date 2017/12/30 + */ +public class SplashActivity extends AppCompatActivity implements View.OnClickListener { + + public static final String SHOW_PRIVACY_AGREEMENT = "show_privacy_agreement"; + private static final int COUNT_DOWN_TIME = 3; + private ActivitySplashBinding mBinding; + private SplashComponent mLocalSplashVo; + + private CompositeDisposable disposable = new CompositeDisposable(); + + // ticket状态 -1:加载失败、0:加载中、1:加载成功 + private int ticketState = 0; + + private volatile boolean needJump = false; + + private Runnable jumpRunnable; + + + public static void start(Context context) { + Intent starter = new Intent(context, SplashActivity.class); + context.startActivity(starter); + } + + // 旧启动逻辑 +// @Override +// protected void onCreate(Bundle savedInstanceState) { +// super.onCreate(savedInstanceState); +// NimMiddleActivity.delayOpenCommunity = true; +// //修复 https://blog.csdn.net/u011153817/article/details/77335255 +// // https://blog.csdn.net/zhangcanyan/article/details/52777265 这样的启动异常问题. +// if (!isTaskRoot()) { +// AccountInfo currentAccountInfo = DemoCache.readCurrentAccountInfo(); +// if (currentAccountInfo == null || TextUtils.isEmpty(currentAccountInfo.getAccess_token())) { +// LoginPasswordActivity.start(this); +// } else { +// MainActivity.start(SplashActivity.this); +// } +// return; +// } +// +// mBinding = DataBindingUtil.setContentView(this, R.layout.activity_splash); +// mBinding.setClick(this); +// if (savedInstanceState != null) { +// // 从堆栈恢复,不再重复解析之前的intent +// setIntent(new Intent()); +// } +// StatusBarUtil.transparencyBar(this); +// StatusBarUtil.StatusBarLightMode(this); +// initTicket(); +// initiate(); +// } +// + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + OtherExtKt.doLog("启动页 onCreate()"); + NimMiddleActivity.delayOpenCommunity = true; + StatusBarUtil.transparencyBar(this); + StatusBarUtil.StatusBarLightMode(this); + + NetworkLatencyChecker.INSTANCE.getMCheckStatusData().observe(this,isCheck -> { + if (isCheck) { + OtherExtKt.doLog("启动页 onCreate() 域名准备就绪,执行启动页逻辑"); + splashCreate(savedInstanceState); + } + }); + + } + + + private void splashCreate(Bundle savedInstanceState) { + + //修复 https://blog.csdn.net/u011153817/article/details/77335255 + // https://blog.csdn.net/zhangcanyan/article/details/52777265 这样的启动异常问题. + if (!isTaskRoot()) { + AccountInfo currentAccountInfo = DemoCache.readCurrentAccountInfo(); + if (currentAccountInfo == null || TextUtils.isEmpty(currentAccountInfo.getAccess_token())) { + LoginPasswordActivity.start(this); + } else { + MainActivity.start(SplashActivity.this); + } + return; + } + + mBinding = DataBindingUtil.setContentView(this, R.layout.activity_splash); + mBinding.setClick(this); + if (savedInstanceState != null) { + // 从堆栈恢复,不再重复解析之前的intent + setIntent(new Intent()); + } + initTicket(); + initiate(); + } + + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + setIntent(intent); + } + + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(LanguageHelper.INSTANCE.wrapContext(newBase)); + LanguageHelper.INSTANCE.wrapContext(newBase.getApplicationContext()); + } + + @Override + public void onConfigurationChanged(@NonNull Configuration newConfig) { + super.onConfigurationChanged(newConfig); + LanguageHelper.INSTANCE.changeLanguage(this, LanguageHelper.INSTANCE.getCurrentLanguage()); + } + + @SuppressLint("CheckResult") + protected void initiate() { + boolean isShowPrivacyAgreement = (boolean) SharedPreferenceUtils.get(SHOW_PRIVACY_AGREEMENT, true); + if (isShowPrivacyAgreement) { + showSplash(true); + SharedPreferenceUtils.put(SHOW_PRIVACY_AGREEMENT, false); + } else { + showSplash(false); + } + } + //todo 展示闪屏 + //xxx , 周星自动化 + private void showSplash(boolean first) { + + if (!TextUtils.isEmpty(DeviceUtil.getAndroidID())) { + OaidUtil.setOaid(DeviceUtil.getAndroidID()); +// if (first) ChannelPageModel.get().checkAd(); + } + + mBinding.tvSkip.setVisibility(View.VISIBLE); + // 不过期的,并且已经下载出来图片的闪屏页数据 + mLocalSplashVo = InitialModel.get().getLocalSplashVo(); + if (mLocalSplashVo != null && !TextUtils.isEmpty(mLocalSplashVo.getPict())) { + + animation(); + //xxx 看下有没有图片适配问题 mLocalSplashVo.getType()==3 是图片 + mBinding.ivActivity.setTextView(25f); + mBinding.ivActivity.load(mLocalSplashVo.getPict(),mLocalSplashVo.getFillVo().getImgMap(), mLocalSplashVo.getFillVo().getTextMap()); + + OtherExtKt.doLog("闪屏页 -> getPict = "+ mLocalSplashVo.getPict()); + OtherExtKt.doLog("闪屏页 -> getImgMap = "+ mLocalSplashVo.getFillVo().getImgMap().toString()); + OtherExtKt.doLog("闪屏页 -> getTextMap = "+ mLocalSplashVo.getFillVo().getTextMap().toString()); + + if (mLocalSplashVo.getType() != 0 && !TextUtils.isEmpty(mLocalSplashVo.getLink())) { + + mBinding.ivActivity.setOnClickListener(v -> { + OtherExtKt.doLog("闪屏页 -> 点击了闪屏 status = "+(mLocalSplashVo == null)); + if (mLocalSplashVo == null) return; + String link = mLocalSplashVo.getLink(); + int type = mLocalSplashVo.getType(); + if (TextUtils.isEmpty(link) || type == 0) return; + needJump = true; + Intent intent = new Intent(); + intent.putExtra("url", link); + intent.putExtra("type", type); + jumpActivity(intent); + }); + } + } else { + jumpActivity(null); + } + } + + private void animation() { + AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1); + alphaAnimation.setDuration(500); + mBinding.ivActivity.startAnimation(alphaAnimation); + mBinding.ivActivity.postDelayed(() -> { + if (needJump) { + return; + } + jumpActivity(null); + }, COUNT_DOWN_TIME * 1000); + } + + public void jumpActivity(Intent intent) { + jumpRunnable = () -> jumpActivityImpl(intent); + next(); + } + + public void jumpActivityImpl(Intent intent) { + + InitialModel.get().loadConfig() + .doOnSuccess(new Consumer() { + @Override + public void accept(ConfigInfo config) throws Exception { + LogUtils.d(" loadConfig doOnSuccess data = " + config.appUiSetting.backgroundColor); + HomeUIManager.INSTANCE.setMConfigInfo(config); + doJumpActivityImpl(intent); + } + }) + .doOnError(new Consumer() { + @Override + public void accept(Throwable throwable) throws Exception { + LogUtils.d(" loadConfig doOnError error = " + throwable.getMessage()); + doJumpActivityImpl(intent); + } + }) + .timeout(2, TimeUnit.SECONDS, observer -> { + LogUtils.d(" loadConfig timeout timeout timeout"); + doJumpActivityImpl(intent); + }) + .subscribe(); + + } + + private void doJumpActivityImpl(Intent intent){ + if (!AuthModel.get().isLogin()) { + NimMiddleActivity.openCommunity = false; + LoginPasswordActivity.start(this); + finish(); + } else { + if (intent != null) { + NimMiddleActivity.delayOpenCommunity = false; + MainActivity.start(this, intent); + finish(); + } else { + NimMiddleActivity.delayOpenCommunity = false; + MainActivity.start(SplashActivity.this); + finish(); + } + } + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.tv_skip: + if (mLocalSplashVo == null) { + return; + } + needJump = true; + jumpActivity(null); + break; + default: + break; + } + + } + + private void initTicket() { + ticketState = 0; + if (!AuthModel.get().isLogin()) { + ticketState = -1; + next(); + return; + } + AuthModel.get().refreshTicket().subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) { + disposable.add(d); + } + + @Override + public void onSuccess(TicketResult ticketResult) { + LogUtil.d("SplashActivity", "initTicket onSuccess", false); + onTicketSuccess(); + ticketState = 1; + next(); + } + + @Override + public void onError(Throwable throwable) { + LogUtil.d("SplashActivity", "initTicket throwable:" + throwable.getMessage(), false); + SingleToastUtil.showToast(throwable.getMessage()); + AuthModel.get().reset(); + ticketState = -1; + next(); + } + }); + } + + private void onTicketSuccess() { + GiftModel.get().tryLoadGiftList(); + } + + private void next() { + if (ticketState != 0 && jumpRunnable != null) { + jumpRunnable.run(); + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (disposable != null && !disposable.isDisposed()) { + disposable.dispose(); + } + } +} diff --git a/app/src/main/java/com/chwl/app/other/dialog/PrivacyAgreementDialog.java b/app/src/main/java/com/chwl/app/other/dialog/PrivacyAgreementDialog.java new file mode 100644 index 0000000..80c680d --- /dev/null +++ b/app/src/main/java/com/chwl/app/other/dialog/PrivacyAgreementDialog.java @@ -0,0 +1,122 @@ +package com.chwl.app.other.dialog; + +import android.annotation.SuppressLint; +import android.app.Dialog; +import android.content.Context; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.method.LinkMovementMethod; +import android.text.style.ForegroundColorSpan; +import android.view.Gravity; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.TextView; + +import androidx.annotation.NonNull; + +import com.chwl.app.MainActivity; +import com.chwl.app.R; +import com.chwl.app.application.IReportConstants; +import com.chwl.app.application.ReportManager; +import com.chwl.app.common.widget.OriginalDrawStatusClickSpan; +import com.chwl.app.ui.webview.SimpleWebViewActivity; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.core.UriProvider; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.ScreenUtils; + +import java.util.HashMap; + +public class PrivacyAgreementDialog extends Dialog implements View.OnClickListener { + + private OnCallBack onCallBack; + + public PrivacyAgreementDialog(@NonNull Context context) { + super(context); + } + + public void setOnCallBack(OnCallBack onCallBack) { + this.onCallBack = onCallBack; + } + + @SuppressLint("SetTextI18n") + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.dialog_privacy_agreement); + TextView tvConfirm = findViewById(R.id.tv_confirm); + tvConfirm.setOnClickListener(this); + findViewById(R.id.btn_cancel).setOnClickListener(this); + tvConfirm.setEnabled(true); + tvConfirm.setText("同意"); + TextView tvDesc = findViewById(R.id.tv_desc); + String privacyAgreementTip = getContext().getString(R.string.tip_privacy_agreement); + String userAgreementTip = getContext().getString(R.string.tip_user_agreement); + String privacyAgreementDescTip = getContext().getString(R.string.tip_privacy_agreement_desc, privacyAgreementTip, userAgreementTip); + SpannableString ss = new SpannableString(privacyAgreementDescTip); + int privacyAgreementTipIndex = privacyAgreementDescTip.indexOf(privacyAgreementTip); + int userAgreementTipIndex = privacyAgreementDescTip.indexOf(userAgreementTip); + + + ss.setSpan(new ForegroundColorSpan(Color.parseColor("#34a7ff")), privacyAgreementTipIndex, privacyAgreementTipIndex + privacyAgreementTip.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + ss.setSpan(new OriginalDrawStatusClickSpan() { + @Override + public void onClick(@NonNull View widget) { + SimpleWebViewActivity.start(getContext(), UriProvider.getPrivacyAgreement()); + } + }, privacyAgreementTipIndex, privacyAgreementTipIndex + privacyAgreementTip.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + ss.setSpan(new ForegroundColorSpan(Color.parseColor("#34a7ff")), userAgreementTipIndex, userAgreementTipIndex + userAgreementTip.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + ss.setSpan(new OriginalDrawStatusClickSpan() { + @Override + public void onClick(@NonNull View widget) { + SimpleWebViewActivity.start(getContext(), UriProvider.getUserProtocolUrl()); + } + }, userAgreementTipIndex, userAgreementTipIndex + privacyAgreementTip.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + + tvDesc.setText(ss); + tvDesc.setMovementMethod(new LinkMovementMethod()); + Window window = getWindow(); + if (window == null) { + return; + } + WindowManager.LayoutParams lp = window.getAttributes(); + if (lp == null) { + return; + } + int screenWidth = ScreenUtils.getScreenWidth(getContext()); + + lp.width = (int) (screenWidth * .855 + .5f); + lp.gravity = Gravity.CENTER; + lp.height = UIUtil.dip2px(getContext(), 425); + + window.setAttributes(lp); + window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); + + //协议弹框展示 + HashMap map = new HashMap<>(2); + map.put(IReportConstants.MODULE, IReportConstants.MOLISTAR_LOGIN); + ReportManager.get().reportEvent(IReportConstants.AGREEMENT_SHOW, map); + } + + @Override + public void onClick(View v) { + //协议弹框展示 + HashMap map = new HashMap<>(5); + map.put(IReportConstants.CLICK_TYPE, IReportConstants.THREE); + map.put(IReportConstants.MODULE, IReportConstants.MOLISTAR_LOGIN); + map.put(IReportConstants.PAGE, IReportConstants.ONE); + ReportManager.get().reportEvent(IReportConstants.AGREEMENT_CLICK, map); + cancel(); + if (onCallBack != null) { + onCallBack.onFinish(v.getId() == R.id.tv_confirm); + } + } + + public interface OnCallBack { + void onFinish(boolean isConfirm); + } +} diff --git a/app/src/main/java/com/chwl/app/other/present/SplashPresenter.java b/app/src/main/java/com/chwl/app/other/present/SplashPresenter.java new file mode 100644 index 0000000..032be9c --- /dev/null +++ b/app/src/main/java/com/chwl/app/other/present/SplashPresenter.java @@ -0,0 +1,15 @@ +package com.chwl.app.other.present; + +import com.chwl.app.base.BaseMvpPresenter; +import com.chwl.app.other.view.ISplashView; + +/** + *

+ * + * @author jiahui + * @date 2017/12/8 + */ +public class SplashPresenter extends BaseMvpPresenter { + + +} diff --git a/app/src/main/java/com/chwl/app/other/view/ISplashView.java b/app/src/main/java/com/chwl/app/other/view/ISplashView.java new file mode 100644 index 0000000..3ec7512 --- /dev/null +++ b/app/src/main/java/com/chwl/app/other/view/ISplashView.java @@ -0,0 +1,18 @@ +package com.chwl.app.other.view; + +import com.chwl.core.home.bean.TabInfo; +import com.chwl.library.base.IMvpBaseView; + +import java.util.List; + +/** + *

+ * + * @author jiahui + * @date 2017/12/8 + */ +public interface ISplashView extends IMvpBaseView { + void resultHomeTabsSuccess(List tabInfoList); + + void resultHomeTabsFail(String error); +} diff --git a/app/src/main/java/com/chwl/app/pay/GiveGoldModel.kt b/app/src/main/java/com/chwl/app/pay/GiveGoldModel.kt new file mode 100644 index 0000000..b8ce641 --- /dev/null +++ b/app/src/main/java/com/chwl/app/pay/GiveGoldModel.kt @@ -0,0 +1,68 @@ +package com.chwl.app.pay + +import androidx.lifecycle.MutableLiveData +import com.chwl.app.base.BaseViewModel +import com.chwl.core.bean.response.ListResult +import com.chwl.core.home.model.HomeModel +import com.chwl.core.user.bean.DiamondGiveHistoryInfo +import com.chwl.core.user.bean.SearchUserInfo + +class GiveGoldModel : BaseViewModel() { + + private val _diamondGiveHistoryLiveData = MutableLiveData?>() + val diamondGiveHistoryLiveData: MutableLiveData?> = + _diamondGiveHistoryLiveData + + private val _searchUserLiveData = MutableLiveData() + val searchUserLiveData: MutableLiveData = _searchUserLiveData + + private val _giveGiftLiveData = MutableLiveData() + val giveGiftLiveData: MutableLiveData = _giveGiftLiveData + + private val _giveDetailLiveData = MutableLiveData?>() + val giveDetailLiveData: MutableLiveData?> = + _giveDetailLiveData + + fun getDiamondListInfo(pageNum: Int, pageSize: Int) { + safeLaunch( + onError = { + _diamondGiveHistoryLiveData.value = ListResult.failed(pageNum) + }, + block = { + val result = HomeModel.getDiamondGiveHistory(pageNum, pageSize) + _diamondGiveHistoryLiveData.value = ListResult.success(result, pageNum) + } + ) + } + + fun getSearchUserInfo(erbanNo: Long) { + safeLaunch( + false, + block = { + _searchUserLiveData.value = HomeModel.getSearchUser(erbanNo) + } + ) + } + + fun giveGift(toUid: Long, giftId: Int, giftNum: Int) { + safeLaunch( + true, + block = { + _giveGiftLiveData.value = HomeModel.giveGift(toUid, giftId, giftNum) + } + ) + } + + fun giveDetailInfo(uid: Long, type: Int, pageNum: Int, pageSize: Int) { + safeLaunch( + onError = { + _giveDetailLiveData.value = ListResult.failed(pageNum) + }, + block = { + val result = HomeModel.getGiveDetail(uid, type, pageNum, pageSize) + _giveDetailLiveData.value = ListResult.success(result, pageNum) + } + ) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/pay/activity/GiveGoldActivity.kt b/app/src/main/java/com/chwl/app/pay/activity/GiveGoldActivity.kt new file mode 100644 index 0000000..318a439 --- /dev/null +++ b/app/src/main/java/com/chwl/app/pay/activity/GiveGoldActivity.kt @@ -0,0 +1,251 @@ +package com.chwl.app.pay.activity + +import android.annotation.SuppressLint +import android.content.Context +import android.text.TextUtils +import android.view.KeyEvent +import android.view.inputmethod.EditorInfo +import android.widget.ImageView +import android.widget.TextView +import android.widget.TextView.OnEditorActionListener +import androidx.activity.viewModels +import androidx.recyclerview.widget.LinearLayoutManager +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.common.EmptyViewHelper +import com.chwl.app.common.dialog.DialogCommon +import com.chwl.app.databinding.ActivityGiveGoldBinding +import com.chwl.app.pay.GiveGoldModel +import com.chwl.app.pay.adapter.LatelyGiveAdapter +import com.chwl.app.ui.bean.RechargeUserInfo +import com.chwl.app.ui.utils.RVDelegate +import com.chwl.app.ui.utils.load +import com.chwl.app.ui.utils.loadAvatar +import com.chwl.app.ui.webview.CommonWebViewActivity +import com.chwl.core.UriProvider +import com.chwl.core.bean.response.ServiceResult +import com.chwl.core.gift.GiftModel +import com.chwl.core.user.UserModel +import com.chwl.core.user.bean.DiamondGiveHistoryInfo +import com.chwl.core.utils.net.RxHelper +import com.chwl.library.common.util.ClickUtils.click +import com.chwl.library.common.util.isVerify +import com.chwl.library.common.util.setViewWH +import com.chwl.library.common.util.setVis +import com.chwl.library.net.rxnet.RxNet +import com.chwl.library.utils.ResUtil +import com.example.lib_utils.ktx.dp +import com.example.lib_utils.ktx.getColor +import com.example.lib_utils.ktx.getString +import com.example.lib_utils.ktx.setPadding2 +import com.netease.nim.uikit.StatusBarUtil +import io.reactivex.Single +import retrofit2.http.GET + +/** + * 轉贈鉆石頁面 + */ +class GiveGoldActivity : BaseViewBindingActivity() { + + private var pageNum: Int = 1 + private val pageSize = 20 + private lateinit var mAdapter: LatelyGiveAdapter + private lateinit var rvDelegate: RVDelegate + + private val giveGoldModel: GiveGoldModel by viewModels() + + companion object { + fun start(context: Context) { +// val intent = Intent(context, GiveGoldActivity::class.java) +// context.startActivity(intent) + CommonWebViewActivity.start(context,UriProvider.getMyTransfer()) + } + } + + override fun init() { + initTitleBar(ResUtil.getString(R.string.me_donation)) + + binding.etSearch.setOnEditorActionListener(OnEditorActionListener { v, actionId, event -> //以下方法防止两次发送请求 + if (actionId == EditorInfo.IME_ACTION_SEARCH && event != null || event != null && event.keyCode == KeyEvent.KEYCODE_ENTER) { + if (event.action == KeyEvent.ACTION_UP) { //发送请求 + val newStr: String = binding.etSearch.text.toString().trim { it <= ' ' } + if (!TextUtils.isEmpty(newStr)) { + giveGoldModel.getSearchUserInfo(newStr.toLong()) + }else{ + toast(getString(R.string.password_input_user_id)) + } + return@OnEditorActionListener true //自己消费 + } + return@OnEditorActionListener true + } + false + }) + + mAdapter = LatelyGiveAdapter() + rvDelegate = RVDelegate.Builder() + .setAdapter(mAdapter) + .setLayoutManager(LinearLayoutManager(this)) + .setPageSize(20) + .setEmptyView( + EmptyViewHelper.createEmptyTextView( + this, + ResUtil.getString(R.string.me_give_gold_empty) + ) + ) + .setRefreshLayout(binding.refreshLayout) + .setRecyclerView(binding.recyclerView) + .build() + mAdapter.setOnItemClickListener { _, _, position -> + + } + + mAdapter.onItemChildClickListener = BaseQuickAdapter.OnItemChildClickListener { adapter, view, position -> + mAdapter.getItem(position)?.let { + if (view?.id == R.id.history) { + GiveGoldDetailActivity.start(this, it.targetUid) + }else if (view?.id == R.id.transfer) { + giveGoldModel.getSearchUserInfo(it.targetErbanNo) + } + } + } + + mAdapter.setOnLoadMoreListener({ + loadData(false) + }, binding.recyclerView) + binding.refreshLayout.setOnRefreshListener { + loadData(true) + } + giveGoldModel.diamondGiveHistoryLiveData.observe(this) { + rvDelegate.loadData(it) + } + giveGoldModel.searchUserLiveData.observe(this) { + it?.let { + GiveGoldToUserActivity.start(this, it) + } + } + giveGoldModel.loadingLiveData.observe(this) { + if (it) dialogManager.showProgressDialog(this) + else dialogManager.dismissDialog() + } + + + + binding.more.click { + + val dialog2 = DialogCommon() + + val text = TextView(context) + text.setTextColor(R.color.color_313131.getColor()) + text.textSize = 13f + text.setPadding2(start = 23.dp, end = 23.dp, bottom = 16.dp) + text.text = R.string.giveGoldTips.getString() + + dialog2.mContentLayout = text + dialog2.mTitle = R.string.layout_layout_single_room_pk_board_view_01.getString() + dialog2.show(context) + } + + + UserModel.get().cacheLoginUserInfo?.let { user-> + binding.enbanNo.text = R.string.text_user_id.getString(user.erbanNo) + binding.charmLevel.load(user.userLevelVo?.charmUrl?:"") + binding.charmLevel.setVis(user.userLevelVo?.charmUrl.isVerify()) + binding.userLevel.load(user.userLevelVo?.experUrl?:"") + binding.charmLevel.setVis(user.userLevelVo?.experUrl.isVerify()) + binding.nick.text = user.nick + binding.avatar.loadAvatar(user.avatar) + } + + + + binding.arDetail.click { + GiveGoldBiliActivity.start(context) + } + binding.enDetail.click { + GiveGoldBiliActivity.start(context) + } + binding.agent.click { + GiveGoldAgentsActivity.start(context) + } + + } + + override fun onResume() { + super.onResume() + loadData(true) + GiftModel.get().requestKnapGiftInfos().subscribe() + loadUserCardInfo() + } + + @SuppressLint("CheckResult") + fun loadData(isRefresh: Boolean) { + binding.refreshLayout.isRefreshing = isRefresh + pageNum = if (isRefresh) 1 else (pageNum + 1) + giveGoldModel.getDiamondListInfo(pageNum, pageSize) + + } + + private fun loadUserCardInfo() { + getRechargeUserInfo() + .compose(bindToLifecycle()) + .doOnSuccess { + binding.starLayout.removeAllViews() + if (it != null) { + if (it.starLevel == -1) { + binding.userInfo.setVis(false) + return@doOnSuccess + } + for (i in 0 until 5) { + val star = ImageView(context) + star.setViewWH(15, 15) + star.setImageResource( if (i < it.starLevel) R.drawable.icon_star_s else R.drawable.icon_star_n) + binding.starLayout.addView(star) + } + + if (UserModel.get().isArUser) { + binding.arView.setVis(true) + binding.enView.setVis(false) + } else { + binding.arView.setVis(false) + binding.enView.setVis(true) + } + + binding.arGoldUs.text = R.string._ver_23_US_s.getString(it.totalGiveGoldUsd) + binding.arGold.text = it.totalGiveGold.toString() + binding.enGold.text = it.totalGiveGold.toString() + + binding.agentNum.text = it.subNum.toString() + + binding.agentNum.setVis(it.subNum != 0) + binding.agent.setVis(it.subNum != 0) + + } + }.subscribe() + } + + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } + + override fun needSteepStateBar(): Boolean { + return true + } + + + private fun getRechargeUserInfo(): Single { + return api.getRechargeUserInfo() + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()) + } + + private val api: Api = RxNet.create(Api::class.java); + interface Api { + @GET("/recharge/user/info") + fun getRechargeUserInfo(): Single> + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/pay/activity/GiveGoldAgentsActivity.kt b/app/src/main/java/com/chwl/app/pay/activity/GiveGoldAgentsActivity.kt new file mode 100644 index 0000000..0961252 --- /dev/null +++ b/app/src/main/java/com/chwl/app/pay/activity/GiveGoldAgentsActivity.kt @@ -0,0 +1,103 @@ +package com.chwl.app.pay.activity + +import android.content.Context +import android.content.Intent +import android.widget.ImageView +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.bindadapter.BaseBindingAdapter +import com.chwl.app.common.EmptyViewHelper +import com.chwl.app.databinding.ActivityGiveGoldAgentsBinding +import com.chwl.app.databinding.ItemGiveGoldAgentBinding +import com.chwl.app.ui.bean.GiveGoldAgentBean +import com.chwl.app.ui.utils.loadAvatar +import com.chwl.core.bean.response.ServiceResult +import com.chwl.core.utils.extension.toast +import com.chwl.core.utils.net.RxHelper +import com.chwl.library.common.util.isVerify +import com.chwl.library.common.util.setViewWH +import com.chwl.library.net.rxnet.RxNet +import com.example.lib_utils.ktx.getString +import com.netease.nim.uikit.StatusBarUtil +import io.reactivex.Single +import retrofit2.http.GET + +class GiveGoldAgentsActivity : BaseViewBindingActivity() { + + companion object { + @JvmStatic + fun start(context: Context) { + val starter = Intent(context, GiveGoldAgentsActivity::class.java) + context.startActivity(starter) + } + } + + + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } + + override fun needSteepStateBar(): Boolean { + return true + } + + private lateinit var mAdapter : GiveGoldAgentsAdapter + + override fun init() { + + initWhiteTitleBar(R.string._ver_23_Sub_Recharge_Agent_List.getString()) + + mAdapter = GiveGoldAgentsAdapter() + mAdapter.emptyView = EmptyViewHelper.createEmptyTextView(context,R.string.empty_data.getString()) + binding.rvList.adapter = mAdapter + + getSubList().compose(bindToLifecycle()) + .doOnSuccess { + if (it.isVerify()) { + mAdapter.setNewData(it) + } + } + .doOnError { + it?.message?.toast() + } + .subscribe() + + } + + + private class GiveGoldAgentsAdapter : BaseBindingAdapter() { + + override fun onBindView(viewBinding: ItemGiveGoldAgentBinding, data: GiveGoldAgentBean, pos: Int) { + + viewBinding.avatar.loadAvatar(data.avatar?:"") + viewBinding.nick.text = data.nick?:"" + viewBinding.erBanNo.text = data.erbanNo.toString() + + viewBinding.starLayout.removeAllViews() + for (i in 0 until 5) { + val star = ImageView(viewBinding.starLayout.context) + star.setViewWH(15, 15) + star.setImageResource( if (i < data.starLevel) R.drawable.icon_star_s else R.drawable.icon_star_n) + viewBinding.starLayout.addView(star) + } + + viewBinding.coin.text = data.totalGiveGold.toString() + } + } + + + private fun getSubList(): Single> { + return api.getSubList() + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()) + } + + private val api: Api = RxNet.create(Api::class.java); + interface Api { + @GET("/recharge/user/subList") + fun getSubList(): Single>> + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/pay/activity/GiveGoldBiliActivity.kt b/app/src/main/java/com/chwl/app/pay/activity/GiveGoldBiliActivity.kt new file mode 100644 index 0000000..7827a0a --- /dev/null +++ b/app/src/main/java/com/chwl/app/pay/activity/GiveGoldBiliActivity.kt @@ -0,0 +1,432 @@ +package com.chwl.app.pay.activity + +import android.content.Context +import android.content.Intent +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.bindadapter.BaseBindingAdapter +import com.chwl.app.common.EmptyViewHelper +import com.chwl.app.databinding.ActivityGiveGoldBiliBinding +import com.chwl.app.databinding.ItemGiveGoldBiliBinding +import com.chwl.app.ui.bean.GiveGoldBiliBean +import com.chwl.app.ui.bean.GiveGoldBiliEntity +import com.chwl.app.ui.utils.loadAvatar +import com.chwl.core.bean.response.ServiceResult +import com.chwl.core.user.UserModel +import com.chwl.core.utils.myutil.MyTimeUtils +import com.chwl.core.utils.net.RxHelper +import com.chwl.library.common.util.ClickUtils.click +import com.chwl.library.common.util.doToast +import com.chwl.library.common.util.isVerify +import com.chwl.library.common.util.setVis +import com.chwl.library.net.rxnet.RxNet +import com.example.lib_utils.ktx.getColor +import com.example.lib_utils.ktx.getDrawable +import com.example.lib_utils.ktx.getString +import com.example.lib_utils.spannable.SpannableTextBuilder +import com.netease.nim.uikit.StatusBarUtil +import com.scwang.smart.refresh.layout.api.RefreshLayout +import com.scwang.smart.refresh.layout.listener.OnRefreshLoadMoreListener + + +import io.reactivex.Single +import retrofit2.http.GET +import retrofit2.http.Query + +class GiveGoldBiliActivity : BaseViewBindingActivity() { + + companion object { + @JvmStatic + fun start(context: Context) { + val starter = Intent(context, GiveGoldBiliActivity::class.java) + context.startActivity(starter) + } + } + + lateinit var mAdapter: GiveGoldBiliAdapter + private var mCycle = -1; + private var mTabType = -1; + + private var mDataThisCycleGold = mutableListOf() + private var mDataThisCycleGoldUs = mutableListOf() + + private var mDataLastCycleGold = mutableListOf() + private var mDataLastCycleGoldUs = mutableListOf() + + private var mPageNumThisCycleGold = 1 + private var mPageNumThisCycleGoldUs = 1 + + private var mPageNumLastCycleGold = 1 + private var mPageNumLastCycleGoldUs = 1 + + private var thisCycleTimeStr = "" + private var thisCycleGoldStr = "" + private var thisCycleGoldUsStr = "" + + private var lastCycleTimeStr = "" + private var lastCycleGoldStr = "" + private var lastCycleGoldUsStr = "" + + override fun init() { + + initWhiteTitleBar(R.string._ver_23_Transfer_History.getString()) + + binding.thisCycle.click { + switchCycle(GiveGoldBiliEntity.Cycle.thisCycle) + } + binding.lastCycle.click { + switchCycle(GiveGoldBiliEntity.Cycle.lastCycle) + } + binding.btnGoldUs.click { + switchTab(GiveGoldBiliEntity.TabType.goldUs) + } + binding.btnGold.click { + switchTab(GiveGoldBiliEntity.TabType.gold) + } + + binding.srlLayout.setOnRefreshLoadMoreListener(object : OnRefreshLoadMoreListener { + override fun onRefresh(p0: RefreshLayout) { + + } + + override fun onLoadMore(p0: RefreshLayout) { + loadData(false) + } + }) + mAdapter = GiveGoldBiliAdapter() + binding.rvList.layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false) + binding.rvList.adapter = mAdapter + mAdapter.emptyView = + EmptyViewHelper.createEmptyTextView(context, R.string.empty_data.getString()) + + + binding.tabLayout.setVis(UserModel.get().isArUser) + + + + + binding.thisCycle.performClick() + if (UserModel.get().isArUser) { + binding.btnGoldUs.performClick() + } else { + binding.btnGold.performClick() + } + + + } + + override fun onResume() { + super.onResume() +// if (mCycle != -1 && mTabType != -1) { +// getData(null,true) +// getPageNum(true) +// loadData() +// } + } + + + private fun switchCycle(type: Int) { + if (mCycle == type) return + binding.thisCycle.setDrawableEmpty( + null, + null, + null, + if (type == GiveGoldBiliEntity.Cycle.thisCycle) R.drawable.e29030_fcc974_draw.getDrawable() else R.drawable.transparent_draw.getDrawable() + ) + binding.lastCycle.setDrawableEmpty( + null, + null, + null, + if (type == GiveGoldBiliEntity.Cycle.lastCycle) R.drawable.e29030_fcc974_draw.getDrawable() else R.drawable.transparent_draw.getDrawable() + ) + + binding.thisCycle.setTextColor(if (type == GiveGoldBiliEntity.Cycle.thisCycle) R.color.color_313131.getColor() else R.color.color_AFB1B3.getColor()) + binding.lastCycle.setTextColor(if (type == GiveGoldBiliEntity.Cycle.lastCycle) R.color.color_313131.getColor() else R.color.color_AFB1B3.getColor()) + + mCycle = type + mAdapter.mCycle = type + loadData() + } + + private fun switchTab(type: Int) { + if (mTabType == type) return + binding.btnGoldUs.changeSoildColor(if (type == GiveGoldBiliEntity.TabType.goldUs) R.color.color_ff8c03.getColor() else R.color.transparent.getColor()) + binding.btnGold.changeSoildColor(if (type == GiveGoldBiliEntity.TabType.gold) R.color.color_ff8c03.getColor() else R.color.transparent.getColor()) + + binding.btnGoldUs.setTextColor(if (type == GiveGoldBiliEntity.TabType.goldUs) R.color.white.getColor() else R.color.color_AFB1B3.getColor()) + binding.btnGold.setTextColor(if (type == GiveGoldBiliEntity.TabType.gold) R.color.white.getColor() else R.color.color_AFB1B3.getColor()) + + + binding.totalTitle.text = if (type == GiveGoldBiliEntity.TabType.goldUs) R.string._ver_23_Total_Amount_of_Transfer_Us.getString() else R.string._ver_23_Total_Amount_of_Transfer_Coins.getString() + + mTabType = type + mAdapter.mTabType = type + loadData() + } + + + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } + + override fun needSteepStateBar(): Boolean { + return true + } + + private fun loadData(isSwitch:Boolean = true) { + if (mCycle == -1 || mTabType == -1) return + val data = getData(null) + if (isSwitch && data.isVerify()) { + setText() + mAdapter.setNewData(data) + binding.srlLayout.setEnableLoadMore(data.size % 20 == 0) + } else { + getHistory(getPageNum(), 20, mCycle, mTabType) + .compose(bindToLifecycle()) + .doOnSuccess { + + if (mCycle == GiveGoldBiliEntity.Cycle.thisCycle) { + thisCycleTimeStr = it.cycleDateStr ?: "" + if (mTabType == GiveGoldBiliEntity.TabType.gold) { + thisCycleGoldStr = it.totalGiveGold.toString() + } else { + thisCycleGoldUsStr = it.totalGiveGoldUsd.toString() + } + } else { + lastCycleTimeStr = it.cycleDateStr ?: "" + if (mTabType == GiveGoldBiliEntity.TabType.gold) { + lastCycleGoldStr = it.totalGiveGold.toString() + } else { + lastCycleGoldUsStr = it.totalGiveGoldUsd.toString() + } + } + + setText() + + if (it.diamondGiveHistoryVoList.isVerify()){ + if (getPageNum() == 1) { + mAdapter.setNewData(getData(it.diamondGiveHistoryVoList)) + } else { + val tranData = tranData(it.diamondGiveHistoryVoList) + tranData.isVerify(0) { first -> + if (mAdapter.data.isVerify()) { + val last = mAdapter.data.last() + if (last.timeStr == first.timeStr) { + first.isHead = false + } + } + } + mAdapter.addData(tranData) + } + + if (it.diamondGiveHistoryVoList.size == 20) { + if (mCycle == GiveGoldBiliEntity.Cycle.thisCycle) { + if (mTabType == GiveGoldBiliEntity.TabType.gold) { + mPageNumThisCycleGold++ + } else { + mPageNumThisCycleGoldUs++ + } + } else { + if (mTabType == GiveGoldBiliEntity.TabType.gold) { + mPageNumLastCycleGold++ + } else { + mPageNumLastCycleGoldUs++ + } + } + } + } + + binding.srlLayout.setEnableLoadMore(it.diamondGiveHistoryVoList.size == 20) + binding.srlLayout.finishLoadMore() + } + .doOnError { + it?.message?.doToast() + binding.srlLayout.finishLoadMore() + }.subscribe() + } + } + + private fun setText() { + if (mCycle == GiveGoldBiliEntity.Cycle.thisCycle) { + binding.totalCoin.text = if (mTabType == GiveGoldBiliEntity.TabType.gold) thisCycleGoldStr else R.string._ver_23_US_s.getString(thisCycleGoldUsStr) + } else { + binding.totalCoin.text = if (mTabType == GiveGoldBiliEntity.TabType.gold) lastCycleGoldStr else R.string._ver_23_US_s.getString(lastCycleGoldUsStr) + } + val icon = if (mTabType == GiveGoldBiliEntity.TabType.gold) R.drawable.ic_coin_84 else R.drawable.transparent_draw + binding.totalCoin.setDrawableEmpty(null,null,icon.getDrawable(),null) + binding.time.text = if (mCycle == GiveGoldBiliEntity.Cycle.thisCycle) thisCycleTimeStr else lastCycleTimeStr + } + + private fun getData(list: List?,isRefresh:Boolean = false): List { + val data = tranData(list) + if (mCycle == GiveGoldBiliEntity.Cycle.thisCycle) { + if (mTabType == GiveGoldBiliEntity.TabType.gold) { + if (isRefresh) { + mDataThisCycleGold.clear() + }else{ + if (data.isVerify()) { + if (mDataThisCycleGold.isVerify()) { + mDataThisCycleGold.addAll(data) + } else { + mDataThisCycleGold = data.toMutableList() + } + } + } + return mDataThisCycleGold + } else { + if (isRefresh){ + mDataThisCycleGoldUs.clear() + }else{ + if (data.isVerify()) { + if (mDataThisCycleGoldUs.isVerify()) { + mDataThisCycleGoldUs.addAll(data) + } else { + mDataThisCycleGoldUs = data.toMutableList() + } + } + } + return mDataThisCycleGoldUs + } + } else { + if (mTabType == GiveGoldBiliEntity.TabType.gold) { + if (isRefresh){ + mDataLastCycleGold.clear() + }else{ + if (data.isVerify()) { + if (mDataLastCycleGold.isVerify()) { + mDataLastCycleGold.addAll(data) + } else { + mDataLastCycleGold = data.toMutableList() + } + } + } + return mDataLastCycleGold + } else { + + if (isRefresh){ + mDataLastCycleGoldUs.clear() + }else{ + if (data.isVerify()) { + if (mDataLastCycleGoldUs.isVerify()) { + mDataLastCycleGoldUs.addAll(data) + } else { + mDataLastCycleGoldUs = data.toMutableList() + } + } + } + return mDataLastCycleGoldUs + } + } + } + + + private fun getPageNum(isRefresh: Boolean = false): Int { + if (mCycle == GiveGoldBiliEntity.Cycle.thisCycle) { + if (mTabType == GiveGoldBiliEntity.TabType.gold) { + if (isRefresh) mPageNumThisCycleGold = 1 + return mPageNumThisCycleGold + } else { + if (isRefresh) mPageNumThisCycleGoldUs = 1 + return mPageNumThisCycleGoldUs + } + } else { + if (mTabType == GiveGoldBiliEntity.TabType.gold) { + if (isRefresh) mPageNumLastCycleGold = 1 + return mPageNumLastCycleGold + } else { + if (isRefresh) mPageNumLastCycleGoldUs = 1 + return mPageNumLastCycleGoldUs + } + } + } + + private fun tranData(list: List?): MutableList { + val data = mutableListOf() + if (list.isVerify()) { + val group = list?.groupBy { it.timeStr } + + group?.forEach { (t, u) -> + u.filterIndexed { index, bean -> + if (index == 0) { + bean.isHead = true + } + data.add(bean) + } + } + } + return data + } + + + public class GiveGoldBiliAdapter : + BaseBindingAdapter() { + + var mCycle = -1; + var mTabType = -1; + + + override fun onBindView( + viewBinding: ItemGiveGoldBiliBinding, + data: GiveGoldBiliBean, + pos: Int + ) { + viewBinding.day.setVis(data.isHead) + viewBinding.day.text = MyTimeUtils.millis2String(data.createTime, "yyyy-MM-dd") + viewBinding.avatar.loadAvatar(data.targetAvatar) + viewBinding.nick.text = data.targetNick ?: "" + viewBinding.erBanNo.text = R.string.text_user_id.getString(data.targetErbanNo) + viewBinding.time.text = MyTimeUtils.millis2String(data.createTime) + + viewBinding.gold.text = data.diamondNum.toString() + viewBinding.gold.setVis(mTabType == GiveGoldBiliEntity.TabType.gold) + + val goldUsStr = "${R.string._ver_23_Settlement_s.getString(data.guildUsdNum)} ${data.diamondNum}" + SpannableTextBuilder(viewBinding.goldUs).appendText(goldUsStr) + .addTextStyleList(arrayListOf( + SpannableTextBuilder.TextStyleBean().apply { + text = R.string._ver_23_Settlement_s.getString(data.guildUsdNum) + textColor = R.color.color_313131.getColor() + }, + SpannableTextBuilder.TextStyleBean().apply { + text = data.diamondNum.toString() + textColor = R.color.color_AFB1B3.getColor() + textSize = 12 + } + )) + .apply() + viewBinding.goldUs.setVis(mTabType == GiveGoldBiliEntity.TabType.goldUs) + + } + } + + private fun getHistory( + pageNo: Int, + pageSize: Int, + periodType: Int, // 1-这周期 2-上周期 + type: Int // 1-金币转赠历史 2-代发薪资历史 + ): Single { + return api.getHistory(pageNo, pageSize, periodType, type) + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()) + } + + private val api: Api = RxNet.create(Api::class.java); + + interface Api { + + @GET("/user/diamond/history") + fun getHistory( + @Query("pageNo") pageNo: Int, + @Query("pageSize") pageSize: Int, + @Query("periodType") periodType: Int, + @Query("type") type: Int + ): Single> + + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/pay/activity/GiveGoldDetailActivity.kt b/app/src/main/java/com/chwl/app/pay/activity/GiveGoldDetailActivity.kt new file mode 100644 index 0000000..2542894 --- /dev/null +++ b/app/src/main/java/com/chwl/app/pay/activity/GiveGoldDetailActivity.kt @@ -0,0 +1,115 @@ +package com.chwl.app.pay.activity + +import android.content.Context +import android.content.Intent +import android.view.View +import android.widget.LinearLayout +import android.widget.TextView +import androidx.fragment.app.Fragment +import androidx.viewpager2.widget.ViewPager2 +import com.netease.nim.uikit.StatusBarUtil +import com.chwl.app.R +import com.chwl.app.avroom.adapter.CommonVPAdapter +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.databinding.ActivityGiveGoldDetailBinding +import com.chwl.app.pay.fragment.GiveDiamondFragment +import com.chwl.app.pay.fragment.GiveGiftFragment +import com.chwl.app.ui.user.adapter.CommonWrapIndicatorAdapter +import com.chwl.app.ui.widget.magicindicator.MagicIndicator +import com.chwl.app.ui.widget.magicindicator.ViewPagerHelper +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.CommonNavigator +import com.chwl.core.initial.InitialModel +import com.chwl.core.user.UserModel +import com.chwl.library.utils.ResUtil + +/** + * 轉贈鉆石頁面 + */ +class GiveGoldDetailActivity : BaseViewBindingActivity() { + + companion object { + fun start(context: Context, uid: Long) { + val intent = Intent(context, GiveGoldDetailActivity::class.java) + intent.putExtra("uid", uid) + context.startActivity(intent) + } + } + + override fun init() { + initTitleBar(ResUtil.getString(R.string.me_donation_detail)) + initDetail() + } + + /** + * 轉贈詳情 + */ + private fun initDetail() { + val uid = intent.extras?.getLong("uid", 0L) ?: 0L + + val initInfo = InitialModel.get().cacheInitInfo + val userInfo = UserModel.get().cacheLoginUserInfo + val diamondList = initInfo?.giveDiamondErbanNoList + val giftList = initInfo?.giveGiftErbanNoList + val levelSep = userInfo?.userLevelVo?.experLevelSeq ?: 0 + + val viewPager: ViewPager2 = binding.viewPagerDetail + val magicIndicator: MagicIndicator = binding.magicIndicator + val fragmentList: MutableList = ArrayList() + val pagerAdapter = CommonVPAdapter(supportFragmentManager, lifecycle, fragmentList) + val tagList: MutableList = ArrayList() + if (diamondList?.contains(userInfo?.erbanNo) == true || levelSep >= (initInfo?.giveDiamondExperLevel + ?: 0) + ) { + tagList.add(getString(R.string.diamond)) + fragmentList.add(GiveDiamondFragment.newInstance(uid)) + } + if (giftList?.contains(userInfo?.erbanNo) == true || levelSep >= (initInfo?.giveGiftExperLevel + ?: 0) + ) { + tagList.add(getString(R.string.gift_action)) + fragmentList.add(GiveGiftFragment.newInstance(uid)) + } + if (tagList.size == 0) { + return + }else if(tagList.size == 1){ + binding.magicIndicator.visibility = View.GONE + } + val commonNavigator = CommonNavigator(context) + commonNavigator.isAdjustMode = true//自我调节位置,实现自我平分 + val magicIndicatorAdapter = CommonWrapIndicatorAdapter(context, tagList) + magicIndicatorAdapter.setOnItemSelectListener { position: Int, view: TextView? -> + viewPager.currentItem = position + } + commonNavigator.adapter = magicIndicatorAdapter + magicIndicator.navigator = commonNavigator + commonNavigator.titleContainer.showDividers = LinearLayout.SHOW_DIVIDER_MIDDLE + viewPager.adapter = pagerAdapter + ViewPagerHelper.bind(magicIndicator, viewPager) + viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { + override fun onPageScrolled( + position: Int, + positionOffset: Float, + positionOffsetPixels: Int + ) { + } + + override fun onPageSelected(position: Int) { + viewPager.requestLayout() + } + + override fun onPageScrollStateChanged(state: Int) {} + }) + + } + + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } + + override fun needSteepStateBar(): Boolean { + return true + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/pay/activity/GiveGoldSearchActivity.kt b/app/src/main/java/com/chwl/app/pay/activity/GiveGoldSearchActivity.kt new file mode 100644 index 0000000..e7ef483 --- /dev/null +++ b/app/src/main/java/com/chwl/app/pay/activity/GiveGoldSearchActivity.kt @@ -0,0 +1,84 @@ +package com.chwl.app.pay.activity + + +import android.annotation.SuppressLint +import android.app.Activity +import android.content.Intent +import android.os.Bundle +import android.os.Parcelable +import android.text.Editable +import android.text.TextWatcher +import android.widget.EditText +import android.widget.TextView +import androidx.recyclerview.widget.LinearLayoutManager +import com.chwl.app.R +import com.chwl.app.base.BaseActivity +import com.chwl.app.common.EmptyViewHelper +import com.chwl.app.pay.adapter.GiveSearchAdapter +import com.chwl.app.ui.utils.RVDelegate +import com.chwl.core.room.bean.SearchRoomInfo +import com.chwl.core.room.model.AvRoomModel +import com.chwl.core.utils.net.RxHelper +import com.chwl.library.utils.ResUtil + +class GiveGoldSearchActivity : BaseActivity(), TextWatcher { + + companion object { + const val REQUEST_CODE = 0xff12 + + @JvmStatic + fun start(context: Activity) { + val intent = Intent(context, GiveGoldSearchActivity::class.java) + context.startActivityForResult(intent, REQUEST_CODE) + } + } + + private lateinit var rvDelegate: RVDelegate + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_give_gold_search) + val adapter = GiveSearchAdapter() + rvDelegate = RVDelegate.Builder() + .setPageSize(Int.MAX_VALUE) + .setEmptyView(EmptyViewHelper.createEmptyTextView(this, ResUtil.getString(R.string.pay_activity_givegoldsearchactivity_01))) + .setLayoutManager(LinearLayoutManager(this)) + .setRecyclerView(findViewById(R.id.recyclerView)) + .setAdapter(adapter) + .build() + adapter.setOnItemClickListener { _, _, position -> + setResult(Activity.RESULT_OK, Intent().apply { + adapter.getItem(position)?.let { + putExtra("searchRoomInfo", it as Parcelable) + } + }) + finish() + } + findViewById(R.id.editSearch).addTextChangedListener(this) + findViewById(R.id.tvCancel).setOnClickListener { finish() } + } + + override fun afterTextChanged(s: Editable?) { + + } + + override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { + } + + @SuppressLint("CheckResult") + override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { + if (s.isNullOrEmpty()) { + rvDelegate.setNewData(null) + } else { + AvRoomModel.get() + .roomSearch(s.toString()) + .compose(RxHelper.handleBeanData()) + .doOnError { rvDelegate.loadErr(true) } + .compose(bindToLifecycle()) + .subscribe { rooms -> + rvDelegate.setNewData(rooms) + } + } + + } +} diff --git a/app/src/main/java/com/chwl/app/pay/activity/GiveGoldToUserActivity.kt b/app/src/main/java/com/chwl/app/pay/activity/GiveGoldToUserActivity.kt new file mode 100644 index 0000000..04196f9 --- /dev/null +++ b/app/src/main/java/com/chwl/app/pay/activity/GiveGoldToUserActivity.kt @@ -0,0 +1,420 @@ +package com.chwl.app.pay.activity + +import android.annotation.SuppressLint +import android.content.Context +import android.content.Intent +import android.text.Editable +import android.text.InputFilter +import android.text.InputFilter.LengthFilter +import android.text.TextWatcher +import android.util.SparseArray +import android.view.View +import android.view.ViewGroup +import android.widget.EditText +import androidx.activity.viewModels +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView +import androidx.viewpager.widget.PagerAdapter +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.databinding.ActivityGiveGoldToUserBinding +import com.chwl.app.pay.GiveGoldModel +import com.chwl.app.pay.adapter.GiveGiftAdapter +import com.chwl.app.pay.password.GiveGoldPassWordFragment +import com.chwl.app.pay.widget.GridPasswordNoFocusView +import com.chwl.app.ui.setting.ModifyPwdActivity +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.app.ui.widget.OnPageSelectedListener +import com.chwl.app.ui.widget.dialog.CommonTipDialog +import com.chwl.app.ui.widget.dialog.GiveDiamondTipDialog +import com.chwl.app.utils.DoubleClickCheckListener +import com.chwl.core.DemoCache +import com.chwl.core.gift.GiftModel +import com.chwl.core.gift.bean.GiftInfo +import com.chwl.core.initial.InitialModel +import com.chwl.core.pay.PayModel +import com.chwl.core.user.UserModel +import com.chwl.core.user.bean.SearchUserInfo +import com.chwl.library.common.util.isVerify +import com.chwl.library.utils.ResUtil +import com.chwl.library.widget.text.DrawableTextView +import com.example.lib_utils.ktx.getDrawable +import com.netease.nim.uikit.StatusBarUtil + +class GiveGoldToUserActivity : BaseViewBindingActivity(), + GridPasswordNoFocusView.OnPasswordChangedListener, + TextWatcher { + + private val giveGoldModel: GiveGoldModel by viewModels() + + companion object { + @JvmStatic + fun start(context: Context, searchUser: SearchUserInfo) { + val intent = Intent(context, GiveGoldToUserActivity::class.java) + intent.putExtra("searchUser", searchUser) + context.startActivity(intent) + } + } + + private var searchUserInfo: SearchUserInfo? = null + private var passWordFragment: GiveGoldPassWordFragment? = null + private var selectGiftPos = -1 + private var giftAllCount = -1 + private var giftId = -1 + + private var centerIndex = 0 + + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } + + override fun needSteepStateBar(): Boolean { + return true + } + + override fun init() { + initTitleBar(ResUtil.getString(R.string.donation_to)) + searchUserInfo = intent.getSerializableExtra("searchUser") as SearchUserInfo? + searchUserInfo?.apply { + binding.tvId.text = "ID:${erbanNo}" + binding.tvNickname.text = nick + ImageLoadUtils.loadAvatar(context, avatar, binding.ivAvatar) + } + val initInfo = InitialModel.get().cacheInitInfo + val userInfo = UserModel.get().cacheLoginUserInfo + + + val diamondList = initInfo?.giveDiamondErbanNoList //金币 + val giftList = initInfo?.giveGiftErbanNoList // ,礼物 + val levelSep = userInfo?.userLevelVo?.experLevelSeq ?: 0 + + if (userInfo?.isRechargeUser == true) { + binding.tvDiamondTab.visibility = View.VISIBLE + binding.groupDiamond.visibility = View.VISIBLE + } else { + if (diamondList?.contains(userInfo?.erbanNo) == true || levelSep >= (initInfo?.giveDiamondExperLevel ?: 0)) { + binding.tvDiamondTab.visibility = View.VISIBLE + binding.groupDiamond.visibility = View.VISIBLE + } else { + binding.tvDiamondTab.visibility = View.GONE + binding.groupDiamond.visibility = View.GONE + } + } + + if (giftList?.contains(userInfo?.erbanNo) == true || levelSep >= (initInfo?.giveGiftExperLevel ?: 0)) { + binding.tvGiftTab.visibility = View.VISIBLE + binding.groupGift.visibility = View.VISIBLE + } else { + binding.tvGiftTab.visibility = View.GONE + binding.groupGift.visibility = View.GONE + } + + binding.viewPagerEntrance.addOnPageChangeListener(object : OnPageSelectedListener() { + override fun onPageSelected(position: Int) { + centerIndex = position + binding.magicIndicatorEntrance.setSelectedPage(position) + } + }) + initDiamond() + initGift() + initListener() + giveGoldModel.loadingLiveData.observe(this) { + if (it) dialogManager.showProgressDialog(this) + else dialogManager.dismissDialog() + } + giveGoldModel.giveGiftLiveData.observe(this) { + toast(getString(R.string.gift_give_success)) + finish() + } + + + } + + private fun initListener() { + binding.tvSure.setOnClickListener { + val initInfo = DemoCache.readInitInfo() + if (binding.groupDiamond.visibility == View.VISIBLE) { + searchUserInfo?.apply { + val goldStr = binding.mEditGold.text.toString() + if (!goldStr.isVerify()) return@apply + val gold = goldStr.toInt() + if (gold <= 0) { + toast(ResUtil.getString(R.string.pay_activity_givegoldtouseractivity_06)) + return@setOnClickListener + } + UserModel.get().cacheLoginUserInfo?.let { + if (!it.isBindPaymentPwd) { + val tipDialog = CommonTipDialog(this@GiveGoldToUserActivity) + tipDialog.setTipMsg(ResUtil.getString(R.string.setting_pay_pwd_first)) + tipDialog.setOkText(getString(R.string.to_setting)) + tipDialog.setOnActionListener( + object : CommonTipDialog.OnActionListener { + override fun onOk() { + ModifyPwdActivity.start( + this@GiveGoldToUserActivity, + ModifyPwdActivity.PAY_PWD + ) + } + } + ) + tipDialog.show() + } else { + val rateGold = initInfo.giveDiamondRate * 100 + val tipDialog = GiveDiamondTipDialog(this@GiveGoldToUserActivity) + tipDialog.setTvDiamond(gold.toString()) + tipDialog.setTipMsg(getString(R.string.give_gold_to_user, nick)) + if (rateGold == 0.0) { + tipDialog.setTipMessageGone(true) + } else { + tipDialog.setTvSeCharge("${rateGold.toInt()}%") + val goldNew = gold + (gold * initInfo.giveDiamondRate) + tipDialog.setTvConsumeDiamond( + getString( + R.string.invite_gift_price_text, + goldNew.toString() + ) + ) + } + tipDialog.setOnActionListener( + object : GiveDiamondTipDialog.OnActionListener { + override fun onOk() { + GiveGoldPassWordFragment.newInstance( + supportFragmentManager, + gold.toString(), + nick, + "" + ) + .apply { + passWordFragment = this + setListener(this@GiveGoldToUserActivity) + } + } + } + ) + tipDialog.show() + } + } ?: run { + toast(ResUtil.getString(R.string.ui_setting_settingactivity_06)) + return@setOnClickListener + } + } + } else {//赠送礼物 + searchUserInfo?.apply { + val giftNumStr = binding.editGift.text.toString() + if (!giftNumStr.isVerify()) return@apply + val giftNum =giftNumStr.toInt() + if (selectGiftPos < 0) { + toast(ResUtil.getString(R.string.please_select_gift)) + return@setOnClickListener + } else if (giftNum == 0) { + toast(ResUtil.getString(R.string.please_enter_gift_num)) + return@setOnClickListener + } else if (giftNum > giftAllCount) { + toast(ResUtil.getString(R.string.gift_num_fail)) + return@setOnClickListener + } + giveGoldModel.giveGift(uid, giftId, giftNum) + } + } + } + } + + private fun initDiamond() { + if (binding.tvDiamondTab.visibility == View.GONE) { + return + } else if (binding.tvGiftTab.visibility == View.VISIBLE) { + btnSelect(binding.tvGiftTab,false) + binding.groupGift.visibility = View.GONE + } + val initInfo = DemoCache.readInitInfo() + val length = initInfo?.giveDiamondOnceLimitNum?.toInt()?.toString()?.length ?: 0 + binding.mEditGold.text.filters = arrayOf(LengthFilter(length)) + binding.mTvDiamond.text = getString( + R.string.my_diamond, + PayModel.get().currentWalletInfo?.diamondNum?.toString() ?: "0" + ) + binding.mEditGold.addTextChangedListener(this) + btnSelect(binding.tvDiamondTab,true) + binding.tvDiamondTab.setOnClickListener { + if (binding.tvGiftTab.visibility == View.VISIBLE) { + btnSelect(binding.tvGiftTab,false) + binding.groupGift.visibility = View.GONE + btnSelect(binding.tvDiamondTab,true) + binding.groupDiamond.visibility = View.VISIBLE + } + } + } + + @SuppressLint("CheckResult") + private fun initGift() { + if (binding.tvGiftTab.visibility == View.GONE) { + return + } + val giftList = GiftModel.get().knapList + if (binding.tvDiamondTab.visibility == View.GONE) { + btnSelect(binding.tvGiftTab,true) + binding.tvSure.isEnabled = true + } + binding.tvGiftTab.setOnClickListener { + if (binding.tvDiamondTab.visibility == View.VISIBLE) { + btnSelect(binding.tvDiamondTab,false) + binding.groupDiamond.visibility = View.GONE + btnSelect(binding.tvGiftTab,true) + binding.groupGift.visibility = View.VISIBLE + binding.tvSure.isEnabled = true + } + } + if (giftList.size == 0) { + binding.tvEmptyTip.visibility = View.VISIBLE + return + } else { + binding.tvEmptyTip.visibility = View.GONE + } + val list = transformList(giftList, 8) + binding.magicIndicatorEntrance.initIndicator(list.size) + binding.magicIndicatorEntrance.setSelectedPage(centerIndex) + binding.magicIndicatorEntrance.visibility = + if (list.size > 1) View.VISIBLE else View.INVISIBLE + binding.viewPagerEntrance.adapter = object : PagerAdapter() { + var cacheItemView = SparseArray() + override fun getCount(): Int { + return list.size + } + + override fun isViewFromObject(view: View, `object`: Any): Boolean { + return view == `object` + } + + override fun instantiateItem(container: ViewGroup, position: Int): Any { + val recyclerView: RecyclerView + val giveGiftAdapter: GiveGiftAdapter + if (cacheItemView[position] == null) { + recyclerView = RecyclerView(context) + var lp = recyclerView.layoutParams + if (lp == null) { + lp = ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ) + } + recyclerView.layoutParams = lp + recyclerView.layoutManager = GridLayoutManager(context, 4) +// recyclerView.addItemDecoration( +// GridSpacingItemNewDecoration( +// UIUtil.dip2px( +// context, +// 18.0 +// ), UIUtil.dip2px(context, 10.0), true +// ) +// ) + giveGiftAdapter = GiveGiftAdapter() + giveGiftAdapter.onItemClickListener = object : DoubleClickCheckListener() { + override fun onItemClickSingle( + adapter: BaseQuickAdapter<*, *>?, + view: View, + position: Int + ) { + val oldBean = giveGiftAdapter.getItem(selectGiftPos) + oldBean?.isSelected = false + giveGiftAdapter.notifyItemChanged(selectGiftPos) + val bean = giveGiftAdapter.getItem(position) + bean?.isSelected = true + giveGiftAdapter.notifyItemChanged(position) + selectGiftPos = position + giftAllCount = giveGiftAdapter.getItem(position)?.count ?: -1 + giftId = giveGiftAdapter.getItem(position)?.giftId ?: -1 + } + } + recyclerView.adapter = giveGiftAdapter + } else { + recyclerView = cacheItemView[position] + giveGiftAdapter = recyclerView.adapter as GiveGiftAdapter + } + giveGiftAdapter.setNewData(list[position]) + container.addView(recyclerView) + return recyclerView + } + + override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) { + val recyclerView = cacheItemView[position] + container.removeView(recyclerView) + } + } + binding.viewPagerEntrance.setCurrentItem(centerIndex, false) + binding.editGift.addTextChangedListener(this) + binding.tvAll.setOnClickListener { + if (giftAllCount != -1) + binding.editGift.setText(giftAllCount.toString()) + } + } + + private fun transformList( + data: List, + pageSize: Int + ): List> { + val result: MutableList> = ArrayList() + if (data.isEmpty()) { + return result + } + for (i in data.toTypedArray().indices) { + var page: MutableList? = null + if (i % pageSize == 0) { + page = ArrayList() + result.add(page) + } else { + if (result.size > 0) { + page = result[result.size - 1] + } + } + page?.add(data[i]) + } + return result + } + + @SuppressLint("CheckResult") + override fun onInputFinish(psw: String) { + } + + @SuppressLint("CheckResult") + override fun onTextChanged(psw: String) { + val password = passWordFragment?.password?.password ?: "" + if (password.length == 6) { + searchUserInfo?.apply { + dialogManager.showProgressDialog(context) + PayModel.get().giveGold(uid, findViewById(R.id.mEditGold).text.toString(), DESAndBase64(password)) + .compose(bindToLifecycle()) + .doOnError { + toast(it.message) + passWordFragment?.password?.clearPassword() + dialogManager.dismissDialog() + } + .subscribe { _ -> + passWordFragment?.dismissAllowingStateLoss() + dialogManager.dismissDialog() + toast(getString(R.string.layout_activity_give_gold_success_01)) + finish() + } + } + } + } + + override fun afterTextChanged(s: Editable?) { + } + + override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { + } + + override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { + binding.tvSure.isEnabled = !s.isNullOrBlank() + } + + private fun btnSelect(view: DrawableTextView,select: Boolean) { + view.isSelected = select + val draw = if (select) R.drawable.icon_give_gold.getDrawable() else R.drawable.transparent_draw.getDrawable() + view.setDrawableEmpty(null,null,null,draw) + } + +} diff --git a/app/src/main/java/com/chwl/app/pay/adapter/GiveDiamondDetailAdapter.kt b/app/src/main/java/com/chwl/app/pay/adapter/GiveDiamondDetailAdapter.kt new file mode 100644 index 0000000..d69a2ca --- /dev/null +++ b/app/src/main/java/com/chwl/app/pay/adapter/GiveDiamondDetailAdapter.kt @@ -0,0 +1,29 @@ +package com.chwl.app.pay.adapter + +import android.annotation.SuppressLint +import android.widget.ImageView +import android.widget.TextView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.ui.utils.loadAvatar +import com.chwl.core.user.bean.DiamondGiveHistoryInfo +import com.chwl.library.utils.TimeUtils +import com.example.lib_utils.ktx.getString + + +class GiveDiamondDetailAdapter : + BaseQuickAdapter(R.layout.item_give_diamond_detail) { + + @SuppressLint("SetTextI18n") + override fun convert(helper: BaseViewHolder, item: DiamondGiveHistoryInfo) { + helper.getView(R.id.tv_number).text = item.targetNick.toString() + + helper.getView(R.id.tv_pay_diamond).text = item.realDiamondNum.toString() + helper.setText(R.id.tv_date, TimeUtils.getDateTimeString(item.createTime,"yyyy-MM-dd HH:mm:ss")) + helper.setText(R.id.erBanNo, R.string.text_user_id.getString(item.targetErbanNo)) + + helper.getView(R.id.iv_avatar).loadAvatar(item.targetAvatar) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/pay/adapter/GiveGiftAdapter.java b/app/src/main/java/com/chwl/app/pay/adapter/GiveGiftAdapter.java new file mode 100644 index 0000000..4fb065d --- /dev/null +++ b/app/src/main/java/com/chwl/app/pay/adapter/GiveGiftAdapter.java @@ -0,0 +1,34 @@ +package com.chwl.app.pay.adapter; + + +import android.widget.ImageView; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.gift.bean.GiftInfo; + +/** + * 赠送礼物 + */ +public class GiveGiftAdapter extends BaseQuickAdapter { + + + public GiveGiftAdapter() { + super(R.layout.item_give_gift); + } + + @Override + protected void convert(BaseViewHolder helper, GiftInfo item) { + if (item == null) { + return; + } + helper.setText(R.id.tvName, item.getGiftName()) + .setText(R.id.tvNum, "x" + item.getCount()); + ImageView giftPic = helper.itemView.findViewById(R.id.ivGift); + ImageLoadUtils.loadImage(mContext, item.getGiftUrl(), giftPic); + helper.getView(R.id.viewBg).setSelected(item.isSelected); + } + +} diff --git a/app/src/main/java/com/chwl/app/pay/adapter/GiveGiftDetailAdapter.kt b/app/src/main/java/com/chwl/app/pay/adapter/GiveGiftDetailAdapter.kt new file mode 100644 index 0000000..64fd001 --- /dev/null +++ b/app/src/main/java/com/chwl/app/pay/adapter/GiveGiftDetailAdapter.kt @@ -0,0 +1,24 @@ +package com.chwl.app.pay.adapter + +import android.annotation.SuppressLint +import android.widget.TextView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.app.utils.TimeUiUtils +import com.chwl.core.user.bean.DiamondGiveHistoryInfo +import com.chwl.library.utils.TimeUtils + + +class GiveGiftDetailAdapter : + BaseQuickAdapter(R.layout.item_give_gift_detail) { + + @SuppressLint("SetTextI18n") + override fun convert(helper: BaseViewHolder, item: DiamondGiveHistoryInfo) { + helper.getView(R.id.tv_gift_name).text = "${item.giftName}x${item.giftNum}" + ImageLoadUtils.loadAvatar(mContext, item.giftUrl, helper.getView(R.id.iv_avatar)) + helper.setText(R.id.tv_date, TimeUtils.getDateTimeString(item.createTime,"yyyy-MM-dd HH:mm:ss")) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/pay/adapter/GiveSearchAdapter.kt b/app/src/main/java/com/chwl/app/pay/adapter/GiveSearchAdapter.kt new file mode 100644 index 0000000..f203ed5 --- /dev/null +++ b/app/src/main/java/com/chwl/app/pay/adapter/GiveSearchAdapter.kt @@ -0,0 +1,22 @@ +package com.chwl.app.pay.adapter + +import android.annotation.SuppressLint +import android.widget.TextView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.core.room.bean.SearchRoomInfo + + +class GiveSearchAdapter : + BaseQuickAdapter(R.layout.item_lately_give) { + + @SuppressLint("SetTextI18n") + override fun convert(helper: BaseViewHolder, item: SearchRoomInfo) { + helper.getView(R.id.tv_id).text = "ID:${item.erbanNo}" + helper.getView(R.id.tv_nickname).text = item.nick + ImageLoadUtils.loadAvatar(mContext, item.avatar, helper.getView(R.id.iv_avatar)) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/pay/adapter/LatelyGiveAdapter.kt b/app/src/main/java/com/chwl/app/pay/adapter/LatelyGiveAdapter.kt new file mode 100644 index 0000000..3f99fd0 --- /dev/null +++ b/app/src/main/java/com/chwl/app/pay/adapter/LatelyGiveAdapter.kt @@ -0,0 +1,25 @@ +package com.chwl.app.pay.adapter + +import android.annotation.SuppressLint +import android.widget.TextView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.core.user.bean.DiamondGiveHistoryInfo + + +class LatelyGiveAdapter : + BaseQuickAdapter(R.layout.item_lately_give) { + + @SuppressLint("SetTextI18n") + override fun convert(helper: BaseViewHolder, item: DiamondGiveHistoryInfo) { + helper.getView(R.id.tv_id).text = "ID:${item.targetErbanNo}" + helper.getView(R.id.tv_nickname).text = item.targetNick + ImageLoadUtils.loadAvatar(mContext, item.targetAvatar, helper.getView(R.id.iv_avatar)) + + helper.addOnClickListener(R.id.transfer) + helper.addOnClickListener(R.id.history) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/pay/fragment/GiveDiamondFragment.kt b/app/src/main/java/com/chwl/app/pay/fragment/GiveDiamondFragment.kt new file mode 100644 index 0000000..e00a39a --- /dev/null +++ b/app/src/main/java/com/chwl/app/pay/fragment/GiveDiamondFragment.kt @@ -0,0 +1,73 @@ +package com.chwl.app.pay.fragment + +import android.annotation.SuppressLint +import android.os.Bundle +import androidx.fragment.app.viewModels +import androidx.recyclerview.widget.LinearLayoutManager +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingFragment +import com.chwl.app.common.EmptyViewHelper +import com.chwl.app.databinding.FragmentGiveDiamondBinding +import com.chwl.app.pay.GiveGoldModel +import com.chwl.app.pay.adapter.GiveDiamondDetailAdapter +import com.chwl.app.ui.utils.RVDelegate +import com.chwl.core.user.bean.DiamondGiveHistoryInfo +import com.chwl.library.utils.ResUtil + +class GiveDiamondFragment : BaseViewBindingFragment() { + + private var pageNum: Int = 1 + private val pageSize = 20 + private lateinit var mAdapter: GiveDiamondDetailAdapter + private lateinit var rvDelegate: RVDelegate + + private val giveGoldModel: GiveGoldModel by viewModels() + + private var uid: Long = 0L + + companion object { + fun newInstance(uid: Long): GiveDiamondFragment { + val args = Bundle() + args.putLong("uid", uid) + val fragment = GiveDiamondFragment() + fragment.arguments = args + return fragment + } + } + + override fun init() { + uid = arguments?.getLong("uid") ?: 0L + mAdapter = GiveDiamondDetailAdapter() + rvDelegate = RVDelegate.Builder() + .setAdapter(mAdapter) + .setLayoutManager(LinearLayoutManager(context)) + .setPageSize(20) + .setEmptyView( + EmptyViewHelper.createEmptyTextView( + context, + ResUtil.getString(R.string.me_give_gold_empty) + ) + ) + .setRefreshLayout(binding.refreshLayout) + .setRecyclerView(binding.recyclerView) + .build() + mAdapter.setOnLoadMoreListener({ + loadData(false) + }, binding.recyclerView) + binding.refreshLayout.setOnRefreshListener { + loadData(true) + } + giveGoldModel.giveDetailLiveData.observe(this) { + rvDelegate.loadData(it) + } + loadData(true) + } + + @SuppressLint("CheckResult") + fun loadData(isRefresh: Boolean) { + binding.refreshLayout.isRefreshing = isRefresh + pageNum = if (isRefresh) 1 else (pageNum + 1) + giveGoldModel.giveDetailInfo(uid, 0, pageNum, pageSize) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/pay/fragment/GiveGiftFragment.kt b/app/src/main/java/com/chwl/app/pay/fragment/GiveGiftFragment.kt new file mode 100644 index 0000000..603a9a3 --- /dev/null +++ b/app/src/main/java/com/chwl/app/pay/fragment/GiveGiftFragment.kt @@ -0,0 +1,73 @@ +package com.chwl.app.pay.fragment + +import android.annotation.SuppressLint +import android.os.Bundle +import androidx.fragment.app.viewModels +import androidx.recyclerview.widget.LinearLayoutManager +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingFragment +import com.chwl.app.common.EmptyViewHelper +import com.chwl.app.databinding.FragmentGiveGiftBinding +import com.chwl.app.pay.GiveGoldModel +import com.chwl.app.pay.adapter.GiveGiftDetailAdapter +import com.chwl.app.ui.utils.RVDelegate +import com.chwl.core.user.bean.DiamondGiveHistoryInfo +import com.chwl.library.utils.ResUtil + +class GiveGiftFragment : BaseViewBindingFragment() { + + private var pageNum: Int = 1 + private val pageSize = 20 + private lateinit var mAdapter: GiveGiftDetailAdapter + private lateinit var rvDelegate: RVDelegate + + private val giveGoldModel: GiveGoldModel by viewModels() + + private var uid: Long = 0L + + companion object { + fun newInstance(uid: Long): GiveGiftFragment { + val args = Bundle() + args.putLong("uid", uid) + val fragment = GiveGiftFragment() + fragment.arguments = args + return fragment + } + } + + override fun init() { + uid = arguments?.getLong("uid") ?: 0L + mAdapter = GiveGiftDetailAdapter() + rvDelegate = RVDelegate.Builder() + .setAdapter(mAdapter) + .setLayoutManager(LinearLayoutManager(context)) + .setPageSize(20) + .setEmptyView( + EmptyViewHelper.createEmptyTextView( + context, + ResUtil.getString(R.string.me_give_gold_empty) + ) + ) + .setRefreshLayout(binding.refreshLayout) + .setRecyclerView(binding.recyclerView) + .build() + mAdapter.setOnLoadMoreListener({ + loadData(false) + }, binding.recyclerView) + binding.refreshLayout.setOnRefreshListener { + loadData(true) + } + giveGoldModel.giveDetailLiveData.observe(this) { + rvDelegate.loadData(it) + } + loadData(true) + } + + @SuppressLint("CheckResult") + fun loadData(isRefresh: Boolean) { + binding.refreshLayout.isRefreshing = isRefresh + pageNum = if (isRefresh) 1 else (pageNum + 1) + giveGoldModel.giveDetailInfo(uid, 1, pageNum, pageSize) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/pay/interfaces/PasswordView.java b/app/src/main/java/com/chwl/app/pay/interfaces/PasswordView.java new file mode 100644 index 0000000..3643c53 --- /dev/null +++ b/app/src/main/java/com/chwl/app/pay/interfaces/PasswordView.java @@ -0,0 +1,23 @@ +package com.chwl.app.pay.interfaces; + +import com.jungly.gridpasswordview.PasswordType; +import com.chwl.app.pay.widget.GridPasswordNoFocusView; + +public interface PasswordView { + + //void setError(String error); + + String getPassWord(); + + void clearPassword(); + + void setPassword(String password); + + void setPasswordVisibility(boolean visible); + + void togglePasswordVisibility(); + + void setOnPasswordChangedListener(GridPasswordNoFocusView.OnPasswordChangedListener listener); + + void setPasswordType(PasswordType passwordType); +} diff --git a/app/src/main/java/com/chwl/app/pay/password/GiveGoldPassWordFragment.java b/app/src/main/java/com/chwl/app/pay/password/GiveGoldPassWordFragment.java new file mode 100644 index 0000000..56d9d1d --- /dev/null +++ b/app/src/main/java/com/chwl/app/pay/password/GiveGoldPassWordFragment.java @@ -0,0 +1,132 @@ +package com.chwl.app.pay.password; + +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.text.TextUtils; +import android.util.DisplayMetrics; +import android.view.Display; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; + +import androidx.annotation.Nullable; +import androidx.fragment.app.DialogFragment; +import androidx.fragment.app.FragmentManager; + +import com.chwl.app.R; +import com.chwl.app.pay.widget.GridPasswordNoFocusView; +import com.chwl.app.ui.setting.ModifyPwdActivity; +import com.chwl.library.utils.ResUtil; + + +//也可继承design中的BottomSheetDialogFragment +public class GiveGoldPassWordFragment extends DialogFragment { + + private GiveGoldPasswordView mPassword; + + private GridPasswordNoFocusView.OnPasswordChangedListener listener; + + private static GiveGoldPassWordFragment passWordFragment; + + private static final String EXTRA_GOLD = "gold"; + private static final String EXTRA_NICKNAME = "nickname"; + private static final String EXTRA_GOLD_RATE = "rate"; + + public static GiveGoldPassWordFragment newInstance(FragmentManager fragmentManager, String gold) { + if (passWordFragment == null) { + passWordFragment = new GiveGoldPassWordFragment(); + Bundle bundle = new Bundle(); + bundle.putString(EXTRA_GOLD, gold); + passWordFragment.setArguments(bundle); + passWordFragment.show(fragmentManager, "GiveGoldPassWordFragment"); + } + return passWordFragment; + } + + /** + * @param gold 金额 + * @param nickname 转账对象昵称 + * @param rate 手续费 + * @return + */ + public static GiveGoldPassWordFragment newInstance(FragmentManager fragmentManager, String gold, String nickname, String rate) { + if (passWordFragment == null) { + passWordFragment = new GiveGoldPassWordFragment(); + Bundle bundle = new Bundle(); + bundle.putString(EXTRA_GOLD, gold); + bundle.putString(EXTRA_NICKNAME, nickname); + bundle.putString(EXTRA_GOLD_RATE, rate); + passWordFragment.setArguments(bundle); + passWordFragment.show(fragmentManager, "GiveGoldPassWordFragment"); + } + return passWordFragment; + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + //继承BottomSheetDialogFragment时onStart()可注释掉 + @Override + public void onStart() { + super.onStart(); + Window window = getDialog().getWindow(); + if (window != null) { + window.setBackgroundDrawable(new ColorDrawable(getResources().getColor(R.color.transparent))); + WindowManager.LayoutParams layoutParams = window.getAttributes(); + DisplayMetrics dm = new DisplayMetrics(); + Display d = window.getWindowManager().getDefaultDisplay(); + d.getRealMetrics(dm); + window.getWindowManager().getDefaultDisplay().getMetrics(dm); + layoutParams.width = dm.widthPixels; + layoutParams.height = WindowManager.LayoutParams.MATCH_PARENT; + window.setAttributes(layoutParams); + } + + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.dialog_give_gold_password, container); + init(view); + return view; + } + + private void init(View view) { + mPassword = view.findViewById(R.id.give_gold_password_view); + mPassword.getCloseImageView().setOnClickListener(view12 -> dismiss()); + mPassword.getForgetTextView().setOnClickListener(view1 -> ModifyPwdActivity.start(getContext(), ModifyPwdActivity.PAY_PWD)); + mPassword.getPswView().setOnPasswordChangedListener(listener); + if (getArguments() != null) { + if (!TextUtils.isEmpty(getArguments().getString(EXTRA_NICKNAME))) { + mPassword.getTvNickname().setText(ResUtil.getString(R.string.pay_password_givegoldpasswordfragment_01) + getArguments().getString(EXTRA_NICKNAME)); + } else { + mPassword.getTvNickname().setVisibility(View.GONE); + } + if (!TextUtils.isEmpty(getArguments().getString(EXTRA_GOLD_RATE))) { + mPassword.getTvRate().setText(getArguments().getString(EXTRA_GOLD_RATE)); + } else { + mPassword.getTvRate().setVisibility(View.GONE); + } + mPassword.getTvGold().setText(getArguments().getString(EXTRA_GOLD)); + } + } + + public void setListener(GridPasswordNoFocusView.OnPasswordChangedListener listener) { + this.listener = listener; + } + + public GiveGoldPasswordView getPassword() { + return mPassword; + } + + @Override + public void onDestroy() { + super.onDestroy(); + passWordFragment = null; + } +} diff --git a/app/src/main/java/com/chwl/app/pay/password/GiveGoldPasswordView.java b/app/src/main/java/com/chwl/app/pay/password/GiveGoldPasswordView.java new file mode 100644 index 0000000..02219d1 --- /dev/null +++ b/app/src/main/java/com/chwl/app/pay/password/GiveGoldPasswordView.java @@ -0,0 +1,135 @@ +package com.chwl.app.pay.password; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.chwl.app.R; +import com.chwl.app.pay.widget.GridPasswordNoFocusView; +import com.chwl.app.ui.widget.password.PasswordKeyboardView; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by lcw on 2016/11/28. + */ + +public class GiveGoldPasswordView extends RelativeLayout { + + private ImageView mClose; + private TextView mTitle; + private TextView mForgetPwd; + private GridPasswordNoFocusView mPassword; + private TextView tvNickname; + private TextView tvRate; + private TextView tvGold; + private PasswordKeyboardView mKeyboard; + private List passwordList;//记录键盘输入的值 + private StringBuilder mValue;//最后保存的密码 + + public GiveGoldPasswordView(Context context) { + this(context, null); + } + + public GiveGoldPasswordView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public GiveGoldPasswordView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + View.inflate(context, R.layout.view_give_gold_password, this); + initView(); + initEvent(); + } + + private void initView() { + mPassword = findViewById(R.id.view_password); + mClose = findViewById(R.id.img_close); + mTitle = findViewById(R.id.tv_title); + mForgetPwd = findViewById(R.id.tv_forgetPwd); + mKeyboard = findViewById(R.id.view_keyboard); + tvGold = findViewById(R.id.tv_gold); + tvNickname = findViewById(R.id.tv_nickname); + tvRate = findViewById(R.id.tv_rate); + //打乱数字的位置 + //mKeyboard.shuffleKeyboard(); + } + + private void initEvent() { + mValue = new StringBuilder(); + passwordList = new ArrayList<>(); + mKeyboard.setIOnKeyboardListener(new PasswordKeyboardView.IOnKeyboardListener() { + + @Override + public void onInsertKeyEvent(String text) { + mValue.setLength(0); + passwordList.add(text); + for (int i = 0; i < passwordList.size(); i++) { + mValue.append(passwordList.get(i)); + } + mPassword.setPassword(mValue.toString()); + } + + @Override + public void onDeleteKeyEvent() { + mValue.setLength(0); + if (passwordList.size() != 0) { + passwordList.remove(passwordList.size() - 1); + for (int i = 0; i < passwordList.size(); i++) { + mValue.append(passwordList.get(i)); + } + mPassword.setPassword(mValue.toString()); + } + } + }); + } + + //获取输入的密码 + public String getPassword() { + return mValue.toString(); + } + + //取消 + public ImageView getCloseImageView() { + return mClose; + } + + //标题 + public TextView getTitleTextView() { + return mTitle; + } + + //忘记密码 + public TextView getForgetTextView() { + return mForgetPwd; + } + + + public TextView getTvNickname() { + return tvNickname; + } + + public TextView getTvRate() { + return tvRate; + } + + public TextView getTvGold() { + return tvGold; + } + + //输入密码控件 + public GridPasswordNoFocusView getPswView() { + return mPassword; + } + + public void clearPassword(){ + mValue.setLength(0); + mPassword.clearPassword(); + passwordList.clear(); + } + +} diff --git a/app/src/main/java/com/chwl/app/pay/presenter/ChargePresenter.java b/app/src/main/java/com/chwl/app/pay/presenter/ChargePresenter.java new file mode 100644 index 0000000..76df0cf --- /dev/null +++ b/app/src/main/java/com/chwl/app/pay/presenter/ChargePresenter.java @@ -0,0 +1,37 @@ +package com.chwl.app.pay.presenter; + + +import com.chwl.app.pay.view.IChargeView; +import com.chwl.core.pay.PayModel; + +/** + * Created by MadisonRong on 05/01/2018. + */ +public class ChargePresenter extends PayPresenter { + + private static final String TAG = "ChargePresenter"; + + public ChargePresenter() { + this.payModel = PayModel.get(); + } + + /** + * 加载用户信息(显示用户账号和钱包余额) + */ + public void loadUserInfo() { + refreshWalletInfo(false); + } + +// @SuppressLint("CheckResult") +// public void loadBanner() { +// payModel.loadChargeBanner() +// .compose(bindUntilEvent(PresenterEvent.DESTROY)) +// .subscribe(list -> { +// if (ListUtils.isListEmpty(list)) { +// return; +// } +// getMvpView().onLoadedBanners(list); +// }, +// error -> ToastUtils.show(error.getMessage())); +// } +} diff --git a/app/src/main/java/com/chwl/app/pay/presenter/PayPresenter.java b/app/src/main/java/com/chwl/app/pay/presenter/PayPresenter.java new file mode 100644 index 0000000..fd0996e --- /dev/null +++ b/app/src/main/java/com/chwl/app/pay/presenter/PayPresenter.java @@ -0,0 +1,49 @@ +package com.chwl.app.pay.presenter; + +import android.annotation.SuppressLint; + +import com.chwl.app.R; +import com.chwl.app.pay.view.IPayView; +import com.chwl.core.pay.PayModel; +import com.chwl.core.pay.bean.WalletInfo; +import com.chwl.library.base.factory.AbstractMvpPresenter; +import com.chwl.library.utils.ResUtil; + +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; + +/** + * Created by MadisonRong on 08/01/2018. + */ + +public class PayPresenter extends AbstractMvpPresenter { + + protected PayModel payModel; + protected WalletInfo walletInfo; + + public PayPresenter() { + this.payModel = PayModel.get(); + } + + /** + * 刷新钱包信息 + */ + @SuppressLint("CheckResult") + public void refreshWalletInfo(boolean force) { + payModel.getWalletInfo() + .compose(bindToLifecycle()) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(walletInfo -> { + if (walletInfo != null) { + // cache walletInfo for calling in the future + this.walletInfo = walletInfo; + PayModel.get().setCurrentWalletInfo(walletInfo); + getMvpView().setupUserWalletBalance(walletInfo); + } else { + getMvpView().getUserWalletInfoFail(ResUtil.getString(R.string.pay_presenter_paypresenter_01)); + } + }); + + } +} diff --git a/app/src/main/java/com/chwl/app/pay/view/IChargeView.java b/app/src/main/java/com/chwl/app/pay/view/IChargeView.java new file mode 100644 index 0000000..8f07f1e --- /dev/null +++ b/app/src/main/java/com/chwl/app/pay/view/IChargeView.java @@ -0,0 +1,13 @@ +package com.chwl.app.pay.view; + + + +/** + * Created by MadisonRong on 05/01/2018. + */ + +public interface IChargeView extends IPayView { + +// void onLoadedBanners(List banners); + +} diff --git a/app/src/main/java/com/chwl/app/pay/view/IPayView.java b/app/src/main/java/com/chwl/app/pay/view/IPayView.java new file mode 100644 index 0000000..6d2ae53 --- /dev/null +++ b/app/src/main/java/com/chwl/app/pay/view/IPayView.java @@ -0,0 +1,16 @@ +package com.chwl.app.pay.view; + + +import com.chwl.core.pay.bean.WalletInfo; +import com.chwl.library.base.IMvpBaseView; + +/** + * Created by MadisonRong on 08/01/2018. + */ + +public interface IPayView extends IMvpBaseView { + + public void setupUserWalletBalance(WalletInfo walletInfo); + + public void getUserWalletInfoFail(String error); +} diff --git a/app/src/main/java/com/chwl/app/pay/widget/GridPasswordNoFocusView.java b/app/src/main/java/com/chwl/app/pay/widget/GridPasswordNoFocusView.java new file mode 100644 index 0000000..96cb426 --- /dev/null +++ b/app/src/main/java/com/chwl/app/pay/widget/GridPasswordNoFocusView.java @@ -0,0 +1,436 @@ +package com.chwl.app.pay.widget; + +import android.content.Context; +import android.content.res.ColorStateList; +import android.content.res.TypedArray; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; +import android.os.Bundle; +import android.os.Parcelable; +import android.text.Editable; +import android.text.InputType; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.text.method.PasswordTransformationMethod; +import android.util.AttributeSet; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.jungly.gridpasswordview.CustomPasswordTransformationMethod; +import com.jungly.gridpasswordview.PasswordType; +import com.jungly.gridpasswordview.Util; +import com.jungly.gridpasswordview.imebugfixer.ImeDelBugFixedEditText; +import com.chwl.app.R; +import com.chwl.app.pay.interfaces.PasswordView; + +public class GridPasswordNoFocusView extends LinearLayout implements PasswordView { + private static final int DEFAULT_PASSWORDLENGTH = 6; + private static final int DEFAULT_TEXTSIZE = 16; + private static final String DEFAULT_TRANSFORMATION = "●"; + private static final int DEFAULT_LINECOLOR = 0xaa888888; + private static final int DEFAULT_GRIDCOLOR = 0xffffffff; + + private ColorStateList mTextColor; + private int mTextSize = DEFAULT_TEXTSIZE; + private int mLineWidth; + private int mLineColor; + private int mGridColor; + private Drawable mLineDrawable; + private Drawable mOuterLineDrawable; + private int mPasswordLength; + private String mPasswordTransformation; + private int mPasswordType; + + private String[] mPasswordArr; + private TextView[] mViewArr; + + private ImeDelBugFixedEditText mInputView; + private OnPasswordChangedListener mListener; + private PasswordTransformationMethod mTransformationMethod; + + public GridPasswordNoFocusView(Context context) { + super(context); + initViews(context); + init(context, null, 0); + } + + public GridPasswordNoFocusView(Context context, AttributeSet attrs) { + super(context, attrs); + init(context, attrs, 0); + } + + public GridPasswordNoFocusView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context, attrs, defStyleAttr); + } + + public GridPasswordNoFocusView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + init(context, attrs, defStyleAttr); + } + + private void init(Context context, AttributeSet attrs, int defStyleAttr) { + initAttrs(context, attrs, defStyleAttr); + initViews(context); + } + + private void initAttrs(Context context, AttributeSet attrs, int defStyleAttr) { + TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.gridPasswordView, defStyleAttr, 0); + + mTextColor = ta.getColorStateList(R.styleable.gridPasswordView_gpvTextColor); + if (mTextColor == null) + mTextColor = ColorStateList.valueOf(getResources().getColor(android.R.color.primary_text_light)); + int textSize = ta.getDimensionPixelSize(R.styleable.gridPasswordView_gpvTextSize, -1); + if (textSize != -1) { + this.mTextSize = Util.px2sp(context, textSize); + } + + mLineWidth = (int) ta.getDimension(R.styleable.gridPasswordView_gpvLineWidth, Util.dp2px(getContext(), 1)); + mLineColor = ta.getColor(R.styleable.gridPasswordView_gpvLineColor, DEFAULT_LINECOLOR); + mGridColor = ta.getColor(R.styleable.gridPasswordView_gpvGridColor, DEFAULT_GRIDCOLOR); + mLineDrawable = ta.getDrawable(R.styleable.gridPasswordView_gpvLineColor); + if (mLineDrawable == null) + mLineDrawable = new ColorDrawable(mLineColor); + mOuterLineDrawable = generateBackgroundDrawable(); + + mPasswordLength = ta.getInt(R.styleable.gridPasswordView_gpvPasswordLength, DEFAULT_PASSWORDLENGTH); + mPasswordTransformation = ta.getString(R.styleable.gridPasswordView_gpvPasswordTransformation); + if (TextUtils.isEmpty(mPasswordTransformation)) + mPasswordTransformation = DEFAULT_TRANSFORMATION; + + + mPasswordType = ta.getInt(R.styleable.gridPasswordView_gpvPasswordType, 0); + + ta.recycle(); + + mPasswordArr = new String[mPasswordLength]; + mViewArr = new TextView[mPasswordLength]; + } + + private void initViews(Context context) { + super.setBackgroundDrawable(mOuterLineDrawable); + setShowDividers(SHOW_DIVIDER_NONE); + setOrientation(HORIZONTAL); + + mTransformationMethod = new CustomPasswordTransformationMethod(mPasswordTransformation); + inflaterViews(context); + } + + private void inflaterViews(Context context) { + LayoutInflater inflater = LayoutInflater.from(context); + inflater.inflate(R.layout.grid_password_view, this); + + mInputView = (ImeDelBugFixedEditText) findViewById(R.id.inputView); + mInputView.setMaxEms(mPasswordLength); + mInputView.addTextChangedListener(textWatcher); + mInputView.setDelKeyEventListener(onDelKeyEventListener); + setCustomAttr(mInputView); + + mViewArr[0] = mInputView; + + int index = 1; + while (index < mPasswordLength) { + View dividerView = inflater.inflate(R.layout.divider, null); + LinearLayout.LayoutParams dividerParams = new LinearLayout.LayoutParams(mLineWidth, LinearLayout.LayoutParams.MATCH_PARENT); + dividerView.setBackgroundDrawable(mLineDrawable); + addView(dividerView, dividerParams); + + TextView textView = (TextView) inflater.inflate(R.layout.textview, null); + setCustomAttr(textView); + LinearLayout.LayoutParams textViewParams = new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.MATCH_PARENT, 1f); + addView(textView, textViewParams); + + mViewArr[index] = textView; + index++; + } + + } + + private void setCustomAttr(TextView view) { + if (mTextColor != null) + view.setTextColor(mTextColor); + view.setTextSize(mTextSize); + + int inputType = InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD; + switch (mPasswordType) { + + case 1: + inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD; + break; + + case 2: + inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD; + break; + + case 3: + inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD; + break; + } + view.setInputType(inputType); + view.setTransformationMethod(mTransformationMethod); + } + + private GradientDrawable generateBackgroundDrawable() { + GradientDrawable drawable = new GradientDrawable(); + drawable.setColor(mGridColor); + drawable.setStroke(mLineWidth, mLineColor); + return drawable; + } + + private ImeDelBugFixedEditText.OnDelKeyEventListener onDelKeyEventListener = new ImeDelBugFixedEditText.OnDelKeyEventListener() { + + @Override + public void onDeleteClick() { + for (int i = mPasswordArr.length - 1; i >= 0; i--) { + if (mPasswordArr[i] != null) { + mPasswordArr[i] = null; + mViewArr[i].setText(null); + notifyTextChanged(); + break; + } else { + mViewArr[i].setText(null); + } + } + } + }; + + private TextWatcher textWatcher = new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + if (s == null) { + return; + } + + String newStr = s.toString(); + if (newStr.length() == 1) { + mPasswordArr[0] = newStr; + notifyTextChanged(); + } else if (newStr.length() == 2) { + String newNum = newStr.substring(1); + for (int i = 0; i < mPasswordArr.length; i++) { + if (mPasswordArr[i] == null) { + mPasswordArr[i] = newNum; + mViewArr[i].setText(newNum); + notifyTextChanged(); + break; + } + } + mInputView.removeTextChangedListener(this); + mInputView.setText(mPasswordArr[0]); + if (mInputView.getText().length() >= 1) { + mInputView.setSelection(1); + } + mInputView.addTextChangedListener(this); + } + } + + @Override + public void afterTextChanged(Editable s) { + + } + }; + + @Deprecated + private OnKeyListener onKeyListener = new OnKeyListener() { + @Override + public boolean onKey(View v, int keyCode, KeyEvent event) { + if (event.getAction() == KeyEvent.ACTION_DOWN && event.getKeyCode() == KeyEvent.KEYCODE_DEL) { + onDelKeyEventListener.onDeleteClick(); + return true; + } + return false; + } + }; + + private void notifyTextChanged() { + if (mListener == null) + return; + + String currentPsw = getPassWord(); + mListener.onTextChanged(currentPsw); + + if (currentPsw.length() == mPasswordLength) + mListener.onInputFinish(currentPsw); + } + + @Override + protected Parcelable onSaveInstanceState() { + Bundle bundle = new Bundle(); + bundle.putParcelable("instanceState", super.onSaveInstanceState()); + bundle.putStringArray("passwordArr", mPasswordArr); + return bundle; + } + + @Override + protected void onRestoreInstanceState(Parcelable state) { + if (state instanceof Bundle) { + Bundle bundle = (Bundle) state; + mPasswordArr = bundle.getStringArray("passwordArr"); + state = bundle.getParcelable("instanceState"); + mInputView.removeTextChangedListener(textWatcher); + setPassword(getPassWord()); + mInputView.addTextChangedListener(textWatcher); + } + super.onRestoreInstanceState(state); + } + + //TODO + //@Override + private void setError(String error) { + mInputView.setError(error); + } + + /** + * Return the text the PasswordView is displaying. + */ + @Override + public String getPassWord() { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < mPasswordArr.length; i++) { + if (mPasswordArr[i] != null) + sb.append(mPasswordArr[i]); + } + return sb.toString(); + } + + /** + * Clear the passwrod the PasswordView is displaying. + */ + @Override + public void clearPassword() { + for (int i = 0; i < mPasswordArr.length; i++) { + mPasswordArr[i] = null; + mViewArr[i].setText(null); + } + } + + /** + * Sets the string value of the PasswordView. + */ + @Override + public void setPassword(String password) { + clearPassword(); + + if (TextUtils.isEmpty(password)) + return; + + char[] pswArr = password.toCharArray(); + for (int i = 0; i < pswArr.length; i++) { + if (i < mPasswordArr.length) { + mPasswordArr[i] = pswArr[i] + ""; + mViewArr[i].setText(mPasswordArr[i]); + } + } + } + + /** + * Set the enabled state of this view. + */ + @Override + public void setPasswordVisibility(boolean visible) { + for (TextView textView : mViewArr) { + textView.setTransformationMethod(visible ? null : mTransformationMethod); + if (textView instanceof EditText) { + EditText et = (EditText) textView; + et.setSelection(et.getText().length()); + } + } + } + + /** + * Toggle the enabled state of this view. + */ + @Override + public void togglePasswordVisibility() { + boolean currentVisible = getPassWordVisibility(); + setPasswordVisibility(!currentVisible); + } + + /** + * Get the visibility of this view. + */ + private boolean getPassWordVisibility() { + return mViewArr[0].getTransformationMethod() == null; + } + + /** + * Register a callback to be invoked when password changed. + */ + @Override + public void setOnPasswordChangedListener(OnPasswordChangedListener listener) { + this.mListener = listener; + } + + @Override + public void setPasswordType(PasswordType passwordType) { + boolean visible = getPassWordVisibility(); + int inputType = InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD; + switch (passwordType) { + + case TEXT: + inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD; + break; + + case TEXTVISIBLE: + inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD; + break; + + case TEXTWEB: + inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD; + break; + } + + for (TextView textView : mViewArr) + textView.setInputType(inputType); + + setPasswordVisibility(visible); + } + + @Override + public void setBackground(Drawable background) { + } + + @Override + public void setBackgroundColor(int color) { + } + + @Override + public void setBackgroundResource(int resid) { + } + + @Override + public void setBackgroundDrawable(Drawable background) { + } + + + /** + * Interface definition for a callback to be invoked when the password changed or is at the maximum length. + */ + public interface OnPasswordChangedListener { + + /** + * Invoked when the password changed. + * + * @param psw new text + */ + void onTextChanged(String psw); + + /** + * Invoked when the password is at the maximum length. + * + * @param psw complete text + */ + void onInputFinish(String psw); + + } +} diff --git a/app/src/main/java/com/chwl/app/photo/BigPagerAdapter.java b/app/src/main/java/com/chwl/app/photo/BigPagerAdapter.java new file mode 100644 index 0000000..5cea5d0 --- /dev/null +++ b/app/src/main/java/com/chwl/app/photo/BigPagerAdapter.java @@ -0,0 +1,70 @@ +/* + * Copyright 2017 Zhihu Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.chwl.app.photo; + +import android.view.ViewGroup; + +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentStatePagerAdapter; + +import com.example.matisse.internal.entity.CustomItem; + +import java.util.ArrayList; +import java.util.List; + +public class BigPagerAdapter extends FragmentStatePagerAdapter { + + private ArrayList mItems = new ArrayList<>(); + + private PagerOption option; + + public BigPagerAdapter(FragmentManager manager, PagerOption option) { + super(manager); + this.option = option; + } + + @Override + public Fragment getItem(int position) { + return BigPhotoItemFragment.newInstance( + new PagerOption() + .setDelete(option.isDelete()) + .setSave(option.isSave()) + .setLayoutHeight(option.getLayoutHeight()) + .setPosition(position) + .setCustomItem(mItems.get(position)) + ); + } + + @Override + public int getCount() { + return mItems.size(); + } + + @Override + public void setPrimaryItem(ViewGroup container, int position, Object object) { + super.setPrimaryItem(container, position, object); + } + + public CustomItem getMediaItem(int position) { + return mItems.get(position); + } + + public void addAll(List items) { + mItems.addAll(items); + } + +} diff --git a/app/src/main/java/com/chwl/app/photo/BigPhotoActivity.java b/app/src/main/java/com/chwl/app/photo/BigPhotoActivity.java new file mode 100644 index 0000000..7a31f8a --- /dev/null +++ b/app/src/main/java/com/chwl/app/photo/BigPhotoActivity.java @@ -0,0 +1,208 @@ +package com.chwl.app.photo; + +import android.Manifest; +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Intent; +import android.view.View; + +import com.chwl.app.R; +import com.chwl.app.base.BaseViewBindingActivity; +import com.chwl.app.databinding.ActivityBigPhotoBinding; +import com.chwl.app.ui.widget.ButtonItem; +import com.chwl.app.ui.widget.OnPageSelectedListener; +import com.chwl.library.common.util.AlbumUtils; +import com.chwl.library.common.util.ExecutorCenter; +import com.chwl.library.utils.ResUtil; +import com.example.matisse.internal.entity.CustomItem; +import com.netease.nim.uikit.StatusBarUtil; +import com.netease.nim.uikit.common.util.log.LogUtil; + +import java.util.ArrayList; +import java.util.List; + +import kotlin.Unit; +import kotlin.jvm.functions.Function1; + +/** + * create by lvzebiao @2019/11/20 + */ +public class BigPhotoActivity extends BaseViewBindingActivity implements OnFragmentOptionListener { + + private ArrayList list; + + public final static int CODE_DELETE_PHOTO = 20; + + private final static String KEY_DATA = "key_data"; + + private final static String KEY_OPTION = "key_option"; + + private final static String KEY_POSITION = "key_position"; + + public final static String KEY_IMG_URL = "key_img_url"; + + private PagerOption option; + + private int mPreviousPos; + + private BigPagerAdapter adapter; + + public static void start(Activity activity, ArrayList list, + int position, PagerOption option, boolean forResult, int requestCode) { + Intent intent = new Intent(activity, BigPhotoActivity.class); + intent.putParcelableArrayListExtra(KEY_DATA, list); + intent.putExtra(KEY_POSITION, position); + intent.putExtra(KEY_OPTION, option); + if (forResult) { + activity.startActivityForResult(intent, requestCode); + } else { + activity.startActivity(intent); + } + } + + public static void start(Activity activity, ArrayList list, + int position, PagerOption option) { + start(activity, list, position, option, false, 0); + } + + public static void startCanDelete(Activity activity, ArrayList list, + int position, PagerOption option) { + start(activity, list, position, option, true, CODE_DELETE_PHOTO); + } + + @Override + public void init() { + if (getIntent() == null) { + return; + } + initTitleBar(""); + list = getIntent().getParcelableArrayListExtra(KEY_DATA); + option = (PagerOption) getIntent().getSerializableExtra(KEY_OPTION); + if (list == null) { + list = new ArrayList<>(); + } + binding.pager.post(() -> { + int pos = getIntent().getIntExtra(KEY_POSITION, 0); + initPager(pos); + }); + + binding.pager.addOnPageChangeListener(new OnPageSelectedListener() { + @Override + public void onPageSelected(int position) { + updateTitle(position); + if (mPreviousPos != -1 && mPreviousPos != position && adapter != null) { + ((BigPhotoItemFragment) adapter.instantiateItem(binding.pager, mPreviousPos)).resetView(); + } + mPreviousPos = position; + } + }); + + if (!option.isDelete()) { + binding.ivDelete.setVisibility(View.GONE); + } else { + binding.ivDelete.setVisibility(View.VISIBLE); + binding.ivDelete.setOnClickListener(v -> { + int currPos = binding.pager.getCurrentItem(); + onDelete(currPos); + }); + } + } + + private void updateTitle(int pos) { + if (mTitleBar != null) { + mTitleBar.setTitle((pos + 1) + "/" + list.size()); + } + } + + private void initPager(int position) { + adapter = new BigPagerAdapter(getSupportFragmentManager(), + option.setLayoutHeight(binding.pager.getHeight())); + + LogUtil.print(ResUtil.getString(R.string.community_photo_bigphotoactivity_01), list); + + adapter.addAll(list); + binding.pager.setAdapter(adapter); + updateTitle(0); + int count = adapter.getCount(); + if (position >= 0 && position < count) { + binding.pager.setCurrentItem(position, false); + } + } + + @Override + public void onClick(int position) { + finish(); + } + + @SuppressLint("CheckResult") + @Override + public void onLongClick(int position) { + if (!option.isSave()) { + return; + } + List listBtn = new ArrayList<>(); + listBtn.add(new ButtonItem(ResUtil.getString(R.string.community_photo_bigphotoactivity_02), () -> { + CustomItem item = list.get(position); + if (item == null) { + return; + } + checkPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) + .compose(bindToLifecycle()) + .subscribe(aBoolean -> { + if (aBoolean) { + ExecutorCenter.getInstance().post(() -> { + AlbumUtils.INSTANCE.addUrlToAlbum(context, item.getPath(), new Function1() { + @Override + public Unit invoke(Boolean aBoolean) { + if (aBoolean) { + toast(ResUtil.getString(R.string.community_photo_bigphotoactivity_05)); + } + return null; + } + }); + }); + } else { + toast(ResUtil.getString(R.string.give_application_storage_permission)); + } + }); + })); + getDialogManager().showCommonPopupDialog(listBtn, ResUtil.getString(R.string.community_photo_bigphotoactivity_07)); + + } + + private void onDelete(int position) { + getDialogManager().showOkCancelDialog(ResUtil.getString(R.string.community_photo_bigphotoactivity_08), () -> { + if (position >= 0 && position < list.size()) { + list.remove(position); + } + if (list.isEmpty()) { + finish(); + return; + } + mPreviousPos--; + initPager(position); + toast(ResUtil.getString(R.string.community_photo_bigphotoactivity_09)); + }); + } + + @Override + public void finish() { + Intent intent = new Intent(); + intent.putParcelableArrayListExtra(KEY_IMG_URL, list); + setResult(RESULT_OK, intent); + super.finish(); + } + + @Override + protected boolean needSteepStateBar() { + return true; + } + + @Override + protected void setStatusBar() { + super.setStatusBar(); + StatusBarUtil.transparencyBar(this); + StatusBarUtil.StatusBarLightMode(this); + } + +} diff --git a/app/src/main/java/com/chwl/app/photo/BigPhotoItemFragment.java b/app/src/main/java/com/chwl/app/photo/BigPhotoItemFragment.java new file mode 100644 index 0000000..e254fea --- /dev/null +++ b/app/src/main/java/com/chwl/app/photo/BigPhotoItemFragment.java @@ -0,0 +1,157 @@ +/* + * Copyright 2017 Zhihu Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.chwl.app.photo; + +import android.app.Activity; +import android.content.Context; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; + +import com.bumptech.glide.request.RequestOptions; +import com.chwl.app.R; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.app.ui.utils.ImageLoadUtilsV2; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.library.utils.LogUtil; +import com.chwl.library.utils.ResUtil; +import com.example.matisse.internal.entity.CustomItem; +import com.netease.nim.uikit.support.glide.GlideApp; + +import it.sephiroth.android.library.imagezoom.ImageViewTouch; +import it.sephiroth.android.library.imagezoom.ImageViewTouchBase; + +public class BigPhotoItemFragment extends Fragment { + + + private static final String ARGS_OPTION = "args_option"; + + private OnFragmentOptionListener mListener; + + private PagerOption option; + + public static BigPhotoItemFragment newInstance(PagerOption option) { + BigPhotoItemFragment fragment = new BigPhotoItemFragment(); + Bundle bundle = new Bundle(); + bundle.putSerializable(ARGS_OPTION, option); + fragment.setArguments(bundle); + return fragment; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_big_photo_item, container, false); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + if (getArguments() == null) { + return; + } + + if (getActivity() == null) { + return; + } + this.option = (PagerOption) getArguments().getSerializable(ARGS_OPTION); + if (option == null) { + return; + } + Activity activity = getActivity(); + + ImageViewTouch image = view.findViewById(R.id.image_view); + image.setDisplayType(ImageViewTouchBase.DisplayType.FIT_TO_SCREEN); + + image.setSingleTapListener(() -> { + if (mListener != null) { + mListener.onClick(option.getPosition()); + } + }); + + image.setOnLongClickListener(v -> { + if (mListener != null) { + mListener.onLongClick(option.getPosition()); + } + return false; + }); + + int width = UIUtil.getScreenWidth(activity); + + int height = UIUtil.getScreenHeight(activity); + + LogUtil.print(ResUtil.getString(R.string.community_photo_bigphotoitemfragment_01) + height); + + int argsHeight = option.getLayoutHeight(); + LogUtil.print("argsHeight=" + argsHeight); + if (argsHeight <= 0) { + argsHeight = height; + } + + CustomItem item = option.getCustomItem(); + LogUtil.print("path:" + item.getPath()); + String limitUrl = item.getPath(); + if (item.isNetImage() && item.isImage()) { + limitUrl = ImageLoadUtilsV2.getSizeUrl(item.getPath(), width); + } + if (limitUrl.endsWith(".gif") || limitUrl.endsWith(".GIF")) { + GlideApp.with(image.getContext()) + .asGif() + .load(limitUrl) + .error(R.drawable.default_cover) + .placeholder(R.drawable.default_cover) + .apply(new RequestOptions().override(width, argsHeight).fitCenter()) + .into(image); + } else { + GlideApp.with(image.getContext()) + .asBitmap() + .load(limitUrl) + .error(R.drawable.default_cover) + .placeholder(R.drawable.default_cover) + .apply(new RequestOptions().override(width, argsHeight).fitCenter()) + .into(image); + } + + + } + + public void resetView() { + if (getView() != null) { + ((ImageViewTouch) getView().findViewById(R.id.image_view)).resetMatrix(); + } + } + + + @Override + public void onAttach(Context context) { + super.onAttach(context); + if (context instanceof OnFragmentOptionListener) { + mListener = (OnFragmentOptionListener) context; + } else { + throw new RuntimeException(context.toString() + + " must implement OnFragmentOptionListener"); + } + } + + @Override + public void onDetach() { + super.onDetach(); + mListener = null; + } +} diff --git a/app/src/main/java/com/chwl/app/photo/DynamicImageAdapter.java b/app/src/main/java/com/chwl/app/photo/DynamicImageAdapter.java new file mode 100644 index 0000000..abd4c3b --- /dev/null +++ b/app/src/main/java/com/chwl/app/photo/DynamicImageAdapter.java @@ -0,0 +1,76 @@ +package com.chwl.app.photo; + +import android.content.Context; +import android.view.ViewGroup; +import android.widget.ImageView; + +import androidx.annotation.Nullable; +import androidx.constraintlayout.widget.ConstraintLayout; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.app.ui.utils.ImageLoadUtilsV2; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.core.community.bean.DynamicMedia; +import com.chwl.library.utils.ScreenUtils; +import com.chwl.library.utils.config.BasicConfig; + +import java.util.List; + +import lombok.Setter; + +public class DynamicImageAdapter extends BaseQuickAdapter { + + private Context context; + @Setter + private int mTwoImageHeight; + @Setter + private int mThreeImageHeight; + + private int imageWidth; + + private int bigImageWidth; + + @Setter + private int singleImageHeight; + + public DynamicImageAdapter(int layoutResId, @Nullable List data) { + super(layoutResId, data); + context = BasicConfig.INSTANCE.getAppContext(); + imageWidth = UIUtil.getScreenWidth(context) * 2 / 5; + bigImageWidth = UIUtil.getScreenWidth(context); + + mTwoImageHeight = (ScreenUtils.getScreenWidth(context) - UIUtil.dip2px(context, 50F)) / 2; + mThreeImageHeight = (ScreenUtils.getScreenWidth(context) - UIUtil.dip2px(context, 60F)) / 3; + } + + @Override + protected void convert(BaseViewHolder helper, DynamicMedia item) { + ImageView ivPhoto = helper.getView(R.id.riv_photo); + helper.setGone(R.id.iv_gif_tag, item.isGif()); + ViewGroup.LayoutParams layoutParams = ivPhoto.getLayoutParams(); + if (helper.itemView instanceof ConstraintLayout && getData().size() > 1) { + ImageLoadUtilsV2.loadImage(ivPhoto, item.getResUrl(), imageWidth); + } else { + switch (getData().size()) { + case 1: + layoutParams.height = singleImageHeight; + ivPhoto.setLayoutParams(layoutParams); + ImageLoadUtilsV2.loadImage(ivPhoto, item.getResUrl(), bigImageWidth); + break; + case 2: + layoutParams.height = mTwoImageHeight; + ivPhoto.setLayoutParams(layoutParams); + ImageLoadUtilsV2.loadImage(ivPhoto, item.getResUrl(), imageWidth); + break; + case 3: + default: + layoutParams.height = mThreeImageHeight; + ivPhoto.setLayoutParams(layoutParams); + ImageLoadUtilsV2.loadImage(ivPhoto, item.getResUrl(), imageWidth); + break; + } + } + } +} diff --git a/app/src/main/java/com/chwl/app/photo/OnFragmentOptionListener.java b/app/src/main/java/com/chwl/app/photo/OnFragmentOptionListener.java new file mode 100644 index 0000000..754d547 --- /dev/null +++ b/app/src/main/java/com/chwl/app/photo/OnFragmentOptionListener.java @@ -0,0 +1,12 @@ +package com.chwl.app.photo; + +/** + * create by lvzebiao @2019/11/20 + */ +public interface OnFragmentOptionListener { + + void onClick(int position); + + void onLongClick(int position); + +} diff --git a/app/src/main/java/com/chwl/app/photo/PagerOption.java b/app/src/main/java/com/chwl/app/photo/PagerOption.java new file mode 100644 index 0000000..31d723c --- /dev/null +++ b/app/src/main/java/com/chwl/app/photo/PagerOption.java @@ -0,0 +1,51 @@ +package com.chwl.app.photo; + + +import com.example.matisse.internal.entity.CustomItem; + +import java.io.Serializable; + +import lombok.Getter; + + +/** + * create by lvzebiao @2019/11/20 + */ +@Getter +public class PagerOption implements Serializable { + + private CustomItem customItem; + + private int position; + + private boolean delete; + + private int layoutHeight; + + private boolean save; + + public PagerOption setCustomItem(CustomItem customItem) { + this.customItem = customItem; + return this; + } + + public PagerOption setPosition(int position) { + this.position = position; + return this; + } + + public PagerOption setDelete(boolean delete) { + this.delete = delete; + return this; + } + + public PagerOption setLayoutHeight(int layoutHeight) { + this.layoutHeight = layoutHeight; + return this; + } + + public PagerOption setSave(boolean save) { + this.save = save; + return this; + } +} diff --git a/app/src/main/java/com/chwl/app/photo/PhotoAdapter.java b/app/src/main/java/com/chwl/app/photo/PhotoAdapter.java new file mode 100644 index 0000000..170a739 --- /dev/null +++ b/app/src/main/java/com/chwl/app/photo/PhotoAdapter.java @@ -0,0 +1,94 @@ +package com.chwl.app.photo; + +import android.content.Context; +import android.content.Intent; +import android.graphics.Bitmap; +import android.net.Uri; +import android.os.Environment; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.bumptech.glide.request.target.SimpleTarget; +import com.bumptech.glide.request.transition.Transition; +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.app.ui.utils.ImageLoadUtilsV2; +import com.chwl.app.ui.widget.ButtonItem; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; +import com.chwl.library.utils.file.JXFileUtils; +import com.example.matisse.internal.entity.CustomItem; +import com.netease.nim.uikit.support.glide.GlideApp; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +public class PhotoAdapter extends BaseQuickAdapter { + + private Context context; + private boolean delete; + + private int screenWidth; + + public PhotoAdapter(int layoutResId, @Nullable List data, Context context, boolean delete) { + super(layoutResId, data); + this.context = context; + this.delete = delete; + screenWidth = UIUtil.getScreenWidth(context); + } + + @Override + protected void convert(BaseViewHolder helper, CustomItem item) { + helper.setIsRecyclable(false); + helper.addOnClickListener(R.id.iv_photo) + .addOnClickListener(R.id.tv_delete); + ZoomImageView photoImg = helper.getView(R.id.iv_photo); + //设置一个合适url 可能存在很大分辨率的图 + String newImage = ImageLoadUtilsV2.getSizeUrl(item.getPath(), false, screenWidth); + + photoImg.setOnLongClickListener(v -> { + DialogManager dialogManager = new DialogManager(context); + ButtonItem upItem = new ButtonItem(ResUtil.getString(R.string.community_photo_photoadapter_01), () -> savePhoto(photoImg, newImage)); + List buttonItemList = new ArrayList<>(); + buttonItemList.add(upItem); + dialogManager.showCommonPopupDialog(buttonItemList, ResUtil.getString(R.string.community_photo_photoadapter_02), false); + return true; + }); + GlideApp.with(context) + .load(newImage) + .dontAnimate() + .into(photoImg); + + if (delete) { + View tvDelete = helper.getView(R.id.tv_delete); + tvDelete.setVisibility(View.VISIBLE); + } + } + + private void savePhoto(ZoomImageView photoImg, String item) { + GlideApp.with(photoImg).asBitmap().load(item).into(new SimpleTarget() { + @Override + public void onResourceReady(@NonNull Bitmap resource, Transition transition) { + try { + File file = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM); + String imgFileName = file + File.separator + System.currentTimeMillis() + ".jpg"; + JXFileUtils.saveBitmapToJPG(resource, imgFileName); + Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); + Uri uri = Uri.fromFile(new File(imgFileName)); + intent.setData(uri); + context.sendBroadcast(intent); + SingleToastUtil.showToast(ResUtil.getString(R.string.community_photo_photoadapter_03)); + } catch (Exception e) { + e.printStackTrace(); + SingleToastUtil.showToast(ResUtil.getString(R.string.community_photo_photoadapter_04)); + } + } + }); + } +} diff --git a/app/src/main/java/com/chwl/app/photo/PreviewPhotoActivity.java b/app/src/main/java/com/chwl/app/photo/PreviewPhotoActivity.java new file mode 100644 index 0000000..6c70246 --- /dev/null +++ b/app/src/main/java/com/chwl/app/photo/PreviewPhotoActivity.java @@ -0,0 +1,88 @@ +package com.chwl.app.photo; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.PagerSnapHelper; +import androidx.recyclerview.widget.RecyclerView; + +import com.chwl.app.R; +import com.chwl.app.base.BaseActivity; +import com.chwl.app.utils.ObjectTypeHelper; +import com.example.matisse.internal.entity.CustomItem; +import com.netease.nim.uikit.common.util.log.LogUtil; + +import java.util.ArrayList; + +public class PreviewPhotoActivity extends BaseActivity { + + public final static String KEY_CURRENT_POSITION = "currentPosition"; + public final static String KEY_IMG_URL = "imgUrlList"; + public final static String KEY_DELETE = "delete"; + public final static int CODE_DELETE_PHOTO = 20; + private ArrayList mImgUrlList; + + public static void start(Context context, ArrayList imgUrlList, int currentPosition) { + + Intent intent = new Intent(context, PreviewPhotoActivity.class); + intent.putExtra(KEY_CURRENT_POSITION, currentPosition); + intent.putParcelableArrayListExtra(KEY_IMG_URL, (ArrayList) + ObjectTypeHelper.stringToCustomList(imgUrlList)); + context.startActivity(intent); + } + + public static void startForResult(Activity context, ArrayList imgUrlList, int currentPosition, boolean delete) { + Intent intent = new Intent(context, PreviewPhotoActivity.class); + intent.putExtra(KEY_CURRENT_POSITION, currentPosition); + intent.putParcelableArrayListExtra(KEY_IMG_URL, imgUrlList); + intent.putExtra(KEY_DELETE, delete); + context.startActivityForResult(intent, CODE_DELETE_PHOTO); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_preview_photo); + + mImgUrlList = getIntent().getParcelableArrayListExtra(KEY_IMG_URL); + int currentPosition = getIntent().getIntExtra(KEY_CURRENT_POSITION, 0); + boolean delete = getIntent().getBooleanExtra(KEY_DELETE, false); + + RecyclerView rvPhoto = findViewById(R.id.rv_photo); + LinearLayoutManager layoutManager = new LinearLayoutManager(context, RecyclerView.HORIZONTAL, false); + PagerSnapHelper snapHelper = new PagerSnapHelper(); + rvPhoto.setLayoutManager(layoutManager); + snapHelper.attachToRecyclerView(rvPhoto); + LogUtil.print(mImgUrlList); + PhotoAdapter adapter = new PhotoAdapter(R.layout.item_preview_photo, mImgUrlList, context, delete); + adapter.setOnItemChildClickListener((adapter1, view, position) -> { + if (view.getId() == R.id.iv_photo) { + setResultData(); + } else if (view.getId() == R.id.tv_delete) { + mImgUrlList.remove(position); + if (mImgUrlList.isEmpty()) { + setResultData(); + } else { + adapter.notifyDataSetChanged(); + } + } + }); + rvPhoto.setAdapter(adapter); + rvPhoto.scrollToPosition(currentPosition); + } + + private void setResultData() { + Intent intent = new Intent(); + intent.putParcelableArrayListExtra(KEY_IMG_URL, mImgUrlList); + setResult(RESULT_OK, intent); + finish(); + } + + @Override + public void onBackPressed() { + setResultData(); + } +} diff --git a/app/src/main/java/com/chwl/app/photo/ZoomImageView.java b/app/src/main/java/com/chwl/app/photo/ZoomImageView.java new file mode 100644 index 0000000..9a11147 --- /dev/null +++ b/app/src/main/java/com/chwl/app/photo/ZoomImageView.java @@ -0,0 +1,476 @@ +package com.chwl.app.photo; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Matrix; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.view.GestureDetector; +import android.view.MotionEvent; +import android.view.ScaleGestureDetector; +import android.view.View; +import android.view.ViewTreeObserver; +import android.widget.ImageView; + +import com.netease.nim.uikit.common.util.log.LogUtil; + + +public class ZoomImageView extends ImageView implements ScaleGestureDetector.OnScaleGestureListener, View.OnTouchListener, ViewTreeObserver.OnGlobalLayoutListener { + + private static final String TAG = ZoomImageView.class.getSimpleName(); + public static final float SCALE_MAX = 3.0f; + private static final float SCALE_MID = 1.5f; + + /** + * 初始化时的缩放比例,如果图片宽或高大于屏幕,此值将小于0 + */ + private float initScale = 1.0f; + private boolean once = true; + + /** + * 用于存放矩阵的9个值 + */ + private final float[] matrixValues = new float[9]; + + /** + * 缩放的手势检测 + */ + private ScaleGestureDetector mScaleGestureDetector = null; + private final Matrix mScaleMatrix = new Matrix(); + + /** + * 用于双击检测 + */ + private GestureDetector mGestureDetector; + private boolean isAutoScale; + + private int mTouchSlop; + + private float mLastX; + private float mLastY; + + private boolean isCanDrag; + private int lastPointerCount; + + private boolean isCheckTopAndBottom = true; + private boolean isCheckLeftAndRight = true; + private OnClickListener onClickListener; + private OnLongClickListener onLongClickListener; + + public ZoomImageView(Context context) { + this(context, null); + } + + public ZoomImageView(Context context, AttributeSet attrs) { + super(context, attrs); + super.setScaleType(ScaleType.MATRIX); + mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { + @Override + public boolean onSingleTapConfirmed(MotionEvent e) { + if (onClickListener != null) { + onClickListener.onClick(ZoomImageView.this); + return true; + } + return super.onSingleTapConfirmed(e); + } + + @Override + public void onLongPress(MotionEvent e) { + if (onLongClickListener != null) { + onLongClickListener.onLongClick(ZoomImageView.this); + } + } + + @Override + public boolean onDoubleTap(MotionEvent e) { + if (isAutoScale) + return true; + + float x = e.getX(); + float y = e.getY(); + LogUtil.print("DoubleTap, " + getScale() + " , " + initScale); + if (getScale() < SCALE_MID) { + //postDelayed(); 16 :多久实现一次的定时器操作 + ZoomImageView.this.postDelayed(new AutoScaleRunnable(SCALE_MID, x, y), 16); + isAutoScale = true; + } /*else if (getScale() >= SCALE_MID //连续双击放大 可放开 + && getScale() < SCALE_MAX) { + ZoomImageView.this.postDelayed(new AutoScaleRunnable(SCALE_MAX, x, y), 16); + isAutoScale = true; + }*/ else { + ZoomImageView.this.postDelayed(new AutoScaleRunnable(initScale, x, y), 16); + isAutoScale = true; + } + + return true; + } + }); + mScaleGestureDetector = new ScaleGestureDetector(context, this); + this.setOnTouchListener(this); + } + + /** + * 自动缩放的任务 + * + * @author zhy + */ + private class AutoScaleRunnable implements Runnable { + static final float BIGGER = 1.07f; + static final float SMALLER = 0.93f; + private float mTargetScale; + private float tmpScale; + + /** + * 缩放的中心 + */ + private float x; + private float y; + + /** + * 传入目标缩放值,根据目标值与当前值,判断应该放大还是缩小 + * + * @param targetScale + */ + public AutoScaleRunnable(float targetScale, float x, float y) { + this.mTargetScale = targetScale; + this.x = x; + this.y = y; + if (getScale() < mTargetScale) { + tmpScale = BIGGER; + } else { + tmpScale = SMALLER; + } + } + + @Override + public void run() { + // 进行缩放 + mScaleMatrix.postScale(tmpScale, tmpScale, x, y); + checkBorderAndCenterWhenScale(); + setImageMatrix(mScaleMatrix); + + final float currentScale = getScale(); + // 如果值在合法范围内,继续缩放 + if (((tmpScale > 1f) && (currentScale < mTargetScale)) || ((tmpScale < 1f) && (mTargetScale < currentScale))) { + + ZoomImageView.this.postDelayed(this, 16); + } else { + // 设置为目标的缩放比例 + final float deltaScale = mTargetScale / currentScale; + mScaleMatrix.postScale(deltaScale, deltaScale, x, y); + checkBorderAndCenterWhenScale(); + setImageMatrix(mScaleMatrix); + isAutoScale = false; + } + } + } + + /** + * 对图片进行缩放的控制,首先进行缩放范围的判断,然后设置mScaleMatrix的scale值 + * + * @param detector + * @return + */ + @SuppressLint("NewApi") + @Override + public boolean onScale(ScaleGestureDetector detector) { + float scale = getScale(); + float scaleFactor = detector.getScaleFactor(); + + if (getDrawable() == null) + return true; + + /** + * 缩放的范围控制 + */ + if ((scale < SCALE_MAX && scaleFactor > 1.0f) || (scale > initScale && scaleFactor < 1.0f)) { + /** + * 最大值最小值判断 + */ + if (scaleFactor * scale < initScale) { + scaleFactor = initScale / scale; + } + if (scaleFactor * scale > SCALE_MAX) { + scaleFactor = SCALE_MAX / scale; + } + /** + * 设置缩放比例 + */ + mScaleMatrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY()); + + checkBorderAndCenterWhenScale(); + setImageMatrix(mScaleMatrix); + } + return true; + } + + /** + * 在缩放时,进行图片显示范围的控制 + */ + private void checkBorderAndCenterWhenScale() { + + RectF rect = getMatrixRectF(); + float deltaX = 0; + float deltaY = 0; + + int width = getWidth(); + int height = getHeight(); + + // 如果宽或高大于屏幕,则控制范围 + if (rect.width() >= width) { + if (rect.left > 0) { + deltaX = -rect.left; + } + if (rect.right < width) { + deltaX = width - rect.right; + } + } + if (rect.height() >= height) { + if (rect.top > 0) { + deltaY = -rect.top; + } + if (rect.bottom < height) { + deltaY = height - rect.bottom; + } + } + // 如果宽或高小于屏幕,则让其居中 + if (rect.width() < width) { + deltaX = width * 0.5f - rect.right + 0.5f * rect.width(); + } + if (rect.height() < height) { + deltaY = height * 0.5f - rect.bottom + 0.5f * rect.height(); + } + + + mScaleMatrix.postTranslate(deltaX, deltaY); + + } + + /** + * 根据当前图片的Matrix获得图片的范围 + * + * @return + */ + private RectF getMatrixRectF() { + Matrix matrix = mScaleMatrix; + RectF rect = new RectF(); + Drawable d = getDrawable(); + if (null != d) { + rect.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight()); + matrix.mapRect(rect); + } + return rect; + } + + @Override + public boolean onScaleBegin(ScaleGestureDetector detector) { + return true; + } + + @Override + public void onScaleEnd(ScaleGestureDetector detector) { + } + + /** + * 我们让OnTouchListener的MotionEvent交给ScaleGestureDetector进行处理 + * public boolean onTouch(View v, MotionEvent event){ + * return mScaleGestureDetector.onTouchEvent(event); + * } + */ + @Override + public boolean onTouch(View v, MotionEvent event) { + + if (mGestureDetector.onTouchEvent(event)) + return true; + mScaleGestureDetector.onTouchEvent(event); + + float x = 0, y = 0; + // 拿到触摸点的个数 + final int pointerCount = event.getPointerCount(); + // 得到多个触摸点的x与y均值 + for (int i = 0; i < pointerCount; i++) { + x += event.getX(i); + y += event.getY(i); + } + x = x / pointerCount; + y = y / pointerCount; + + /** + * 每当触摸点发生变化时,重置mLasX , mLastY + */ + if (pointerCount != lastPointerCount) { + isCanDrag = false; + mLastX = x; + mLastY = y; + } + + lastPointerCount = pointerCount; + RectF rectF = getMatrixRectF(); + + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + if (rectF.width() > getWidth() || rectF.height() > getHeight()) { + getParent().requestDisallowInterceptTouchEvent(true); + } + break; + case MotionEvent.ACTION_MOVE: + if (rectF.width() > getWidth() || rectF.height() > getHeight()) { + getParent().requestDisallowInterceptTouchEvent(true); + } + + float dx = x - mLastX; + float dy = y - mLastY; + + if (!isCanDrag) { + isCanDrag = isCanDrag(dx, dy); + } + if (isCanDrag) { + + if (getDrawable() != null) { + // if (getMatrixRectF().left == 0 && dx > 0) + // { + // getParent().requestDisallowInterceptTouchEvent(false); + // } + // + // if (getMatrixRectF().right == getWidth() && dx < 0) + // { + // getParent().requestDisallowInterceptTouchEvent(false); + // } + isCheckLeftAndRight = isCheckTopAndBottom = true; + // 如果宽度小于屏幕宽度,则禁止左右移动 + if (rectF.width() < getWidth()) { + dx = 0; + isCheckLeftAndRight = false; + } + // 如果高度小雨屏幕高度,则禁止上下移动 + if (rectF.height() < getHeight()) { + dy = 0; + isCheckTopAndBottom = false; + } + + //设置偏移量 + mScaleMatrix.postTranslate(dx, dy); + //再次校验 + checkMatrixBounds(); + setImageMatrix(mScaleMatrix); + } + } + mLastX = x; + mLastY = y; + break; + + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + + lastPointerCount = 0; + break; + } + return true; + } + + /** + * 获得当前的缩放比例 + * + * @return + */ + public final float getScale() { + mScaleMatrix.getValues(matrixValues); + return matrixValues[Matrix.MSCALE_X]; + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + getViewTreeObserver().addOnGlobalLayoutListener(this); + } + + @SuppressWarnings("deprecation") + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + getViewTreeObserver().removeGlobalOnLayoutListener(this); + } + + /** + * 根据图片的宽和高以及屏幕的宽和高,对图片进行缩放以及移动至屏幕的中心。 + * 如果图片很小,那就正常显示,不放大了~ + */ + @Override + public void onGlobalLayout() { + if (once) { + Drawable d = getDrawable(); + if (d == null) + return; + + int width = getWidth(); + int height = getHeight(); + // 拿到图片的宽和高 + int dw = d.getIntrinsicWidth(); + int dh = d.getIntrinsicHeight(); + float scale = 1.0f; + // 如果图片的宽或者高大于屏幕,则缩放至屏幕的宽或者高 + if (dw > width && dh <= height) { + scale = width * 1.0f / dw; + } + if (dh > height && dw <= width) { + scale = height * 1.0f / dh; + } + // 如果宽和高都大于屏幕,则让其按按比例适应屏幕大小 + if (dw > width && dh > height) { + scale = Math.min(width * 1.0f / dw, height * 1.0f / dh); + } + initScale = scale; + + mScaleMatrix.postTranslate((width - dw) / 2, (height - dh) / 2); + mScaleMatrix.postScale(scale, scale, getWidth() / 2, getHeight() / 2); + // 图片移动至屏幕中心 + setImageMatrix(mScaleMatrix); + once = false; + } + } + + /** + * 移动时,进行边界判断,主要判断宽或高大于屏幕的 + */ + private void checkMatrixBounds() { + RectF rect = getMatrixRectF(); + + float deltaX = 0, deltaY = 0; + final float viewWidth = getWidth(); + final float viewHeight = getHeight(); + // 判断移动或缩放后,图片显示是否超出屏幕边界 + if (rect.top > 0 && isCheckTopAndBottom) { + deltaY = -rect.top; + } + if (rect.bottom < viewHeight && isCheckTopAndBottom) { + deltaY = viewHeight - rect.bottom; + } + if (rect.left > 0 && isCheckLeftAndRight) { + deltaX = -rect.left; + } + if (rect.right < viewWidth && isCheckLeftAndRight) { + deltaX = viewWidth - rect.right; + } + mScaleMatrix.postTranslate(deltaX, deltaY); + } + + /** + * 是否是推动行为 + * + * @param dx + * @param dy + * @return + */ + private boolean isCanDrag(float dx, float dy) { + return Math.sqrt((dx * dx) + (dy * dy)) >= mTouchSlop; + } + + public void setOnClickListener(OnClickListener onClickListener) { + this.onClickListener = onClickListener; + } + + public void setOnLongClickListener(OnLongClickListener onLongClickListener) { + this.onLongClickListener = onLongClickListener; + } +} diff --git a/app/src/main/java/com/chwl/app/radish/activity/RadishRecordActivity.java b/app/src/main/java/com/chwl/app/radish/activity/RadishRecordActivity.java new file mode 100644 index 0000000..84c142f --- /dev/null +++ b/app/src/main/java/com/chwl/app/radish/activity/RadishRecordActivity.java @@ -0,0 +1,128 @@ +package com.chwl.app.radish.activity; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.TextView; + +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.Observer; +import androidx.viewpager.widget.ViewPager; + +import com.netease.nim.uikit.StatusBarUtil; +import com.chwl.app.R; +import com.chwl.app.avroom.adapter.RoomContributeListAdapter; +import com.chwl.app.base.BaseMvpActivity; +import com.chwl.app.base.TitleBar; +import com.chwl.app.radish.presenter.RadishRecordPresenter; +import com.chwl.app.radish.view.IRadishRecordView; +import com.chwl.app.radish.wallet.RadishWalletManager; +import com.chwl.app.radish.widget.RadishRecordNavAdapter; +import com.chwl.app.ui.radish.RadishRecordFragment; +import com.chwl.app.ui.webview.CommonWebViewActivity; +import com.chwl.app.ui.widget.magicindicator.MagicIndicator; +import com.chwl.app.ui.widget.magicindicator.ViewPagerHelper; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.CommonNavigator; +import com.chwl.core.UriProvider; +import com.chwl.core.radish.RadishWalletInfo; +import com.chwl.library.base.factory.CreatePresenter; +import com.chwl.library.utils.ResUtil; + +import java.util.ArrayList; + +@CreatePresenter(RadishRecordPresenter.class) +public class RadishRecordActivity extends BaseMvpActivity implements IRadishRecordView { + + private MagicIndicator mMagicIndicator; + private ViewPager mVpRadishRecord; + private TextView tvTotalRadish; + + public static void startActivity(Context context) { + Intent intent = new Intent(context, RadishRecordActivity.class); + context.startActivity(intent); + } + + @Override + protected boolean needSteepStateBar() { + return true; + } + + @Override + protected void setStatusBar() { + super.setStatusBar(); + StatusBarUtil.transparencyBar(this); + StatusBarUtil.StatusBarLightMode(this); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_radish_record); + findView(); + initTitleBar(ResUtil.getString(R.string.radish_activity_radishrecordactivity_02)); + setTotalRadish(0L); + + ArrayList fragments = new ArrayList<>(2); + fragments.add(RadishRecordFragment.newInstance(RadishRecordFragment.TYPE_RADISH_INCOME)); + fragments.add(RadishRecordFragment.newInstance(RadishRecordFragment.TYPE_RADISH_EXPAND)); + mVpRadishRecord.setAdapter(new RoomContributeListAdapter(getSupportFragmentManager(), fragments)); + CommonNavigator commonNavigator = new CommonNavigator(this); + commonNavigator.setAdjustMode(true); + + RadishRecordNavAdapter indicator = new RadishRecordNavAdapter(); + indicator.setOnItemSelectListener(position -> mVpRadishRecord.setCurrentItem(position)); + commonNavigator.setAdapter(indicator); + mMagicIndicator.setNavigator(commonNavigator); + ViewPagerHelper.bind(mMagicIndicator, mVpRadishRecord); + + RadishWalletManager.get().registerRadishNum(this, new Observer() { + @Override + public void onChanged(@Nullable RadishWalletInfo radishWalletInfo) { + if (radishWalletInfo != null) { + setTotalRadish(radishWalletInfo.getAmount()); + } + } + }); + getMvpPresenter().getRadishWallet(); + } + + private void findView() { + mMagicIndicator = findViewById(R.id.mi_radish_record); + mVpRadishRecord = findViewById(R.id.vp_radish_record); + tvTotalRadish = findViewById(R.id.tv_total_radish); + } + + private void setTotalRadish(long total) { + if (tvTotalRadish != null) + tvTotalRadish.setText(getMvpPresenter().formatBigDecimal(total)); + } + + @Override + public void initTitleBar(String title) { + if (mTitleBar != null) { + mTitleBar.setTitle(title); + mTitleBar.setImmersive(true); + mTitleBar.setTitleColor(getResources().getColor(R.color.white)); + mTitleBar.setLeftImageResource(R.drawable.arrow_left); + mTitleBar.setBackgroundColor(getResources().getColor(R.color.transparent)); + mTitleBar.setLeftClickListener(v -> finish()); + } + + addAction(); + } + + private void addAction() { + if (mTitleBar != null) { + mTitleBar.addAction(new TitleBar.ImageAction(R.mipmap.common_ic_help_white) { + @Override + public void performAction(View view) { + CommonWebViewActivity.start(RadishRecordActivity.this, UriProvider.JAVA_WEB_URL + "/molistar/modules/rule/radish.html"); + } + }); + } + } + +} diff --git a/app/src/main/java/com/chwl/app/radish/adapter/RadishRecordAdapter.java b/app/src/main/java/com/chwl/app/radish/adapter/RadishRecordAdapter.java new file mode 100644 index 0000000..f7df4d9 --- /dev/null +++ b/app/src/main/java/com/chwl/app/radish/adapter/RadishRecordAdapter.java @@ -0,0 +1,38 @@ +package com.chwl.app.radish.adapter; + +import static com.chwl.app.ui.radish.RadishRecordFragment.TYPE_RADISH_INCOME; + +import androidx.core.content.ContextCompat; + +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.app.bills.adapter.BillBaseAdapter; +import com.chwl.core.bills.bean.BillItemEntity; +import com.chwl.core.bills.bean.RadishRecordInfo; +import com.chwl.library.utils.TimeUtils; + +import java.util.List; + +public class RadishRecordAdapter extends BillBaseAdapter { + private byte mType; + + public RadishRecordAdapter(List billItemEntityList, byte type) { + super(billItemEntityList); + addItemType(BillItemEntity.ITEM_NORMAL, R.layout.item_radish_record); + + mType = type; + } + + @Override + public void convertNormal(BaseViewHolder baseViewHolder, BillItemEntity billItemEntity) { + + RadishRecordInfo radishRecordInfo = billItemEntity.mRadishRecordInfo; + if (radishRecordInfo == null) return; + baseViewHolder.setText(R.id.tv_record_name, radishRecordInfo.getDescribeStr()) + .setText(R.id.tv_record_hmd, TimeUtils.getDateTimeString(radishRecordInfo.getCreateTime(), "HH:mm:ss")) + .setText(R.id.tv_record_value, radishRecordInfo.getAmountStr()) + .setTextColor(R.id.tv_record_value, + ContextCompat.getColor(mContext, mType == TYPE_RADISH_INCOME ? R.color.appColor : R.color.color_333333)); + + } +} diff --git a/app/src/main/java/com/chwl/app/radish/helper/PrizeAnimUiHelper.java b/app/src/main/java/com/chwl/app/radish/helper/PrizeAnimUiHelper.java new file mode 100644 index 0000000..1fae1e2 --- /dev/null +++ b/app/src/main/java/com/chwl/app/radish/helper/PrizeAnimUiHelper.java @@ -0,0 +1,202 @@ +package com.chwl.app.radish.helper; + +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.text.TextUtils; +import android.view.View; +import android.view.animation.DecelerateInterpolator; +import android.widget.ImageView; +import android.widget.TextView; + +import com.chwl.app.R; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.radish.task.bean.PrizeAnim; +import com.chwl.core.utils.net.BeanObserver; +import com.chwl.core.utils.net.RxHelper; + +import java.util.concurrent.TimeUnit; + +import io.reactivex.Single; +import io.reactivex.android.schedulers.AndroidSchedulers; + +/** + * 动画界面,签到和任务界面一样,整合一处 + * create by lvzebiao @2019/3/26 + */ +public class PrizeAnimUiHelper { + + /** + * 任务界面 + */ + public final static int TYPE_TASK_PAGE = 1; + private ImageView ivRewardBg; + private ImageView ivRewardContent; + private TextView tvDetailPrizeName; + private TextView tvLabelNum; + private TextView tvDetailPrizeNumber; + private TextView tvDetailTips; + private TextView tvDetailShare; + + private AnimatorSet contentAllSet; + + private AnimatorSet bgSet; + + private View clRewardAnimContainer; + + private Context context; + + private int mType; + + private PrizeAnim prizeAnim; + + private DialogManager dialogManager; + + private void close() { + clRewardAnimContainer.setVisibility(View.GONE); + prizeAnim = null; + } + + public void onCreate(Context context, View parent, int type, DialogManager dialogManager) { + this.context = context; + findView(); + this.clRewardAnimContainer = parent; + clRewardAnimContainer.setOnClickListener(v -> close()); + this.mType = type; + if (dialogManager == null) { + dialogManager = new DialogManager(context); + } + this.dialogManager = dialogManager; + clRewardAnimContainer.setVisibility(View.GONE); + if (mType == TYPE_TASK_PAGE) { + tvDetailTips.setVisibility(View.VISIBLE); + tvDetailShare.setVisibility(View.GONE); + } else { + tvDetailTips.setVisibility(View.GONE); + tvDetailShare.setVisibility(View.VISIBLE); + tvDetailShare.setOnClickListener(v -> { + if (prizeAnim == null) { + return; + } + }); + } + + } + + private void findView() { + ivRewardBg = clRewardAnimContainer.findViewById(R.id.iv_reward_bg); + ivRewardContent = clRewardAnimContainer.findViewById(R.id.iv_reward_content); + tvDetailPrizeName = clRewardAnimContainer.findViewById(R.id.tv_detail_prize_name); + tvLabelNum = clRewardAnimContainer.findViewById(R.id.tv_label_number); + tvDetailPrizeNumber = clRewardAnimContainer.findViewById(R.id.tv_detail_prize_number); + tvDetailTips = clRewardAnimContainer.findViewById(R.id.tv_detail_tips); + tvDetailShare = clRewardAnimContainer.findViewById(R.id.tv_detail_share); + } + + public void showPrizeInfoUi(PrizeAnim prizeAnim) { + if (prizeAnim == null) { + return; + } + this.prizeAnim = prizeAnim; + clRewardAnimContainer.setVisibility(View.VISIBLE); + if (!TextUtils.isEmpty(prizeAnim.getPrizePic())) { + ImageLoadUtils.loadDrawable(context, prizeAnim.getPrizePic()) + .compose(RxHelper.bindContext(context)) + .subscribe(new BeanObserver() { + @Override + public void onErrorMsg(String error) { + + } + + @Override + public void onSuccess(Drawable drawable) { + playAnim(drawable); + } + }); + } else + playAnim(ivRewardContent.getContext().getResources().getDrawable(R.drawable.icon_draw_gold)); + + tvDetailPrizeName.setText(prizeAnim.getPrizeName()); + tvLabelNum.setVisibility(View.GONE); + tvDetailPrizeNumber.setVisibility(View.GONE); + + if (mType == TYPE_TASK_PAGE) { + tvDetailTips.setText(prizeAnim.getTips()); + } + } + + public void setType(int type) { + this.mType = type; + } + + @SuppressLint("CheckResult") + private void playAnim(Drawable drawable) { + + ivRewardBg.setImageResource(R.drawable.icon_reward_bg); + ivRewardContent.setImageDrawable(drawable); + + playRewardContentAnim(ivRewardContent); + ivRewardBg.setVisibility(View.INVISIBLE); + //noinspection ResultOfMethodCallIgnored + Single.timer(200, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread()) + .compose(RxHelper.bindContext(context)) + .subscribe(aLong -> { + playRewardBgAnim(ivRewardBg); + ivRewardBg.setVisibility(View.VISIBLE); + }); + } + + private void playRewardContentAnim(View ivRewardContent) { + //内容的动画 + //透明度 + ObjectAnimator contentAlpha = ObjectAnimator.ofFloat(ivRewardContent, "alpha", 0f, 1f); + contentAlpha.setDuration(200); + //缩放 + ObjectAnimator contentScaleX = ObjectAnimator.ofFloat(ivRewardContent, "scaleX", 0f, 1.15f, 1f); + ObjectAnimator contentScaleY = ObjectAnimator.ofFloat(ivRewardContent, "scaleY", 0f, 1.15f, 1f); + AnimatorSet contentScale = new AnimatorSet(); + contentScale.play(contentScaleX).with(contentScaleY); + contentScale.setDuration(640); + //内容的放一起 + contentAllSet = new AnimatorSet(); + contentAllSet.play(contentAlpha).with(contentScale); + contentAllSet.setInterpolator(new DecelerateInterpolator()); + contentAllSet.start(); + } + + private void playRewardBgAnim(View ivRewardBg) { + //背景动画 + ObjectAnimator animatorScaleY = ObjectAnimator.ofFloat(ivRewardBg, "scaleY", 0f, 1.1f, 1f); + ObjectAnimator animatorScaleX = ObjectAnimator.ofFloat(ivRewardBg, "scaleX", 0f, 1.1f, 1f); + + ObjectAnimator animatorAlpha = ObjectAnimator.ofFloat(ivRewardBg, "alpha", 0.4f, 1f); + animatorAlpha.setDuration(120); + + bgSet = new AnimatorSet(); + bgSet.play(animatorScaleX).with(animatorScaleY).with(animatorAlpha); + bgSet.setDuration(720); + bgSet.setInterpolator(new DecelerateInterpolator()); + bgSet.start(); + } + + public boolean onBackPressed() { + boolean hasHandle = false; + if (clRewardAnimContainer.getVisibility() == View.VISIBLE) { + clRewardAnimContainer.setVisibility(View.GONE); + hasHandle = true; + } + return hasHandle; + } + + public void onDestroy() { + if (contentAllSet != null) { + contentAllSet.cancel(); + } + if (bgSet != null) { + bgSet.cancel(); + } + } +} diff --git a/app/src/main/java/com/chwl/app/radish/helper/TaskCenterDialogHelper.java b/app/src/main/java/com/chwl/app/radish/helper/TaskCenterDialogHelper.java new file mode 100644 index 0000000..578923d --- /dev/null +++ b/app/src/main/java/com/chwl/app/radish/helper/TaskCenterDialogHelper.java @@ -0,0 +1,34 @@ +package com.chwl.app.radish.helper; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import com.chwl.app.R; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.app.ui.utils.ImageLoadUtils; + +public class TaskCenterDialogHelper { + + private Context mContext; + private DialogManager mDialogManager; + + public TaskCenterDialogHelper(Context context) { + this.mContext = context; + mDialogManager = new DialogManager(mContext); + } + + public void showDialog(String picUrl) { + View view1 = LayoutInflater.from(mContext).inflate(R.layout.dialog_task, null); + ImageView imageView = view1.findViewById(R.id.iv_task_guide); + if (imageView != null) + ImageLoadUtils.loadImage(mContext, picUrl, imageView); + + TextView cancel = view1.findViewById(R.id.btn_cancel); + cancel.setOnClickListener(v -> mDialogManager.dismissDialog()); + + mDialogManager.showCustomViewDialog(view1); + } +} diff --git a/app/src/main/java/com/chwl/app/radish/presenter/RadishRecordFrgPresenter.java b/app/src/main/java/com/chwl/app/radish/presenter/RadishRecordFrgPresenter.java new file mode 100644 index 0000000..4416161 --- /dev/null +++ b/app/src/main/java/com/chwl/app/radish/presenter/RadishRecordFrgPresenter.java @@ -0,0 +1,42 @@ +package com.chwl.app.radish.presenter; + +import com.chwl.app.base.BaseMvpPresenter; +import com.chwl.app.radish.view.IRadishRecordFrgView; +import com.chwl.core.radish.RadishModel; +import com.chwl.core.radish.RadishRecordResult; + +import io.reactivex.SingleObserver; +import io.reactivex.disposables.Disposable; + +public class RadishRecordFrgPresenter extends BaseMvpPresenter { + + public void getRadishRecord(int page, int pageSize, long date, byte type) { + RadishModel.get().getRadishRecord(page, pageSize, date, type) + .subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onSuccess(RadishRecordResult radishRecordResult) { + if (radishRecordResult != null && radishRecordResult.isSuccess()) { + if (mMvpView != null) + mMvpView.getRadishRecordSuccess(radishRecordResult.getData()); + } else if (radishRecordResult != null){ + if (mMvpView != null) + mMvpView.getRadishRecordFail(radishRecordResult.getError()); + } + } + + @Override + public void onError(Throwable e) { + if (mMvpView != null) + mMvpView.getRadishRecordFail(e.getMessage()); + + } + }); + + } + +} diff --git a/app/src/main/java/com/chwl/app/radish/presenter/RadishRecordPresenter.java b/app/src/main/java/com/chwl/app/radish/presenter/RadishRecordPresenter.java new file mode 100644 index 0000000..551d979 --- /dev/null +++ b/app/src/main/java/com/chwl/app/radish/presenter/RadishRecordPresenter.java @@ -0,0 +1,28 @@ +package com.chwl.app.radish.presenter; + +import com.chwl.app.base.BaseMvpPresenter; +import com.chwl.app.radish.view.IRadishRecordView; +import com.chwl.core.radish.RadishModel; + +import java.math.RoundingMode; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Locale; + +public class RadishRecordPresenter extends BaseMvpPresenter { + public void getRadishWallet() { + RadishModel.get().updateRadishWallet() + .subscribe(); + } + + public String formatBigDecimal(long bigDecimal) { + try { + DecimalFormat decimalFormat = new DecimalFormat("#,###"); + decimalFormat.setDecimalFormatSymbols(DecimalFormatSymbols.getInstance(Locale.ENGLISH)); + decimalFormat.setRoundingMode(RoundingMode.HALF_UP); + return decimalFormat.format(bigDecimal); + } catch (Exception e) { + } + return "0"; + } +} diff --git a/app/src/main/java/com/chwl/app/radish/task/activity/TaskCenterActivity.java b/app/src/main/java/com/chwl/app/radish/task/activity/TaskCenterActivity.java new file mode 100644 index 0000000..dadd03a --- /dev/null +++ b/app/src/main/java/com/chwl/app/radish/task/activity/TaskCenterActivity.java @@ -0,0 +1,167 @@ +package com.chwl.app.radish.task.activity; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.view.ViewStub; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.fragment.app.Fragment; +import androidx.viewpager.widget.ViewPager; + +import com.chwl.app.R; +import com.chwl.app.avroom.adapter.RoomContributeListAdapter; +import com.chwl.app.base.BaseMvpActivity; +import com.chwl.app.radish.helper.PrizeAnimUiHelper; +import com.chwl.app.radish.task.fragment.TaskCenterFragment; +import com.chwl.app.radish.task.presenter.TaskCenterPresenter; +import com.chwl.app.radish.task.view.ITaskCenterView; +import com.chwl.app.radish.widget.TaskCenterNavAdapter; +import com.chwl.app.ui.widget.magicindicator.MagicIndicator; +import com.chwl.app.ui.widget.magicindicator.ViewPagerHelper; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.CommonNavigator; +import com.chwl.core.radish.task.bean.PrizeAnim; +import com.chwl.core.radish.task.bean.TaskInfo; +import com.chwl.core.utils.SharedPreferenceUtils; +import com.chwl.library.base.factory.CreatePresenter; +import com.chwl.library.utils.ResUtil; + +import java.util.ArrayList; + +/** + * 任务中心 + * create by lvzebiao @2019/3/26 + */ +@CreatePresenter(TaskCenterPresenter.class) +public class TaskCenterActivity extends BaseMvpActivity implements ITaskCenterView { + + public interface FromPage { + String GIFT = ResUtil.getString(R.string.task_activity_taskcenteractivity_01); + String FIND = ResUtil.getString(R.string.task_activity_taskcenteractivity_02); + String RADISH_NOT_ENOUGH_DIALOG = ResUtil.getString(R.string.task_activity_taskcenteractivity_03); + } + + /** + * 任务中心是否第一次启动 + */ + public final static String KEY_TASK_CENTER_FIRST_START = "task_center_first_start"; + + private MagicIndicator magicIndicator; + private ViewPager viewPager; + private ViewStub vsStartTips; + + PrizeAnimUiHelper priceAnimUiHelper; + + public static void start(Context context, String fromPage) { + Intent intent = new Intent(context, TaskCenterActivity.class); + context.startActivity(intent); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_task_center); + findView(); + initTitleBar(context.getResources().getString(R.string.task_center)); + priceAnimUiHelper = new PrizeAnimUiHelper(); + priceAnimUiHelper.onCreate(this, findViewById(R.id.cl_reward_anim_container), + PrizeAnimUiHelper.TYPE_TASK_PAGE, getDialogManager()); + + ArrayList fragments = new ArrayList<>(2); + TaskCenterFragment days = TaskCenterFragment.newInstance(TaskCenterFragment.TYPE_TASK); + days.setiTaskCenterView(this); + TaskCenterFragment task = TaskCenterFragment.newInstance(TaskCenterFragment.TYPE_ACHIEVEMENT); + task.setiTaskCenterView(this); + fragments.add(days); + fragments.add(task); + + viewPager.setAdapter(new RoomContributeListAdapter(getSupportFragmentManager(), fragments)); + CommonNavigator commonNavigator = new CommonNavigator(this); + commonNavigator.setAdjustMode(true); + + TaskCenterNavAdapter indicator = new TaskCenterNavAdapter(); + indicator.setOnItemSelectListener(position -> viewPager.setCurrentItem(position)); + commonNavigator.setAdapter(indicator); + magicIndicator.setNavigator(commonNavigator); + ViewPagerHelper.bind(magicIndicator, viewPager); + +// showStartTips(); + } + + private void findView() { + magicIndicator = findViewById(R.id.mi_task); + viewPager = findViewById(R.id.vp_task_center); + vsStartTips = findViewById(R.id.vs_start_tips); + } + + @Override + public void onBackPressed() { + if (priceAnimUiHelper.onBackPressed()) { + return; + } + super.onBackPressed(); + } + + @Override + public void playPriceAnim(TaskInfo info) { + if (priceAnimUiHelper != null && info != null) + priceAnimUiHelper.showPrizeInfoUi(PrizeAnim.formatTaskInfo(info)); + } + + public void initTitleBar(String title) { + mTitleBar = findViewById(R.id.title_bar); + if (mTitleBar != null) { + mTitleBar.setTitle(title); + mTitleBar.setImmersive(false); + mTitleBar.setTitleColor(getResources().getColor(R.color.white)); + mTitleBar.setLeftImageResource(R.mipmap.common_ic_back_white); + mTitleBar.setBackgroundResource(R.color.transparent); + mTitleBar.setLeftClickListener(v -> onLeftClickListener()); + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + priceAnimUiHelper.onDestroy(); + } + + private int indexTips = 0; + + /** + * 首次启动展示 提示图 + */ + private void showStartTips() { + boolean isFirst = (boolean) SharedPreferenceUtils.get(KEY_TASK_CENTER_FIRST_START, true); + if (!isFirst) { + return; + } + SharedPreferenceUtils.put(KEY_TASK_CENTER_FIRST_START, false); + View llTaskTtartContainer = vsStartTips.inflate(); + int[] topTipsRes = new int[]{R.drawable.cover_task_top_first, R.drawable.cover_task_top_second, + R.drawable.cover_task_top_third, R.drawable.cover_task_top_fourth}; + + ImageView ivTipsTop = llTaskTtartContainer.findViewById(R.id.iv_tips_top); + ivTipsTop.setImageResource(topTipsRes[indexTips++]); + + TextView tv_skip_guide = llTaskTtartContainer.findViewById(R.id.tv_skip_guide); + tv_skip_guide.setOnClickListener(v -> + llTaskTtartContainer.setVisibility(View.GONE)); + tv_skip_guide.setVisibility(View.VISIBLE); + llTaskTtartContainer.setOnClickListener(v -> { + if (indexTips < topTipsRes.length) { + if (indexTips == topTipsRes.length - 1) { + tv_skip_guide.setVisibility(View.GONE); + } else { + tv_skip_guide.setVisibility(View.VISIBLE); + } + ivTipsTop.setImageResource(topTipsRes[indexTips++]); + } else { + llTaskTtartContainer.setVisibility(View.GONE); + } + }); + } + +} diff --git a/app/src/main/java/com/chwl/app/radish/task/adpter/TaskCenterAdapter.java b/app/src/main/java/com/chwl/app/radish/task/adpter/TaskCenterAdapter.java new file mode 100644 index 0000000..f7ebf8b --- /dev/null +++ b/app/src/main/java/com/chwl/app/radish/task/adpter/TaskCenterAdapter.java @@ -0,0 +1,70 @@ +package com.chwl.app.radish.task.adpter; + +import android.content.Context; +import android.text.TextUtils; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.radish.task.bean.TaskInfo; + +/** + * create by lvzebiao @2019/3/26 + */ +public class TaskCenterAdapter extends BaseQuickAdapter { + + private Context context; + + public TaskCenterAdapter(Context context) { + super(R.layout.item_task); + this.context = context; + } + + @Override + protected void convert(BaseViewHolder helper, TaskInfo item) { + helper.setText(R.id.tv_task_name, item.getName()); + helper.setText(R.id.tv_task_desc, item.getDescription()); + + TextView tvOperationStatus = helper.getView(R.id.tv_operation_status); + helper.addOnClickListener(R.id.tv_operation_status); + tvOperationStatus.setClickable(true); + if (item.getStatus() == TaskInfo.STATUS_HAS_RECEIVED) { + //已完成 + tvOperationStatus.setText(R.string.task_done); + tvOperationStatus.setBackgroundResource(R.drawable.icon_task_has_received); + tvOperationStatus.setTextColor(context.getResources().getColor(R.color.color_B3B3B3)); + tvOperationStatus.setClickable(false); + } else if (item.getStatus() == TaskInfo.STATUS_FINISHED_NOT_RECEIVE) { + //完成未领取 + tvOperationStatus.setText(R.string.task_receive); + tvOperationStatus.setBackgroundResource(R.drawable.icon_task_finished_not_receive); + tvOperationStatus.setTextColor(context.getResources().getColor(R.color.white)); + } else { + //未完成 + tvOperationStatus.setText(R.string.task_go_to_finish); + tvOperationStatus.setBackgroundResource(R.drawable.icon_task_un_finish); + tvOperationStatus.setTextColor(context.getResources().getColor(R.color.white)); + } + + ImageView ivPrizeIcon = helper.getView(R.id.iv_prize_icon); + if (TextUtils.isEmpty(item.getPrizeIcon())) { + ivPrizeIcon.setVisibility(View.INVISIBLE); + } else { + ivPrizeIcon.setVisibility(View.VISIBLE); + ImageLoadUtils.loadImage(context, item.getPrizeIcon(), ivPrizeIcon); + } + + TextView tvPrizeNum = helper.getView(R.id.tv_prize_num); + if (item.getPrizeNum() > 0) { + tvPrizeNum.setVisibility(View.VISIBLE); + tvPrizeNum.setText("x" + item.getPrizeNum()); + } else { + tvPrizeNum.setVisibility(View.INVISIBLE); + } + + } +} diff --git a/app/src/main/java/com/chwl/app/radish/task/fragment/TaskCenterFragment.java b/app/src/main/java/com/chwl/app/radish/task/fragment/TaskCenterFragment.java new file mode 100644 index 0000000..a4db4f3 --- /dev/null +++ b/app/src/main/java/com/chwl/app/radish/task/fragment/TaskCenterFragment.java @@ -0,0 +1,194 @@ +package com.chwl.app.radish.task.fragment; + +import android.annotation.SuppressLint; +import android.os.Bundle; +import android.view.View; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.SimpleItemAnimator; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chwl.app.R; +import com.chwl.app.base.BaseMvpFragment; +import com.chwl.app.radish.helper.TaskCenterDialogHelper; +import com.chwl.app.radish.task.adpter.TaskCenterAdapter; +import com.chwl.app.radish.task.presenter.TaskCenterFrgPresenter; +import com.chwl.app.radish.task.view.ITaskCenterView; +import com.chwl.app.radish.task.view.ITaskCenterViewFrg; +import com.chwl.app.ui.im.RouterHandler; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.ui.widget.recyclerview.decoration.HorizontalDecoration; +import com.chwl.core.XConstants; +import com.chwl.core.radish.task.ITaskModel; +import com.chwl.core.radish.task.TaskModel; +import com.chwl.core.radish.task.bean.TaskInfo; +import com.chwl.core.utils.net.DontWarnObserver; +import com.chwl.core.utils.net.RxHelper; +import com.chwl.library.base.factory.CreatePresenter; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; + +@CreatePresenter(TaskCenterFrgPresenter.class) +public class TaskCenterFragment extends BaseMvpFragment implements ITaskCenterViewFrg{ + + public static final int TYPE_TASK = 1; + public static final int TYPE_ACHIEVEMENT = 2; + + private RecyclerView rvTaskList; + private SwipeRefreshLayout swipeRefresh; + + private TaskCenterAdapter adapter; + ITaskModel model = new TaskModel(); + private ITaskCenterView iTaskCenterView; + + public static TaskCenterFragment newInstance(int type) { + TaskCenterFragment fragment = new TaskCenterFragment(); + Bundle bundle = new Bundle(); + bundle.putInt("type", type); + fragment.setArguments(bundle); + return fragment; + } + + public void setiTaskCenterView(ITaskCenterView iTaskCenterView) { + this.iTaskCenterView = iTaskCenterView; + } + + @Override + public int getRootLayoutId() { + return R.layout.fragment_task_center; + } + + @Override + public void onFindViews() { + rvTaskList = mView.findViewById(R.id.rv_task_list); + swipeRefresh = mView.findViewById(R.id.swipe_refresh); + + rvTaskList.setLayoutManager(new LinearLayoutManager(mContext)); + rvTaskList.addItemDecoration(new HorizontalDecoration(UIUtil.dip2px(mContext, 12), true, true)); + ((SimpleItemAnimator) rvTaskList.getItemAnimator()).setSupportsChangeAnimations(false); // 禁recyclerView动画, 防止图片闪烁 + + adapter = new TaskCenterAdapter(mContext); + adapter.setHasStableIds(true); // 禁recyclerView动画, 防止图片闪烁 + adapter.setOnItemChildClickListener(new BaseQuickAdapter.OnItemChildClickListener() { + @Override + public void onItemChildClick(BaseQuickAdapter adp, View view, int position) { + if (!(view.getId() == R.id.tv_operation_status)) { + return; + } + TaskInfo info = null; + if (position < adapter.getData().size()) { + info = adapter.getData().get(position); + } + if (info == null) { + return; + } + final TaskInfo item = info; + if (!item.isSupport()) { + SingleToastUtil.showToast(ResUtil.getString(R.string.yizhuan_xchat_android_constants_xchatconstants_013)); + return; + } + if (item.getStatus() == TaskInfo.STATUS_FINISHED_NOT_RECEIVE) { + view.setClickable(false); + + new TaskModel().receivePrice(item.getConfigId(), item.getPrizeType()) + .compose(RxHelper.bindContext(mContext)) + .subscribe(new DontWarnObserver() { + @Override + public void accept(String s, String error) { + super.accept(s, error); + if (error != null) { + view.setClickable(true); + SingleToastUtil.showToast(error); + } else { + item.setStatus(TaskInfo.STATUS_HAS_RECEIVED); + adapter.notifyItemChanged(position); + //播放动画 + if (iTaskCenterView != null) + iTaskCenterView.playPriceAnim(item); + } + } + }); + + } else if (item.getStatus() == TaskInfo.STATUS_UN_FINISH) { + boolean record = false; + if (item.getSkipType() == TaskInfo.SHIP_TYPE_APP) { + boolean result = RouterHandler.handle(mContext, item.getRouterType(), item.getRouterValue()); + if (!result) { + SingleToastUtil.showToast(ResUtil.getString(R.string.yizhuan_xchat_android_constants_xchatconstants_013)); + return; + } + + record = true; + + } else if (item.getSkipType() == TaskInfo.SHIP_TYPE_TASK){ + TaskCenterDialogHelper helper = new TaskCenterDialogHelper(mContext); + helper.showDialog(item.getStepPic()); + record = true; + + } else + SingleToastUtil.showToast(ResUtil.getString(R.string.yizhuan_xchat_android_constants_xchatconstants_013)); + + if (record) { + + } + } + } + }); + + rvTaskList.setAdapter(adapter); + swipeRefresh.setOnRefreshListener(this::loadData); + } + + @Override + public void onResume() { + super.onResume(); + loadData(); + } + + @SuppressLint("CheckResult") + private void loadData() { + //noinspection ResultOfMethodCallIgnored + if (mType == TYPE_TASK) { + model.getTaskList() + .compose(bindToLifecycle()) + .subscribe((taskInfos, throwable) -> { + swipeRefresh.setRefreshing(false); + if (throwable != null) { + toast(throwable.getMessage()); + } else { + adapter.setNewData(taskInfos); + } + }); + + } else if (mType == TYPE_ACHIEVEMENT) { + model.getAchievementTaskList() + .compose(bindToLifecycle()) + .subscribe((taskInfos, throwable) -> { + swipeRefresh.setRefreshing(false); + if (throwable != null) { + toast(throwable.getMessage()); + } else { + adapter.setNewData(taskInfos); + } + }); + + } + + } + + @Override + public void onSetListener() { + + } + + private int mType = 1; + @Override + public void initiate() { + Bundle bundle = getArguments(); + if (bundle != null) + mType = bundle.getInt("type", 1); + + } +} diff --git a/app/src/main/java/com/chwl/app/radish/task/presenter/TaskCenterFrgPresenter.java b/app/src/main/java/com/chwl/app/radish/task/presenter/TaskCenterFrgPresenter.java new file mode 100644 index 0000000..15e12f6 --- /dev/null +++ b/app/src/main/java/com/chwl/app/radish/task/presenter/TaskCenterFrgPresenter.java @@ -0,0 +1,7 @@ +package com.chwl.app.radish.task.presenter; + +import com.chwl.app.base.BaseMvpPresenter; +import com.chwl.app.radish.task.view.ITaskCenterViewFrg; + +public class TaskCenterFrgPresenter extends BaseMvpPresenter { +} diff --git a/app/src/main/java/com/chwl/app/radish/task/presenter/TaskCenterPresenter.java b/app/src/main/java/com/chwl/app/radish/task/presenter/TaskCenterPresenter.java new file mode 100644 index 0000000..915de70 --- /dev/null +++ b/app/src/main/java/com/chwl/app/radish/task/presenter/TaskCenterPresenter.java @@ -0,0 +1,12 @@ +package com.chwl.app.radish.task.presenter; + +import com.chwl.app.base.BaseMvpPresenter; +import com.chwl.app.radish.task.view.ITaskCenterView; + +/** + * create by lvzebiao @2019/3/27 + */ +public class TaskCenterPresenter extends BaseMvpPresenter { + + +} diff --git a/app/src/main/java/com/chwl/app/radish/task/view/ITaskCenterView.java b/app/src/main/java/com/chwl/app/radish/task/view/ITaskCenterView.java new file mode 100644 index 0000000..b29d9b8 --- /dev/null +++ b/app/src/main/java/com/chwl/app/radish/task/view/ITaskCenterView.java @@ -0,0 +1,11 @@ +package com.chwl.app.radish.task.view; + +import com.chwl.core.radish.task.bean.TaskInfo; +import com.chwl.library.base.IMvpBaseView; + +/** + * create by lvzebiao @2019/3/27 + */ +public interface ITaskCenterView extends IMvpBaseView { + void playPriceAnim(TaskInfo info); +} diff --git a/app/src/main/java/com/chwl/app/radish/task/view/ITaskCenterViewFrg.java b/app/src/main/java/com/chwl/app/radish/task/view/ITaskCenterViewFrg.java new file mode 100644 index 0000000..103fa25 --- /dev/null +++ b/app/src/main/java/com/chwl/app/radish/task/view/ITaskCenterViewFrg.java @@ -0,0 +1,6 @@ +package com.chwl.app.radish.task.view; + +import com.chwl.library.base.IMvpBaseView; + +public interface ITaskCenterViewFrg extends IMvpBaseView { +} diff --git a/app/src/main/java/com/chwl/app/radish/view/IRadishRecordFrgView.java b/app/src/main/java/com/chwl/app/radish/view/IRadishRecordFrgView.java new file mode 100644 index 0000000..58432db --- /dev/null +++ b/app/src/main/java/com/chwl/app/radish/view/IRadishRecordFrgView.java @@ -0,0 +1,9 @@ +package com.chwl.app.radish.view; + +import com.chwl.core.bills.bean.RadishRecordListInfo; +import com.chwl.library.base.IMvpBaseView; + +public interface IRadishRecordFrgView extends IMvpBaseView { + void getRadishRecordSuccess(RadishRecordListInfo list); + void getRadishRecordFail(String message); +} diff --git a/app/src/main/java/com/chwl/app/radish/view/IRadishRecordView.java b/app/src/main/java/com/chwl/app/radish/view/IRadishRecordView.java new file mode 100644 index 0000000..881c5fc --- /dev/null +++ b/app/src/main/java/com/chwl/app/radish/view/IRadishRecordView.java @@ -0,0 +1,6 @@ +package com.chwl.app.radish.view; + +import com.chwl.library.base.IMvpBaseView; + +public interface IRadishRecordView extends IMvpBaseView { +} diff --git a/app/src/main/java/com/chwl/app/radish/wallet/RadishWalletManager.java b/app/src/main/java/com/chwl/app/radish/wallet/RadishWalletManager.java new file mode 100644 index 0000000..0cc3768 --- /dev/null +++ b/app/src/main/java/com/chwl/app/radish/wallet/RadishWalletManager.java @@ -0,0 +1,59 @@ +package com.chwl.app.radish.wallet; + +import androidx.lifecycle.LifecycleOwner; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.Observer; + +import com.chwl.core.radish.RadishModel; +import com.chwl.core.radish.RadishWalletInfo; +import com.chwl.core.radish.event.RadishWalletInfoUpdateEvent; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +/** + * 萝卜数据统一管理,与data层接通数据 + * 连接UI层显示 + * create by lvzebiao @2019/3/25 + */ +public class RadishWalletManager { + + private static final class Helper { + public static final RadishWalletManager INSTANCE = new RadishWalletManager(); + } + + private RadishWalletManager() { + EventBus.getDefault().register(this); + ldRadishWallet.setValue(new RadishWalletInfo()); + } + + public static RadishWalletManager get() { + return Helper.INSTANCE; + } + + private MutableLiveData ldRadishWallet = new MutableLiveData<>(); + + public void registerRadishNum(LifecycleOwner owner, Observer observer) { + ldRadishWallet.observe(owner, observer); + } + + public MutableLiveData getLdRadishNumber() { + return ldRadishWallet; + } + + public void updateRadishNum(long newNum) { + RadishWalletInfo info = RadishModel.get().getRadishWalletInfo(); + info.setAmount(newNum); + ldRadishWallet.setValue(info); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onRadishWalletInfoUpdateEvent(RadishWalletInfoUpdateEvent event) { + RadishWalletInfo info = RadishModel.get().getRadishWalletInfo(); + if (info != null) { + ldRadishWallet.setValue(info); + } + } + +} diff --git a/app/src/main/java/com/chwl/app/radish/widget/RadishRecordNavAdapter.java b/app/src/main/java/com/chwl/app/radish/widget/RadishRecordNavAdapter.java new file mode 100644 index 0000000..b63aa50 --- /dev/null +++ b/app/src/main/java/com/chwl/app/radish/widget/RadishRecordNavAdapter.java @@ -0,0 +1,77 @@ +package com.chwl.app.radish.widget; + +import android.content.Context; +import android.graphics.Color; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import androidx.core.content.ContextCompat; + +import com.chwl.app.R; +import com.chwl.app.decoration.view.widgets.BadgeScaleTransitionPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.CommonNavigatorAdapter; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.indicators.LinePagerIndicator; +import com.chwl.library.utils.ResUtil; + +import java.util.ArrayList; +import java.util.List; + +public class RadishRecordNavAdapter extends CommonNavigatorAdapter { + + private List mTitleList = new ArrayList<>(); + + public RadishRecordNavAdapter() { + mTitleList.add(ResUtil.getString(R.string.radish_widget_radishrecordnavadapter_01)); + mTitleList.add(ResUtil.getString(R.string.radish_widget_radishrecordnavadapter_02)); + } + + @Override + public int getCount() { + return mTitleList.size(); + } + + @Override + public IPagerTitleView getTitleView(Context context, int index) { + BadgeScaleTransitionPagerTitleView scaleTransitionPagerTitleView = new BadgeScaleTransitionPagerTitleView(context); + scaleTransitionPagerTitleView.setNormalColor(ContextCompat.getColor(context, R.color.color_B3FFFFFF)); + scaleTransitionPagerTitleView.setSelectedColor(ContextCompat.getColor(context, R.color.white)); + scaleTransitionPagerTitleView.setMinScale(1.0f); + scaleTransitionPagerTitleView.setTextSize(16); + scaleTransitionPagerTitleView.setText(mTitleList.get(index)); + + scaleTransitionPagerTitleView.setOnClickListener(view -> { + if (mOnItemSelectListener != null) { + mOnItemSelectListener.onItemSelect(index); + } + }); + return scaleTransitionPagerTitleView; + } + + @Override + public IPagerIndicator getIndicator(Context context) { + LinePagerIndicator indicator = new LinePagerIndicator(context); + indicator.setMode(LinePagerIndicator.MODE_EXACTLY); + indicator.setLineHeight(UIUtil.dip2px(context, 0)); + indicator.setRoundRadius(UIUtil.dip2px(context, 0)); + indicator.setLineWidth(UIUtil.dip2px(context, 0)); + indicator.setColors(Color.parseColor("#FF894F")); + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + //lp.bottomMargin = 0; + indicator.setLayoutParams(lp); + return indicator; + } + + + private OnItemSelectListener mOnItemSelectListener; + + public void setOnItemSelectListener(OnItemSelectListener mOnItemSelectListener) { + this.mOnItemSelectListener = mOnItemSelectListener; + } + + public interface OnItemSelectListener { + void onItemSelect(int position); + } +} diff --git a/app/src/main/java/com/chwl/app/radish/widget/TaskCenterNavAdapter.java b/app/src/main/java/com/chwl/app/radish/widget/TaskCenterNavAdapter.java new file mode 100644 index 0000000..744ee26 --- /dev/null +++ b/app/src/main/java/com/chwl/app/radish/widget/TaskCenterNavAdapter.java @@ -0,0 +1,77 @@ +package com.chwl.app.radish.widget; + +import android.content.Context; +import android.graphics.Color; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import androidx.core.content.ContextCompat; + +import com.chwl.app.R; +import com.chwl.app.decoration.view.widgets.BadgeScaleTransitionPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.CommonNavigatorAdapter; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.indicators.LinePagerIndicator; +import com.chwl.library.utils.ResUtil; + +import java.util.ArrayList; +import java.util.List; + +public class TaskCenterNavAdapter extends CommonNavigatorAdapter { + + private List mTitleList = new ArrayList<>(); + + public TaskCenterNavAdapter() { + mTitleList.add(ResUtil.getString(R.string.radish_widget_taskcenternavadapter_01)); + mTitleList.add(ResUtil.getString(R.string.radish_widget_taskcenternavadapter_02)); + } + + @Override + public int getCount() { + return mTitleList.size(); + } + + @Override + public IPagerTitleView getTitleView(Context context, int index) { + BadgeScaleTransitionPagerTitleView scaleTransitionPagerTitleView = new BadgeScaleTransitionPagerTitleView(context); + scaleTransitionPagerTitleView.setNormalColor(ContextCompat.getColor(context, R.color.color_B3FFFFFF)); + scaleTransitionPagerTitleView.setSelectedColor(ContextCompat.getColor(context, R.color.white)); + scaleTransitionPagerTitleView.setMinScale(1.0f); + scaleTransitionPagerTitleView.setTextSize(16); + scaleTransitionPagerTitleView.setText(mTitleList.get(index)); + + scaleTransitionPagerTitleView.setOnClickListener(view -> { + if (mOnItemSelectListener != null) { + mOnItemSelectListener.onItemSelect(index); + } + }); + return scaleTransitionPagerTitleView; + } + + @Override + public IPagerIndicator getIndicator(Context context) { + LinePagerIndicator indicator = new LinePagerIndicator(context); + indicator.setMode(LinePagerIndicator.MODE_EXACTLY); + indicator.setLineHeight(UIUtil.dip2px(context, 4)); + indicator.setRoundRadius(UIUtil.dip2px(context, 2)); + indicator.setLineWidth(UIUtil.dip2px(context, 17)); + indicator.setColors(Color.parseColor("#FFFFFF")); + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + //lp.bottomMargin = 0; + indicator.setLayoutParams(lp); + return indicator; + } + + + private OnItemSelectListener mOnItemSelectListener; + + public void setOnItemSelectListener(OnItemSelectListener mOnItemSelectListener) { + this.mOnItemSelectListener = mOnItemSelectListener; + } + + public interface OnItemSelectListener { + void onItemSelect(int position); + } +} diff --git a/app/src/main/java/com/chwl/app/reciever/IncomingCallReceiver.java b/app/src/main/java/com/chwl/app/reciever/IncomingCallReceiver.java new file mode 100644 index 0000000..3628f93 --- /dev/null +++ b/app/src/main/java/com/chwl/app/reciever/IncomingCallReceiver.java @@ -0,0 +1,23 @@ +package com.chwl.app.reciever; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.telephony.TelephonyManager; + +import com.chwl.core.im.state.PhoneCallStateModel; + +/** + * Created by zhouxiangfeng on 2017/5/31. + */ + +public class IncomingCallReceiver extends BroadcastReceiver{ + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action)) { + final String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE); + PhoneCallStateModel.get().callStateChanged(state); + } + } +} diff --git a/app/src/main/java/com/chwl/app/reciever/NotificationClickReceiver.java b/app/src/main/java/com/chwl/app/reciever/NotificationClickReceiver.java new file mode 100644 index 0000000..9042075 --- /dev/null +++ b/app/src/main/java/com/chwl/app/reciever/NotificationClickReceiver.java @@ -0,0 +1,24 @@ +package com.chwl.app.reciever; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +import com.chwl.app.avroom.activity.AVRoomActivity; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.room.bean.RoomInfo; + +/** + * Created by chenran on 2017/11/16. + */ + +public class NotificationClickReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + //TODO 跳转之前要处理的逻辑 + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo != null) { + AVRoomActivity.start(context, roomInfo.getUid()); + } + } +} diff --git a/app/src/main/java/com/chwl/app/reciever/OnePixelReceiver.java b/app/src/main/java/com/chwl/app/reciever/OnePixelReceiver.java new file mode 100644 index 0000000..9bfeca7 --- /dev/null +++ b/app/src/main/java/com/chwl/app/reciever/OnePixelReceiver.java @@ -0,0 +1,33 @@ +package com.chwl.app.reciever; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +import com.chwl.app.ui.keepalive.OnePiexlActivity; + +/** + * + * @author chenran + * @date 2017/11/16 + */ + +public class OnePixelReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + + if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) { + //屏幕关闭启动1像素Activity + Intent it = new Intent(context, OnePiexlActivity.class); + it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(it); + } else if (Intent.ACTION_SCREEN_ON.equals(intent.getAction())) { + //屏幕打开 结束1像素 + context.sendBroadcast(new Intent("finish")); + Intent main = new Intent(Intent.ACTION_MAIN); + main.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + main.addCategory(Intent.CATEGORY_HOME); + context.startActivity(main); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/relation/cp/CpDataManager.java b/app/src/main/java/com/chwl/app/relation/cp/CpDataManager.java new file mode 100644 index 0000000..f62603f --- /dev/null +++ b/app/src/main/java/com/chwl/app/relation/cp/CpDataManager.java @@ -0,0 +1,30 @@ +package com.chwl.app.relation.cp; + + +import com.chwl.core.relation.cp.bean.CpInviteInfo; + +public class CpDataManager { + + public static class Holder { + private static final CpDataManager INSTANCE = new CpDataManager(); + } + + public static CpDataManager get() { + return CpDataManager.Holder.INSTANCE; + } + + private CpInviteInfo cpInviteInfo; + + public CpInviteInfo getCpInviteInfo() { + return cpInviteInfo; + } + + public void setCpInviteInfo(CpInviteInfo cpInviteInfo) { + this.cpInviteInfo = cpInviteInfo; + } + + + public void clearCpInviteInfo() { + setCpInviteInfo(null); + } +} diff --git a/app/src/main/java/com/chwl/app/relation/cp/CpDataParser.kt b/app/src/main/java/com/chwl/app/relation/cp/CpDataParser.kt new file mode 100644 index 0000000..96e6fbd --- /dev/null +++ b/app/src/main/java/com/chwl/app/relation/cp/CpDataParser.kt @@ -0,0 +1,51 @@ +package com.chwl.app.relation.cp + +import com.chwl.core.relation.cp.bean.CpInviteDetailEntity +import com.chwl.core.relation.cp.bean.CpInviteInfo + +object CpDataParser { + fun inviteMsg2cpDetailEntity(msgEntity: CpInviteInfo) = CpInviteDetailEntity( + msgEntity.acceptAvatar, + msgEntity.acceptGender, + msgEntity.acceptNick, + msgEntity.acceptUid, + msgEntity.cpId, + msgEntity.declaration, + msgEntity.inviteAvatar, + msgEntity.inviteGender, + msgEntity.inviteNick, + msgEntity.inviteUid, + msgEntity.propsId, + msgEntity.propsImg, + msgEntity.propsName, + msgEntity.propsPrice, + msgEntity.recommenTxtList, + msgEntity.replyExpireTime + ) + + /** + * data class CpInviteDetailEntity( + * + val acceptAvatar: String? = "", + val acceptGender: Int = 1, + val acceptNick: String = "", + val acceptUid: Long = 0, + + val cpId: Int = 0, + val declaration: String = "", + + val inviteAvatar: String? = null, + val inviteGender: Int = 1, + val inviteNick: String = "", + val inviteUid: Long = 0, + + val propsId: Int = 0, + val propsImg: String = "", + val propsName: String = "", + val propsPrice: Double = 0.0, + val recommenTxtList: List? = null, + val replyExpireTime: Int = 0 + ) + */ +} + diff --git a/app/src/main/java/com/chwl/app/relation/cp/CpViewHelper.kt b/app/src/main/java/com/chwl/app/relation/cp/CpViewHelper.kt new file mode 100644 index 0000000..f585ebd --- /dev/null +++ b/app/src/main/java/com/chwl/app/relation/cp/CpViewHelper.kt @@ -0,0 +1,111 @@ +package com.chwl.app.relation.cp + +import android.content.Context +import android.graphics.Color +import android.text.SpannableStringBuilder +import android.text.style.AbsoluteSizeSpan +import android.text.style.ForegroundColorSpan +import android.widget.TextView +import androidx.annotation.ColorInt +import com.netease.nim.uikit.common.util.sys.ScreenUtil +import com.chwl.app.R +import com.chwl.app.common.widget.dialog.DialogManager + +object CpViewHelper { + + fun setInviteGiftPriceStyle(context: Context, proName: String, price: String, tv: TextView) { + val absoluteSizeSpan13 = AbsoluteSizeSpan(ScreenUtil.dip2px(13f)) + val absoluteSizeSpan10 = AbsoluteSizeSpan(ScreenUtil.dip2px(10f)) + val stringBuilder = StringBuilder() + stringBuilder.append(proName).append("\n").append( + String.format( + context.resources.getString(R.string.invite_gift_price_text), price + ) + ) + val builder = + SpannableStringBuilder(stringBuilder.toString()) + builder.setSpan( + absoluteSizeSpan13, + 0, + 3, + SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE + ) + + builder.setSpan( + absoluteSizeSpan10, + 4, + builder.length, + SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE + ) + tv.text = builder + } + + fun setInviteTimeRemain(time: String, tv: TextView) { + val s = "請在${time}內決定,過期自動失效!" + tv.text = getColorSpan(s, Color.parseColor("#FB466A"), 2, time.length + 2) + } + + fun getColorSpan( + text: String, + @ColorInt color: Int, + start: Int, + end: Int + ): SpannableStringBuilder { + var builder = SpannableStringBuilder(text) + builder = getColorSpan(builder, color, start, end) + return builder + } + + + fun getColorSpan( + text: SpannableStringBuilder, + @ColorInt color: Int, + start: Int, + end: Int + ): SpannableStringBuilder { + val colorSpan = ForegroundColorSpan(color) + text.setSpan( + colorSpan, + start, + end, + SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE + ) + return text + } + + + fun getSizeSpan(text: String, size: Float, start: Int, end: Int): SpannableStringBuilder { + var builder = SpannableStringBuilder(text) + builder = getSizeSpan(builder, size, start, end) + return builder + } + + fun getSizeSpan(text: SpannableStringBuilder, size: Float, start: Int, end: Int) = + SpannableStringBuilder(text).apply { + val sizeSpan = AbsoluteSizeSpan(ScreenUtil.dip2px(size)) + setSpan( + sizeSpan, + start, + end, + SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE + ) + } + + + fun showInviteTipDialog( + context: Context, + title: String, + message: String, + listener: DialogManager.OkCancelDialogListener + ) { + val builder = getColorSpan(message, Color.parseColor("#999999"), 0, message.length) + val sizeSpan = AbsoluteSizeSpan(ScreenUtil.dip2px(13f)) + builder.setSpan( + sizeSpan, + 0, + message.length, + SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE + ) + DialogManager(context).showOkCancelDialog(title, builder, "確定", "取消", true, listener) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/relation/cp/activity/CpHomeActivity.kt b/app/src/main/java/com/chwl/app/relation/cp/activity/CpHomeActivity.kt new file mode 100644 index 0000000..cadb985 --- /dev/null +++ b/app/src/main/java/com/chwl/app/relation/cp/activity/CpHomeActivity.kt @@ -0,0 +1,122 @@ +package com.chwl.app.relation.cp.activity + +import android.content.Context +import android.content.Intent +import android.graphics.Color +import android.view.View +import androidx.activity.viewModels +import com.netease.nim.uikit.StatusBarUtil +import com.chwl.app.R +import com.chwl.app.base.BaseBindingActivity +import com.chwl.app.base.TitleBar +import com.chwl.app.databinding.ActivityCpHomeBinding +import com.chwl.app.relation.cp.viewmodel.CpViewModel +import com.chwl.app.relation.cp.widget.RelationCpCardView.Companion.PAGE_TYPE_SELF_CP +import com.chwl.app.ui.relation.FansListActivity +import com.chwl.app.ui.user.activity.UserInfoActivity +import com.chwl.core.auth.AuthModel +import com.chwl.core.relation.cp.CpBindUnbindEvent +import com.chwl.library.annatation.ActLayoutRes +import com.chwl.library.utils.ResUtil +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode + +@ActLayoutRes(R.layout.activity_cp_home) +class CpHomeActivity : BaseBindingActivity() { + private val mUserId = AuthModel.get().currentUid + private var hasAddedTitle = false + private val vm: CpViewModel by viewModels() + override fun init() { + initTitleBar(ResUtil.getString(R.string.cp_activity_cphomeactivity_01)) + mBinding.cpCardView.setClick(this) + initObserver() + vm.getCpRelation(mUserId) + } + + override fun onClick(v: View) { + when (v.id) { + R.id.mine_avatar -> { + toUserInfoActivity(vm.cpRelation.value?.uid) + } + R.id.other_avatar -> { + if (vm.cpRelation.value?.cpUid ?: 0L == 0L) { + FansListActivity.start(this, FansListActivity.TYPE_CP) + } else { + toUserInfoActivity(vm.cpRelation.value?.cpUid) + } + } + R.id.tv_recovery_unbind -> { + dialogManager.showOkCancelWithTitleDialog( + resources.getString(R.string.cp_revert_tip) + ) { + vm.revertUnbindCp() + } + } + R.id.iv_unbind -> { + dialogManager.showOkCancelWithTitleDialog( + resources.getString(R.string.cp_unbind_tip) + ) { + vm.unBindCp() + } + } + } + } + + private fun initObserver() { + EventBus.getDefault().register(this) + vm.loadingLiveData.observe(this) { + if (it) dialogManager.showProgressDialog(this) + else dialogManager.dismissDialog() + } + + vm.cpRelation.observe(this) { + mBinding.cpCardView.setCpEntityData(mUserId, PAGE_TYPE_SELF_CP, it) + if (it.cpUid != 0L) { + initRightTitle() + } + } + } + + private fun initRightTitle() { + if (hasAddedTitle) return + hasAddedTitle = true + mTitleBar.addAction(object : TitleBar.TextAction( + ResUtil.getString(R.string.cp_activity_cphomeactivity_02), Color.parseColor("#4C5AF1") + ) { + override fun performAction(view: View) { + start(CpTaskActivity::class.java) + } + }) + } + + + private fun toUserInfoActivity(uid: Long?) { + uid?.let { UserInfoActivity.Companion.start(this, it) } + } + + companion object { + fun start(context: Context) { + val intent = Intent(context, CpHomeActivity::class.java) + context.startActivity(intent) + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onRelationChange(event: CpBindUnbindEvent) { + vm.getCpRelation(mUserId) + } + + override fun onDestroy() { + super.onDestroy() + EventBus.getDefault().unregister(this) + } + + + override fun needSteepStateBar() = true + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/relation/cp/activity/CpInviteRecordActivity.kt b/app/src/main/java/com/chwl/app/relation/cp/activity/CpInviteRecordActivity.kt new file mode 100644 index 0000000..574359a --- /dev/null +++ b/app/src/main/java/com/chwl/app/relation/cp/activity/CpInviteRecordActivity.kt @@ -0,0 +1,149 @@ +package com.chwl.app.relation.cp.activity + +import android.content.Context +import android.content.Intent +import android.graphics.Color +import androidx.activity.viewModels +import androidx.recyclerview.widget.LinearLayoutManager +import com.netease.nim.uikit.StatusBarUtil +import com.chwl.app.R +import com.chwl.app.base.BaseBindingActivity +import com.chwl.app.common.EmptyViewHelper +import com.chwl.app.databinding.ActivityCpInviteRecordBinding +import com.chwl.app.relation.cp.CpDataManager +import com.chwl.app.relation.cp.CpViewHelper +import com.chwl.app.relation.cp.adapter.InviteRecordAdapter +import com.chwl.app.relation.cp.dialog.CpInviteReplyConfirmDialog +import com.chwl.app.relation.cp.dialog.CpInviteReplyDialog +import com.chwl.app.relation.cp.viewmodel.CpViewModel +import com.chwl.app.ui.widget.dialog.CommonTipDialog +import com.chwl.core.relation.cp.CpBindUnbindEvent +import com.chwl.core.relation.cp.bean.CpInviteDetailEntity +import com.chwl.core.relation.cp.bean.UserCpListEntity +import com.chwl.library.annatation.ActLayoutRes +import com.chwl.library.utils.ResUtil +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode + +@ActLayoutRes(R.layout.activity_cp_invite_record) +class CpInviteRecordActivity : BaseBindingActivity() { + private val vm: CpViewModel by viewModels() + private lateinit var adapter: InviteRecordAdapter + private val type = 1// 1-別人給我發的邀請,2-我給別人發的邀請 + + override fun init() { + initTitleBar(ResUtil.getString(R.string.cp_activity_cpinviterecordactivity_01)) + initRecyclerView() + initObserver() + queryRecord(type) + } + + private fun initObserver() { + EventBus.getDefault().register(this) + vm.userCpListData.observe(this) { + adapter.setNewData(it) + } + + vm.loadingLiveData.observe(this) { + if (it) dialogManager.showProgressDialog(this) + else dialogManager.dismissDialog() + if (mBinding.swipeRefresh.isRefreshing) { + mBinding.swipeRefresh.isRefreshing = false + } + } + vm.cpInviteDetailData.observe(this) { + showReplyDialog(it) + } + } + + private fun showReplyDialog(item: CpInviteDetailEntity) { + CpInviteReplyDialog(context).apply { + cpInviteData = item + listener = object : CpInviteReplyDialog.ReplyListener { + override fun onAgree() { + showConfirmDialog(item, true) + } + + override fun onRefuse() { + showConfirmDialog(item, false) + } + + override fun onTimeOut() { + queryRecord(type) + } + } + openDialog() + } + } + + private fun initRecyclerView() { + adapter = InviteRecordAdapter(this) + adapter.onVisitClickListener = object : InviteRecordAdapter.OnVisitClickListener { + override fun onVisitClick(item: UserCpListEntity) { + vm.getCpInviteDetail(item.cpId) + } + } + val layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false) + mBinding.recyclerView.layoutManager = layoutManager + adapter.emptyView = EmptyViewHelper.createEmptyTextView(this, ResUtil.getString(R.string.cp_activity_cpinviterecordactivity_02)) + adapter.bindToRecyclerView(mBinding.recyclerView) + mBinding.swipeRefresh.setOnRefreshListener { + queryRecord(type) + } + } + + private fun queryRecord(type: Int) { + vm.getUserCpListData(type) + } + + companion object { + fun start(context: Context, needAlert: Boolean) { + val intent = Intent(context, CpInviteRecordActivity::class.java) + intent.putExtra("needAlert", needAlert) + context.startActivity(intent) + } + } + + private fun showConfirmDialog(item: CpInviteDetailEntity, isAgree: Boolean) { + val shb = CpViewHelper.getColorSpan( + "是否${if (isAgree) "同意" else "拒絕"}與${item.inviteNick}成為CP?\n", + Color.parseColor("#4C5AF1"), + 5, 5 + item.inviteNick.length + ) + if (isAgree) { + val str = "(同意將自動拒絕其他邀請)" + val append = CpViewHelper.getSizeSpan(str, 12f, 0, str.length) + shb.append(append) + } + + CpInviteReplyConfirmDialog(context).apply { + setDialogTitle(shb) + okCancelListener = object : CommonTipDialog.OnActionListener { + override fun onOk() { + vm.replyInvite(item.cpId, if (isAgree) 2 else 3) + } + } + openDialog() + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onBindUnbindEvent(event: CpBindUnbindEvent) { + queryRecord(type) + } + + override fun onDestroy() { + super.onDestroy() + EventBus.getDefault().unregister(this) + CpDataManager.get().clearCpInviteInfo() + } + + + override fun needSteepStateBar() = true + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/relation/cp/activity/CpTaskActivity.kt b/app/src/main/java/com/chwl/app/relation/cp/activity/CpTaskActivity.kt new file mode 100644 index 0000000..d80d2e1 --- /dev/null +++ b/app/src/main/java/com/chwl/app/relation/cp/activity/CpTaskActivity.kt @@ -0,0 +1,152 @@ +package com.chwl.app.relation.cp.activity + +import android.content.Context +import android.content.Intent +import android.view.View +import android.widget.TextView +import androidx.activity.viewModels +import com.netease.nim.uikit.StatusBarUtil +import com.netease.nim.uikit.common.util.sys.ScreenUtil +import com.chwl.app.R +import com.chwl.app.base.BaseBindingActivity +import com.chwl.app.databinding.ActivityCpTaskBinding +import com.chwl.app.relation.cp.adapter.CpTaskIndicatorAdapter +import com.chwl.app.relation.cp.adapter.TaskPagerAdapter +import com.chwl.app.relation.cp.fragment.CpTaskFragment +import com.chwl.app.relation.cp.viewmodel.CpViewModel +import com.chwl.app.relation.cp.widget.CpTaskDescriptionView +import com.chwl.app.relation.extention.visibility +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.app.ui.utils.ImageLoadUtilsV2 +import com.chwl.app.ui.widget.OnPageSelectedListener +import com.chwl.app.ui.widget.magicindicator.ViewPagerHelper +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.CommonNavigator +import com.chwl.core.auth.AuthModel +import com.chwl.core.relation.cp.bean.CpTaskEntity +import com.chwl.library.annatation.ActLayoutRes +import com.chwl.library.utils.ResUtil + +@ActLayoutRes(R.layout.activity_cp_task) +class CpTaskActivity : BaseBindingActivity(), + CpTaskIndicatorAdapter.OnItemSelectListener { + private val vm: CpViewModel by viewModels() + private val pagerAdapter: TaskPagerAdapter by lazy { + val list = ArrayList(2) + list.add(CpTaskFragment.newInstance(CpTaskFragment.TYPE_DAILY)) + list.add(CpTaskFragment.newInstance(CpTaskFragment.TYPE_TOTAL)) + TaskPagerAdapter(supportFragmentManager, list) + } + + override fun init() { + initTitleBar(ResUtil.getString(R.string.cp_activity_cptaskactivity_01)) + vm.loadingLiveData.observe(this) { + if (it) dialogManager.showProgressDialog(this) + else dialogManager.dismissDialog() + } + vm.cpTaskData.observe(this) { + setTaskProgress(it) + } + vm.cpTaskProcess(AuthModel.get().currentUid) + setViewPager() + setCpLevelDesc() + } + + private fun setTaskProgress(entity: CpTaskEntity) { + ImageLoadUtils.loadAvatar( entity.cpAvatar,mBinding.ivAccept) + ImageLoadUtils.loadAvatar(entity.avatar,mBinding.ivInvite) + mBinding.tvLevel.text = + String.format(resources.getString(R.string.cp_level, entity.cpLevel.toString())) + val progress = ((entity.cpSecretVal.toFloat() / entity.cpNextLevelSecretVal) * 100).toInt() + mBinding.progressBar.progress = progress + mBinding.tvProgress.text = "${entity.cpSecretVal}/${entity.cpNextLevelSecretVal}" + mBinding.tvProgress.measure(0, 0) + val pRight = ScreenUtil.dip2px(5f) + val pLeft = ScreenUtil.dip2px(5f) + val tvWidth = mBinding.tvProgress.measuredWidth + val pbWidth = mBinding.progressBar.width + var left = (pbWidth * (progress * 1f / 100)).toInt() - pRight - tvWidth + if (left < 0) { + left = pLeft + } + mBinding.tvProgress.translationX = left.toFloat() + mBinding.ivDropDown.visibility = entity.isDamp.visibility() + } + + private fun setViewPager() { + val list = ArrayList(2) + list.add(ResUtil.getString(R.string.cp_activity_cptaskactivity_02)) + list.add(ResUtil.getString(R.string.cp_activity_cptaskactivity_03)) + + val commonNavigator = CommonNavigator(this) + commonNavigator.isAdjustMode = true + val indicator = CpTaskIndicatorAdapter(list) + indicator.setOnItemSelectListener(this) + commonNavigator.adapter = indicator + mBinding.indicator.navigator = commonNavigator + mBinding.viewPager.adapter = pagerAdapter + mBinding.viewPager.addOnPageChangeListener(object : OnPageSelectedListener() { + override fun onPageSelected(position: Int) { + mBinding.viewPager.requestLayout() + } + }) + ViewPagerHelper.bind(mBinding.indicator, mBinding.viewPager) + } + + /** + * 设置亲密度简介 + */ + private fun setCpLevelDesc() { + val titles = resources.getStringArray(R.array.cp_task_title) + val contents = resources.getStringArray(R.array.cp_task_content) + val intimacyTitles = resources.getStringArray(R.array.cp_task_intimacy_title) + val intimacyContents = resources.getStringArray(R.array.cp_task_intimacy_content) + val privilegeTitles = resources.getStringArray(R.array.cp_task_privilege_title) + val privilegeContents = resources.getStringArray(R.array.cp_task_privilege_content) + for (i in titles.indices) { + val itemView = layoutInflater.inflate( + R.layout.layout_cp_task_introduce, + null, false + ) + itemView.findViewById(R.id.tv_cp_level_title).text = titles[i] + itemView.findViewById(R.id.tv_cp_level_content).text = contents[i] + val cpDescView = itemView.findViewById(R.id.taskView) + when (i) { + 2 -> { + cpDescView.setTaskData( + ResUtil.getString(R.string.cp_activity_cptaskactivity_04), ResUtil.getString(R.string.cp_activity_cptaskactivity_05), CpTaskDescriptionView.TaskEntity.toTaskList( + intimacyTitles, intimacyContents + ) + ) + cpDescView.visibility = View.VISIBLE + } + 3 -> { + cpDescView.setTaskData( + ResUtil.getString(R.string.cp_activity_cptaskactivity_06), ResUtil.getString(R.string.cp_activity_cptaskactivity_07), CpTaskDescriptionView.TaskEntity.toTaskList( + privilegeTitles, privilegeContents + ) + ) + cpDescView.visibility = View.VISIBLE + } + } + mBinding.llCpLevelContent.addView(itemView) + } + } + + override fun onItemSelect(position: Int) { + mBinding.viewPager.currentItem = position + } + + companion object { + fun start(context: Context) { + context.startActivity(Intent(context, CpTaskActivity::class.java)) + } + } + + + override fun needSteepStateBar() = true + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/relation/cp/adapter/CpTaskAdapter.kt b/app/src/main/java/com/chwl/app/relation/cp/adapter/CpTaskAdapter.kt new file mode 100644 index 0000000..b18ec73 --- /dev/null +++ b/app/src/main/java/com/chwl/app/relation/cp/adapter/CpTaskAdapter.kt @@ -0,0 +1,20 @@ +package com.chwl.app.relation.cp.adapter + +import android.widget.TextView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.core.relation.cp.bean.Task +import com.chwl.library.utils.ResUtil + +class CpTaskAdapter : BaseQuickAdapter(R.layout.item_cp_task) { + override fun convert(helper: BaseViewHolder, item: Task?) { + item?.let { + helper.setText(R.id.tv_task_title, it.taskDesc) + helper.setText(R.id.tv_task_desc, it.taskSecretDesc) + helper.setText(R.id.tv_task_completed, "${it.currentVal}/${it.taskNeedVal}") + helper.setText(R.id.tv_task_status, if (it.isComplete) ResUtil.getString(R.string.cp_adapter_cptaskadapter_01) else ResUtil.getString(R.string.cp_adapter_cptaskadapter_02)) + helper.getView(R.id.tv_task_status).isEnabled = it.isComplete + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/relation/cp/adapter/CpTaskIndicatorAdapter.java b/app/src/main/java/com/chwl/app/relation/cp/adapter/CpTaskIndicatorAdapter.java new file mode 100644 index 0000000..6755165 --- /dev/null +++ b/app/src/main/java/com/chwl/app/relation/cp/adapter/CpTaskIndicatorAdapter.java @@ -0,0 +1,97 @@ +package com.chwl.app.relation.cp.adapter; + +import android.content.Context; +import android.view.LayoutInflater; +import android.widget.FrameLayout; +import android.widget.TextView; + +import androidx.core.content.ContextCompat; + +import com.chwl.app.R; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.CommonNavigatorAdapter; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerTitleView; + +import java.util.List; + + +/** + * @author jack + * @Description + * @Date 2018/11/1 + */ +public class CpTaskIndicatorAdapter extends CommonNavigatorAdapter { + private List mTitleList; + + public CpTaskIndicatorAdapter(List mTitleList) { + this.mTitleList = mTitleList; + } + + @Override + public int getCount() { + return mTitleList == null ? 0 : mTitleList.size(); + } + + @Override + public IPagerTitleView getTitleView(Context context, int index) { + PagerTitleView categoryPagerTitleView = new PagerTitleView(context, mTitleList.get(index)); + categoryPagerTitleView.setOnClickListener(v -> { + if (null != mOnItemSelectListener) { + mOnItemSelectListener.onItemSelect(index); + } + }); + return categoryPagerTitleView; + } + + @Override + public IPagerIndicator getIndicator(Context context) { + return null; + } + + private OnItemSelectListener mOnItemSelectListener; + + public void setOnItemSelectListener(OnItemSelectListener onItemSelectListener) { + mOnItemSelectListener = onItemSelectListener; + } + + public interface OnItemSelectListener { + void onItemSelect(int position); + } + + class PagerTitleView extends FrameLayout implements IPagerTitleView { + + + public PagerTitleView(Context context, String tabInfo) { + super(context); + LayoutInflater.from(context).inflate(R.layout.layout_cp_task_indicator,this,true); + ((TextView) getChildAt(0)).setText(tabInfo); + } + + + @Override + public void onSelected(int index, int totalCount) { + TextView tv = (TextView) getChildAt(0); + tv.setBackground(ContextCompat.getDrawable(getContext(), R.drawable.bg_cp_task_label_selected)); + tv.setTextColor(getResources().getColor(R.color.white)); + } + + @Override + public void onDeselected(int index, int totalCount) { + TextView tv = (TextView) getChildAt(0); + tv.setBackground(null); + tv.setTextColor(getResources().getColor(R.color.color_999999)); + } + + @Override + public void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight) { + + } + + @Override + public void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight) { + + } + } + + +} diff --git a/app/src/main/java/com/chwl/app/relation/cp/adapter/DeclarationRecommondAdapter.kt b/app/src/main/java/com/chwl/app/relation/cp/adapter/DeclarationRecommondAdapter.kt new file mode 100644 index 0000000..aedf516 --- /dev/null +++ b/app/src/main/java/com/chwl/app/relation/cp/adapter/DeclarationRecommondAdapter.kt @@ -0,0 +1,12 @@ +package com.chwl.app.relation.cp.adapter + +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R + +class DeclarationRecommendAdapter : + BaseQuickAdapter(R.layout.item_cp_declaration_recommend) { + override fun convert(helper: BaseViewHolder, item: String?) { + helper.setText(R.id.tv_recommend,item) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/relation/cp/adapter/InviteRecordAdapter.kt b/app/src/main/java/com/chwl/app/relation/cp/adapter/InviteRecordAdapter.kt new file mode 100644 index 0000000..9745e90 --- /dev/null +++ b/app/src/main/java/com/chwl/app/relation/cp/adapter/InviteRecordAdapter.kt @@ -0,0 +1,52 @@ +package com.chwl.app.relation.cp.adapter + +import android.content.Context +import android.widget.ImageView +import android.widget.TextView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.app.ui.utils.ImageLoadUtilsV2 +import com.chwl.core.relation.cp.bean.UserCpListEntity + + +class InviteRecordAdapter(private val context: Context) : + BaseQuickAdapter( + R.layout.item_cp_invite_record + ) { + var onVisitClickListener: OnVisitClickListener? = null + override fun convert(helper: BaseViewHolder, item: UserCpListEntity?) { + item?.inviteUserAvatar?.let { + val imageView = helper + .getView(R.id.iv_avatar) + ImageLoadUtils.loadAvatar(it,imageView) + } + item?.inviteUserNick.let { + val tvName = helper.getView(R.id.tv_name) + tvName.text = it + } + + val tvVisit = helper.getView(R.id.tv_visit) + item?.state?.let { + when (it) { + 1 -> tvVisit.text = context.resources.getString(R.string.invite_cp_state_visit) + 2 -> tvVisit.text = context.resources.getString(R.string.invite_cp_state_agreed) + 3 -> tvVisit.text = context.resources.getString(R.string.invite_cp_state_refused) + 4 -> tvVisit.text = context.resources.getString(R.string.invite_cp_state_unbinding) + 5 -> tvVisit.text = context.resources.getString(R.string.invite_cp_state_unbound) + 6 -> tvVisit.text = context.resources.getString(R.string.invite_cp_state_invalid) + } + tvVisit.isEnabled = it == 1 + } + tvVisit.setOnClickListener { + if (item != null) { + onVisitClickListener?.onVisitClick(item) + } + } + } + + interface OnVisitClickListener { + fun onVisitClick(item: UserCpListEntity) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/relation/cp/adapter/TaskPagerAdapter.kt b/app/src/main/java/com/chwl/app/relation/cp/adapter/TaskPagerAdapter.kt new file mode 100644 index 0000000..c82756b --- /dev/null +++ b/app/src/main/java/com/chwl/app/relation/cp/adapter/TaskPagerAdapter.kt @@ -0,0 +1,13 @@ +package com.chwl.app.relation.cp.adapter + +import android.annotation.SuppressLint +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentStatePagerAdapter +import com.chwl.app.base.BaseFragment + +@SuppressLint("WrongConstant") +class TaskPagerAdapter(fm: FragmentManager, private val list: List) : + FragmentStatePagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { + override fun getCount() = list.size + override fun getItem(position: Int) = list[position] +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/relation/cp/dialog/CpGlobalDialog.kt b/app/src/main/java/com/chwl/app/relation/cp/dialog/CpGlobalDialog.kt new file mode 100644 index 0000000..d6c5fd1 --- /dev/null +++ b/app/src/main/java/com/chwl/app/relation/cp/dialog/CpGlobalDialog.kt @@ -0,0 +1,112 @@ +package com.chwl.app.relation.cp.dialog + +import android.content.Context +import android.view.Gravity +import android.view.View +import android.view.WindowManager +import com.netease.nim.uikit.common.util.sys.ScreenUtil +import com.chwl.app.R +import com.chwl.app.databinding.DialogCpGlobalBinding +import com.chwl.app.relation.cp.CpDataManager +import com.chwl.app.relation.cp.activity.CpInviteRecordActivity +import com.chwl.app.base.BaseBindingDialog +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.app.ui.utils.ImageLoadUtilsV2 +import com.chwl.core.relation.cp.bean.CpInviteInfo +import com.chwl.library.annatation.ActLayoutRes +import io.reactivex.Observable +import io.reactivex.Observer +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.disposables.Disposable +import io.reactivex.schedulers.Schedulers +import java.util.concurrent.TimeUnit + +@ActLayoutRes(R.layout.dialog_cp_global) +class CpGlobalDialog(context: Context) : + View.OnClickListener, + BaseBindingDialog(context) { + private var entity: CpInviteInfo? = null + private val disposeSet: CompositeDisposable by lazy { + CompositeDisposable() + } + + override fun init() { + binding.ivClose.setOnClickListener(this) + binding.tvVisit.setOnClickListener(this) + setCancelable(false) + entity?.let { + ImageLoadUtils.loadAvatar(entity?.inviteAvatar, binding.ivAvatar ) + binding.tvNick.text = it.inviteNick + } + } + + override fun onStart() { + super.onStart() + window?.let { + it.attributes?.let { attr -> + attr.y = ScreenUtil.getStatusBarHeight(context) + attr.width = WindowManager.LayoutParams.MATCH_PARENT + attr.dimAmount = 0f + attr.height = ScreenUtil.dip2px(80f) + attr.gravity = Gravity.TOP + it.attributes = attr + } + } + } + + override fun onClick(v: View) { + when (v.id) { + R.id.iv_close -> { + closeDialog() + } + R.id.tv_visit -> { + CpDataManager.get().cpInviteInfo = entity + CpInviteRecordActivity.start(context, true) + } + } + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + Observable.interval(1000, TimeUnit.MILLISECONDS) + .subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : Observer { + override fun onSubscribe(d: Disposable) { + disposeSet.add(d) + } + + override fun onNext(t: Long) { + binding.tvSec.text = "${5L - t}s" + if (t == 5L) { + unregisterTimer() + closeDialog() + } + } + + override fun onError(e: Throwable) {} + override fun onComplete() {} + } + ) + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + unregisterTimer() + } + + private fun unregisterTimer() { + if (!disposeSet.isDisposed) { + disposeSet.dispose() + } + } + + companion object { + @JvmStatic + fun newInstance(entity: CpInviteInfo, context: Context): CpGlobalDialog = + CpGlobalDialog(context).apply { + this.entity = entity + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/relation/cp/dialog/CpInvitePageDialog.kt b/app/src/main/java/com/chwl/app/relation/cp/dialog/CpInvitePageDialog.kt new file mode 100644 index 0000000..b87bce5 --- /dev/null +++ b/app/src/main/java/com/chwl/app/relation/cp/dialog/CpInvitePageDialog.kt @@ -0,0 +1,92 @@ +package com.chwl.app.relation.cp.dialog + +import android.content.Context +import android.graphics.Color +import android.text.style.AbsoluteSizeSpan +import android.view.View +import com.netease.nim.uikit.common.util.sys.ScreenUtil +import com.chwl.app.R +import com.chwl.app.databinding.DialogCpInviteBinding +import com.chwl.app.relation.cp.CpViewHelper +import com.chwl.app.relation.cp.adapter.DeclarationRecommendAdapter +import com.chwl.app.base.BaseBindingDialog +import com.chwl.app.ui.utils.ImageLoadUtilsV2 +import com.chwl.app.ui.widget.LinearLayoutManagerWrapper +import com.chwl.core.relation.cp.bean.CpInvitePageEntity +import com.chwl.library.annatation.ActLayoutRes +import com.chwl.library.utils.ScreenUtils + +@ActLayoutRes(R.layout.dialog_cp_invite) +class CpInvitePageDialog(context: Context) : View.OnClickListener, + BaseBindingDialog(context) { + var listener: DialogClickListener? = null + var invitePageEntity: CpInvitePageEntity? = null + private val adapter = DeclarationRecommendAdapter() + override fun init() { + width = (ScreenUtils.getScreenWidth(context) * 0.95).toInt() + height = (ScreenUtils.getScreenHeight(context) * 0.85).toInt() + invitePageEntity?.let { + binding.cpCard.setInviteDialogPageData(invitePageEntity) + ImageLoadUtilsV2.loadImage(binding.ivGift, it.propsImg) + } + val layoutManager = LinearLayoutManagerWrapper(context) + binding.rvRecommend.layoutManager = layoutManager + adapter.bindToRecyclerView(binding.rvRecommend) + adapter.setOnItemClickListener { _, _, position -> + adapter.getItem(position)?.let { + binding.editDeclaration.setText(it) + } + } + invitePageEntity?.recommenTxtList?.let { + adapter.setNewData(it) + } + initSpannable() + binding.tvSend.setOnClickListener(this) + binding.ivClose.setOnClickListener(this) + } + + private fun initSpannable() { + val absoluteSizeSpan10 = AbsoluteSizeSpan(ScreenUtil.dip2px(10f)) + val absoluteSizeSpan8 = AbsoluteSizeSpan(ScreenUtil.dip2px(8f)) + + binding.editDeclaration.apply { + var builder = CpViewHelper.getSizeSpan( + context.resources.getString(R.string.invite_declaration_hint), + 10f, 0, + 14 + ) + builder = CpViewHelper.getSizeSpan(builder, 8f, 15, builder.length) + builder = + CpViewHelper.getColorSpan(builder, Color.parseColor("#603BED"), 0, 14) + builder = + CpViewHelper.getColorSpan(builder, Color.parseColor("#6D79F4"), 15, builder.length) + hint = builder + } + + invitePageEntity?.let { + CpViewHelper.setInviteGiftPriceStyle( + context, + it.propsName, + it.propsPrice.toInt().toString(), + binding.tvPrice + ) + } + } + + + override fun onClick(v: View) { + when (v.id) { + R.id.tv_send -> { + if (invitePageEntity == null) return + listener?.onSentClick(invitePageEntity!!, binding.editDeclaration.text.toString()) + closeDialog() + } + R.id.iv_close -> closeDialog() + } + } + + + interface DialogClickListener { + fun onSentClick(cpInvitePageEntity: CpInvitePageEntity, declaration: String) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/relation/cp/dialog/CpInviteReplyConfirmDialog.kt b/app/src/main/java/com/chwl/app/relation/cp/dialog/CpInviteReplyConfirmDialog.kt new file mode 100644 index 0000000..ea013c9 --- /dev/null +++ b/app/src/main/java/com/chwl/app/relation/cp/dialog/CpInviteReplyConfirmDialog.kt @@ -0,0 +1,41 @@ +package com.chwl.app.relation.cp.dialog + +import android.content.Context +import android.text.SpannableStringBuilder +import android.view.View +import com.netease.nim.uikit.common.util.sys.ScreenUtil +import com.chwl.app.R +import com.chwl.app.databinding.DialogCpInviteReplyConfirmBinding +import com.chwl.app.base.BaseBindingDialog +import com.chwl.app.ui.widget.dialog.CommonTipDialog +import com.chwl.library.annatation.ActLayoutRes + +@ActLayoutRes(R.layout.dialog_cp_invite_reply_confirm) +class CpInviteReplyConfirmDialog(context: Context) : + BaseBindingDialog(context), View.OnClickListener { + private var text: CharSequence? = null + var okCancelListener: CommonTipDialog.OnActionListener? = null + override fun init() { + width = ScreenUtil.dip2px(300f) + height = ScreenUtil.dip2px(180f) + binding.click = this + binding.tvMessage.text = text + } + + fun setDialogTitle(text: SpannableStringBuilder) { + this.text = text + } + + override fun onClick(v: View) { + when (v.id) { + R.id.tv_refuse -> { + okCancelListener?.onCancel() + closeDialog() + } + R.id.tv_agree -> { + okCancelListener?.onOk() + closeDialog() + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/relation/cp/dialog/CpInviteReplyDialog.kt b/app/src/main/java/com/chwl/app/relation/cp/dialog/CpInviteReplyDialog.kt new file mode 100644 index 0000000..dda5db9 --- /dev/null +++ b/app/src/main/java/com/chwl/app/relation/cp/dialog/CpInviteReplyDialog.kt @@ -0,0 +1,133 @@ +package com.chwl.app.relation.cp.dialog + +import android.content.Context +import android.graphics.Color +import android.view.View +import com.netease.nim.uikit.common.util.sys.ScreenUtil +import com.chwl.app.R +import com.chwl.app.databinding.DialogCpInviteReplyBinding +import com.chwl.app.relation.cp.CpViewHelper +import com.chwl.app.relation.cp.CpViewHelper.getColorSpan +import com.chwl.app.relation.extention.toTimeString +import com.chwl.app.base.BaseBindingDialog +import com.chwl.app.ui.utils.ImageLoadUtilsV2 +import com.chwl.core.relation.cp.bean.CpInviteDetailEntity +import com.chwl.library.annatation.ActLayoutRes +import io.reactivex.Observable +import io.reactivex.Observer +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.disposables.Disposable +import io.reactivex.schedulers.Schedulers +import java.util.concurrent.TimeUnit + +@ActLayoutRes(R.layout.dialog_cp_invite_reply) +class CpInviteReplyDialog(context: Context) : + BaseBindingDialog(context), + View.OnClickListener { + private val disposeSet by lazy { + CompositeDisposable() + } + + var cpInviteData: CpInviteDetailEntity? = null + var listener: ReplyListener? = null + override fun init() { + width = ((292f / 375) * ScreenUtil.screenWidth).toInt() + binding.click = this + cpInviteData?.let { + setPage(it) + } + } + + private fun setPage(data: CpInviteDetailEntity) { + + binding.tvDialogTitle.text = getColorSpan( + "${data.inviteNick}邀請你達成CP關系,是否同意?", + Color.parseColor("#4C5AF1"), + 0, + data.inviteNick.length + ) + CpViewHelper.setInviteGiftPriceStyle( + context, + data.propsName, + data.propsPrice.toInt().toString(), + binding.tvPrice + ) + binding.tvDeclaration.text = data.declaration + ImageLoadUtilsV2.loadImage(binding.ivGift, cpInviteData?.propsImg) + } + + override fun onClick(v: View) { + when (v.id) { + R.id.tv_refuse -> { + listener?.onRefuse() + closeDialog() + } + R.id.tv_agree -> { + listener?.onAgree() + closeDialog() + } + R.id.iv_close -> closeDialog() + } + } + + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + cpInviteData?.replyExpireTime?.let { + countDown(it) + } + } + + private fun countDown(r: Int) { + Observable.interval(1000, TimeUnit.MILLISECONDS) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : Observer { + override fun onSubscribe(d: Disposable) { + disposeSet.add(d) + } + + override fun onNext(t: Long) { + var remain = (r - t).toInt() + if (remain <= 0) { + remain = 0 + stopCountDown() + listener?.onTimeOut() + } + val h = remain / 3600 + val m = (remain % 3600) / 60 + val s = remain % 3600 % 60 + val timeString = "${h.toTimeString()}:${m.toTimeString()}:${s.toTimeString()}" + CpViewHelper.setInviteTimeRemain(timeString, binding.tvTime) + } + + override fun onError(e: Throwable) { + e.printStackTrace() + stopCountDown() + } + + override fun onComplete() { + stopCountDown() + } + }) + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + stopCountDown() + } + + private fun stopCountDown() { + if (!disposeSet.isDisposed) { + disposeSet.dispose() + disposeSet.clear() + } + } + + interface ReplyListener { + fun onAgree() + fun onRefuse() + fun onTimeOut()//計時過期 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/relation/cp/dialog/CpMpDialog.kt b/app/src/main/java/com/chwl/app/relation/cp/dialog/CpMpDialog.kt new file mode 100644 index 0000000..f37d3f2 --- /dev/null +++ b/app/src/main/java/com/chwl/app/relation/cp/dialog/CpMpDialog.kt @@ -0,0 +1,67 @@ +package com.chwl.app.relation.cp.dialog + +import android.content.Context +import android.text.Editable +import android.view.View +import androidx.core.view.isVisible +import com.chwl.app.R +import com.chwl.app.databinding.DialogCpMpBinding +import com.chwl.app.base.BaseBindingDialog +import com.chwl.library.annatation.ActLayoutRes +import com.chwl.library.utils.TextWatcherWrapper + +@ActLayoutRes(R.layout.dialog_cp_mp) +class CpMpDialog(context: Context, private val type: Int) : + BaseBindingDialog(context), + View.OnClickListener { + //type:0 申请 1 定制 + override fun init() { + if (type == 0) { + binding.layoutRoot.setBackgroundResource(R.mipmap.bg_cp_mp_card_apply) + binding.groupApply.isVisible = true + binding.groupCustomized.isVisible = false + } else { + binding.layoutRoot.setBackgroundResource(R.mipmap.bg_cp_mp_card_customized) + binding.groupApply.isVisible = false + binding.groupCustomized.isVisible = true + } + binding.click = this + // binding.data = ? + binding.editCpMpCustomized.addTextChangedListener(textWatcher) + } + + override fun onClick(v: View) { + when (v.id) { + R.id.btn_require_current -> { + //申请名牌 + } + R.id.btn_require_next -> { + //申请名牌 + } + R.id.iv_cp_mp_customized -> { + //定制名牌 + } + } + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + binding.editCpMpCustomized.removeTextChangedListener(textWatcher) + } + + private val textWatcher = object : TextWatcherWrapper() { + private var hasEnabled = false + override fun afterTextChanged(editable: Editable?) { + super.afterTextChanged(editable) + if (editable?.length ?: 0 > 0) { + if (!hasEnabled) { + binding.ivCpMpCustomized.setImageResource(R.mipmap.ic_cp_mp_customized_enable) + hasEnabled = true + } + } else { + binding.ivCpMpCustomized.setImageResource(R.mipmap.ic_cp_mp_customized_disable) + hasEnabled = false + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/relation/cp/fragment/CpTaskFragment.kt b/app/src/main/java/com/chwl/app/relation/cp/fragment/CpTaskFragment.kt new file mode 100644 index 0000000..d6bf7f8 --- /dev/null +++ b/app/src/main/java/com/chwl/app/relation/cp/fragment/CpTaskFragment.kt @@ -0,0 +1,47 @@ +package com.chwl.app.relation.cp.fragment + +import android.os.Bundle +import androidx.fragment.app.activityViewModels +import androidx.recyclerview.widget.LinearLayoutManager +import com.chwl.app.R +import com.chwl.app.base.BaseBindingFragment +import com.chwl.app.databinding.FragmentCpTaskBinding +import com.chwl.app.relation.cp.adapter.CpTaskAdapter +import com.chwl.app.relation.cp.viewmodel.CpViewModel +import com.chwl.library.annatation.ActLayoutRes + +@ActLayoutRes(R.layout.fragment_cp_task) +class CpTaskFragment : BaseBindingFragment() { + private var pageType: Int = 0 + private lateinit var adapter: CpTaskAdapter + private val vm: CpViewModel by activityViewModels() + override fun initiate() { + arguments?.let { + pageType = it.getInt("type") + } + mBinding.recyclerView.layoutManager = + LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false) + adapter = CpTaskAdapter() + adapter.bindToRecyclerView(mBinding.recyclerView) + vm.cpTaskData.observe(this){ + when (pageType) { + TYPE_DAILY -> { + adapter.setNewData(it.dailyTask) + } + TYPE_TOTAL -> { + adapter.setNewData(it.totalTask) + } + } + } + } + + companion object { + const val TYPE_DAILY = 1 + const val TYPE_TOTAL = 2 + fun newInstance(type: Int) = CpTaskFragment().apply { + val bundle = Bundle() + bundle.putInt("type", type) + arguments = bundle + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/relation/cp/fragment/UserInfoCpFragment.kt b/app/src/main/java/com/chwl/app/relation/cp/fragment/UserInfoCpFragment.kt new file mode 100644 index 0000000..cffda84 --- /dev/null +++ b/app/src/main/java/com/chwl/app/relation/cp/fragment/UserInfoCpFragment.kt @@ -0,0 +1,114 @@ +package com.chwl.app.relation.cp.fragment + +import android.os.Bundle +import android.view.Gravity +import android.view.View +import android.widget.FrameLayout +import androidx.fragment.app.activityViewModels +import com.opensource.svgaplayer.SVGADrawable +import com.opensource.svgaplayer.SVGAImageView +import com.opensource.svgaplayer.SVGAParser +import com.opensource.svgaplayer.SVGAVideoEntity +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingFragment +import com.chwl.app.databinding.FragmentUserinfoCpBinding +import com.chwl.app.relation.cp.viewmodel.CpViewModel +import com.chwl.app.relation.cp.widget.RelationCpCardView +import com.chwl.app.ui.im.friend.FriendFragmentCpDelegate +import com.chwl.app.ui.relation.FansListActivity +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.core.auth.AuthModel +import com.chwl.core.noble.NobleResourceType +import com.chwl.core.noble.NobleUtil +import com.chwl.library.annatation.ActLayoutRes +import java.io.File +import java.net.URL + +@ActLayoutRes(R.layout.fragment_userinfo_cp) +class UserInfoCpFragment : BaseViewBindingFragment(), + View.OnClickListener { + private val vm: CpViewModel by activityViewModels() + private var uid: Long? = 0L + private val delegate: FriendFragmentCpDelegate by lazy { + FriendFragmentCpDelegate(this) + } + + override fun init() { + uid = arguments?.getLong("uid") + val isSelf = uid == AuthModel.get().currentUid + val type = if (isSelf) RelationCpCardView.PAGE_TYPE_SELF_INFO + else RelationCpCardView.PAGE_TYPE_CUS_INFO + vm.cpRelation.observe(this) { it -> + binding.cpCardView.setCpEntityData( + AuthModel.get().currentUid, + type, it + ) + //设置RelationView的位置 + (binding.cpCardView.layoutParams as? FrameLayout.LayoutParams)?.let { params -> + params.gravity = if (it.cpUid == 0L) Gravity.TOP else Gravity.CENTER + binding.container.requestLayout() + } + if (it.cpUid != 0L) {//有CP才加载背景 + //加一层判断 加载SVGA + binding.svgaImageViewBg.visibility = View.VISIBLE + when (NobleUtil.getResourceType(it.cpBackImg)) { + NobleResourceType.SVGAS -> playSVGA(binding.svgaImageViewBg, it.cpBackImg) + else -> ImageLoadUtils.loadImage( + requireContext(), + it.cpBackImg, + binding.svgaImageViewBg, + R.drawable.bg_cp_userinfo_card + ) + } + } + } + vm.loadingLiveData.observe(this) { + if (it) dialogManager.showProgressDialog(requireContext()) + else dialogManager.dismissDialog() + } + uid?.let { vm.getCpRelation(it) } + binding.cpCardView.setClick(this) + } + + companion object { + fun newInstance(uid: Long) = UserInfoCpFragment().apply { + val bundle = Bundle() + bundle.putLong("uid", uid) + arguments = bundle + } + } + + override fun onClick(v: View) { + when (v.id) { + R.id.other_avatar -> { + if (vm.cpRelation.value?.cpUid == 0L) { + //自己-邀请 + FansListActivity.start(requireContext(), FansListActivity.TYPE_CP) + } + } + R.id.iv_invite -> { + uid?.let { delegate.inviteCp(it) } + } + } + } + + private fun playSVGA(view: SVGAImageView, url: String) { + if (view.isAnimating) view.clearAnimation() + val mSVGAParser = SVGAParser(context) + mSVGAParser.decodeFromURL( + URL(url), + object : SVGAParser.ParseCompletion { + override fun onComplete(videoItem: SVGAVideoEntity) { + val drawable = SVGADrawable(videoItem) + view.setImageDrawable(drawable) + view.startAnimation() + } + + override fun onError() { + } + }, + object : SVGAParser.PlayCallback { + override fun onPlay(file: List) {} + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/relation/cp/model/Api.kt b/app/src/main/java/com/chwl/app/relation/cp/model/Api.kt new file mode 100644 index 0000000..4ec6e03 --- /dev/null +++ b/app/src/main/java/com/chwl/app/relation/cp/model/Api.kt @@ -0,0 +1,121 @@ +package com.chwl.app.relation.cp.model + +import com.chwl.core.bean.response.ServiceResult +import com.chwl.core.relation.cp.* +import com.chwl.core.relation.cp.bean.CpInviteDetailEntity +import com.chwl.core.relation.cp.bean.CpInvitePageEntity +import com.chwl.core.relation.cp.bean.CpMpApplyListEntity +import com.chwl.core.relation.cp.bean.CpRelation +import com.chwl.core.relation.cp.bean.CpTaskEntity +import com.chwl.core.relation.cp.bean.UserCpLevelMpRootEntity +import com.chwl.core.relation.cp.bean.UserCpListEntity +import retrofit2.http.* + +interface Api { + + /** + * 获取组CP邀请弹窗页面所需信息 + * + * @param acceptUid (query) 被邀请用户uid + */ + @GET("/user/couple/cpInvitePage") + suspend fun getCpInvitePageData( + @Query("acceptUid") acceptUid: Long + ): ServiceResult + + /** + * cp铭牌申请 + */ + @FormUrlEncoded + @POST("/user/couple/cpMpApply") + suspend fun cpMpApply( + @Field("mpId") mpId: Int, + @Field("mpTxt") mpTxt: String + ): ServiceResult//无需关心返回值 + + /** + *cp铭牌申请记录 + */ + @GET("/user/couple/cpMpApplyList") + suspend fun getCpMpApplyList( + @Query("pageNumber") pageNumber: Int, + @Query("pageSize") pageSize: Int + ): ServiceResult> + + + /** + * 发起组CP邀请 + * @param acceptUid + * @param declaration + * @param propsId + */ + @FormUrlEncoded + @POST("/user/couple/makeCpInvite") + suspend fun makeCpInvite( + @Field("acceptUid") acceptUid: Long, + @Field("declaration") declaration: String, + @Field("propsId") propsId: Int + ): ServiceResult + + /** + * 回复CP邀请 + * @param state 组CP邀请同意或拒绝:2-同意,3-拒绝 + * @param id 组cp邀请记录id + */ + @FormUrlEncoded + @POST("/user/couple/replyCpInvite") + suspend fun replyCpInvite( + @Field("id") id: Int, @Query("state") state: Int + ): ServiceResult + + /** + * 撤销解除绑定 + */ + @POST("/user/couple/revertUnboundCp") + suspend fun revertUnboundCp(): ServiceResult + + /** + *解除绑定CP关系 + */ + @POST("/user/couple/unboundCp") + suspend fun unboundCp(): ServiceResult + + /** + *用户CP等级可申请铭牌 + */ + @GET("/user/couple/userCpLevelMp") + suspend fun userCpLevelMp(): ServiceResult + + /** + *个人CP邀请列表 + * @param type 1-别人给我发的邀请,2-我给别人发的邀请 + */ + @GET("/user/couple/userCpList") + suspend fun userCpList( + @Query("type") type: Int + ): ServiceResult> + + /** + *亲密(CP)关系 + */ + @GET("/user/couple/cpRelation") + suspend fun cpRelation(@Query("uid") uid: Long): ServiceResult + + /** + *用户CP任务进程 + * @param cpTaskProcess 任务周期类型:1-每日任务,2-累计任务 + */ + @GET("/user/couple/cpTaskProcess") + suspend fun cpTaskProcess( + @Query("uid") uid: Long + ): ServiceResult + + /** + * 邀请记录详情 + * /user/couple/cpRecordDetail + */ + @GET("/user/couple/cpRecordDetail") + suspend fun inviteRecordDetail( + @Query("cpId") cpId: Int + ): ServiceResult +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/relation/cp/model/CpModel.kt b/app/src/main/java/com/chwl/app/relation/cp/model/CpModel.kt new file mode 100644 index 0000000..66cb66a --- /dev/null +++ b/app/src/main/java/com/chwl/app/relation/cp/model/CpModel.kt @@ -0,0 +1,77 @@ +package com.chwl.app.relation.cp.model + +import com.chwl.core.base.BaseModel +import com.chwl.core.relation.cp.bean.CpInviteDetailEntity +import com.chwl.core.relation.cp.bean.CpInvitePageEntity +import com.chwl.core.relation.cp.bean.CpMpApplyListEntity +import com.chwl.core.relation.cp.bean.CpRelation +import com.chwl.core.relation.cp.bean.CpTaskEntity +import com.chwl.core.relation.cp.bean.UserCpLevelMpRootEntity +import com.chwl.core.relation.cp.bean.UserCpListEntity +import com.chwl.core.utils.net.launchRequest +import com.chwl.library.net.rxnet.RxNet + +object CpModel : BaseModel() { + private val api = RxNet.create(Api::class.java) + + suspend fun getCpInvitePageData(acceptUid: Long): CpInvitePageEntity? = + launchRequest { + api.getCpInvitePageData(acceptUid) + } + + suspend fun cpMpApply(mpId: Int, mpText: String): Any? = + launchRequest { + api.cpMpApply(mpId, mpText) + } + + suspend fun cpMpApplyList(pageNumber: Int, pageSize: Int): List? = + launchRequest { + api.getCpMpApplyList(pageNumber, pageSize) + } + + suspend fun makeCpInvite(acceptUid: Long, declaration: String, propsId: Int): Any? = + launchRequest { + api.makeCpInvite(acceptUid, declaration, propsId) + } + + suspend fun replyCpInvite(id: Int, state: Int): Any? = + launchRequest { + api.replyCpInvite(id, state) + } + + suspend fun revertUnboundCp(): Any? = + launchRequest { + api.revertUnboundCp() + } + + suspend fun unboundCp(): Any? = + launchRequest { + api.unboundCp() + } + + suspend fun userCpLevelMp(): UserCpLevelMpRootEntity? = + launchRequest { + api.userCpLevelMp() + } + + suspend fun userCpList(type: Int): List? = + launchRequest { + api.userCpList(type) + } + + suspend fun userCpRelation(uid: Long): CpRelation? = + launchRequest { + api.cpRelation(uid) + } + + suspend fun cpTaskProcess(uid: Long): CpTaskEntity? = + launchRequest { + api.cpTaskProcess(uid) + } + suspend fun cpInviteDetail(cpId: Int): CpInviteDetailEntity? = + launchRequest { + api.inviteRecordDetail(cpId) + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/relation/cp/viewmodel/CpViewModel.kt b/app/src/main/java/com/chwl/app/relation/cp/viewmodel/CpViewModel.kt new file mode 100644 index 0000000..68ddc8a --- /dev/null +++ b/app/src/main/java/com/chwl/app/relation/cp/viewmodel/CpViewModel.kt @@ -0,0 +1,183 @@ +package com.chwl.app.relation.cp.viewmodel + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import com.chwl.app.R +import com.chwl.app.base.BaseViewModel +import com.chwl.app.relation.cp.model.CpModel +import com.chwl.core.relation.cp.* +import com.chwl.core.relation.cp.bean.CpInviteDetailEntity +import com.chwl.core.relation.cp.bean.CpInvitePageEntity +import com.chwl.core.relation.cp.bean.CpMpApplyListEntity +import com.chwl.core.relation.cp.bean.CpRelation +import com.chwl.core.relation.cp.bean.CpTaskEntity +import com.chwl.core.relation.cp.bean.UserCpLevelMpRootEntity +import com.chwl.core.relation.cp.bean.UserCpListEntity +import com.chwl.core.utils.net.BalanceNotEnoughExeption +import com.chwl.core.utils.net.ServerException +import com.chwl.core.utils.extension.toast +import com.chwl.library.utils.ResUtil +import org.greenrobot.eventbus.EventBus + +class CpViewModel : BaseViewModel() { + + //发起邀请组队CP弹窗数据 + private val _cpInvitePageData: MutableLiveData = MutableLiveData() + val cpInvitePageData: LiveData = _cpInvitePageData + + //cp铭牌申请记录 + private val _cpMpApplyListData: MutableLiveData> = MutableLiveData() + val cpMpApplyListData: LiveData> = _cpMpApplyListData + + //用户CP等级可申请铭牌 + private val _userCpLevelMpData: MutableLiveData = MutableLiveData() + val userCpLevelMpData: LiveData = _userCpLevelMpData + + //个人CP邀请列表 + private val _userCpListData: MutableLiveData> = MutableLiveData() + val userCpListData: LiveData> = _userCpListData + + //个人Cp信息 + private val _cpRelation: MutableLiveData = MutableLiveData() + val cpRelation: LiveData = _cpRelation + + //任务进程 + private val _cpTaskData: MutableLiveData = MutableLiveData() + val cpTaskData: LiveData = _cpTaskData + + //记录详情 + private val _cpInviteDetailData: MutableLiveData = MutableLiveData() + val cpInviteDetailData: LiveData = _cpInviteDetailData + + fun getCpInvitePageData(acceptUid: Long) { + safeLaunch( + true, + block = { + CpModel.getCpInvitePageData(acceptUid)?.let { + _cpInvitePageData.value = it + } + } + ) + } + + fun getCpMpApplyListData(pageNumber: Int, pageSize: Int) { + safeLaunch( + true, + block = { + CpModel.cpMpApplyList(pageNumber, pageSize)?.let { + _cpMpApplyListData.value = it + } + } + ) + } + + fun getUserCpLevelMpData() { + safeLaunch( + true, + block = { + CpModel.userCpLevelMp()?.let { + _userCpLevelMpData.value = it + } + } + ) + } + + fun getUserCpListData(type: Int) { + safeLaunch( + true, + block = { + CpModel.userCpList(type)?.let { + _userCpListData.value = it + } + } + ) + } + + fun getCpRelation(uid: Long) { + + safeLaunch( + true, + block = { + CpModel.userCpRelation(uid)?.let { + _cpRelation.value = it + } + + } + ) + } + + fun makeCpInvite( + acceptUid: Long, + declaration: String, + propsId: Int, + onBalanceNotEnough: (() -> Unit)? = null + ) { + + safeLaunch( + true, + onError = { + if (it is ServerException && it.code == BalanceNotEnoughExeption.code) { + //余额不足 + onBalanceNotEnough?.invoke() + } else { + it.message.toast() + } + }, + block = { + CpModel.makeCpInvite(acceptUid, declaration, propsId) + ResUtil.getString(R.string.cp_viewmodel_cpviewmodel_01).toast() + EventBus.getDefault().post(CpBindUnbindEvent()) + } + ) + } + + + fun revertUnbindCp() { + safeLaunch( + true, + block = { + CpModel.revertUnboundCp() + EventBus.getDefault().post(CpBindUnbindEvent()) + } + ) + } + + fun replyInvite(id: Int, state: Int) { + safeLaunch( + true, + block = { + CpModel.replyCpInvite(id, state) + EventBus.getDefault().post(CpBindUnbindEvent()) + } + ) + } + + fun unBindCp() { + safeLaunch( + true, + block = { + CpModel.unboundCp() + EventBus.getDefault().post(CpBindUnbindEvent()) + } + ) + } + + fun cpTaskProcess(uid: Long) { + safeLaunch( + true, + block = { + _cpTaskData.value = CpModel.cpTaskProcess(uid) + } + ) + } + + fun getCpInviteDetail(cpId: Int) { + safeLaunch( + true, + block = { + _cpInviteDetailData.value = CpModel.cpInviteDetail(cpId) + } + ) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/relation/cp/widget/CpTaskDescriptionView.kt b/app/src/main/java/com/chwl/app/relation/cp/widget/CpTaskDescriptionView.kt new file mode 100644 index 0000000..040306b --- /dev/null +++ b/app/src/main/java/com/chwl/app/relation/cp/widget/CpTaskDescriptionView.kt @@ -0,0 +1,95 @@ +package com.chwl.app.relation.cp.widget + +import android.content.Context +import android.graphics.Color +import android.text.SpannableStringBuilder +import android.text.TextUtils +import android.text.style.AbsoluteSizeSpan +import android.text.style.ForegroundColorSpan +import android.util.AttributeSet +import android.view.LayoutInflater +import android.widget.LinearLayout +import android.widget.TextView +import com.netease.nim.uikit.common.util.sys.ScreenUtil +import com.chwl.app.R + + +class CpTaskDescriptionView(context: Context, attr: AttributeSet?, def: Int) : LinearLayout( + context, attr, def +) { + constructor(context: Context, attr: AttributeSet?):this(context,attr,0) + constructor(context: Context):this(context,null,0) + init { + orientation = VERTICAL + setBackgroundResource(R.drawable.bg_white_cornor_4) + } + + fun setTaskData(titleLeft: String, titleRight: String, taskList: List) { + addTab(titleLeft, titleRight, true) + taskList.forEach { + addTab(it.title, it.value, false) + } + requestLayout() + } + + + private fun addTab( + title: String, + content: String, + isTableTitle: Boolean + ) { + val view = + LayoutInflater.from(context).inflate(R.layout.layout_cp_task_table_item, this, false) + val titleView = view.findViewById(R.id.tv_cp_level_title) + val contentView = view.findViewById(R.id.tv_cp_level_content) + if (isTableTitle) { + (view.layoutParams as MarginLayoutParams).bottomMargin = 0 + titleView.isSingleLine = true + titleView.ellipsize = TextUtils.TruncateAt.END + contentView.isSingleLine = true + contentView.ellipsize = TextUtils.TruncateAt.END + titleView.setBackgroundResource(R.drawable.bg_cp_task_label_left) + contentView.setBackgroundResource(R.drawable.bg_cp_task_label_right) + val sizeSpan = AbsoluteSizeSpan(ScreenUtil.dip2px(16f)) + val colorSpan = ForegroundColorSpan(Color.WHITE) + SpannableStringBuilder(title).apply { + setSpan(sizeSpan, 0, title.length, SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE) + setSpan(colorSpan, 0, title.length, SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE) + titleView.text = this + } + SpannableStringBuilder(content).apply { + setSpan( + sizeSpan, + 0, + content.length, + SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE + ) + setSpan( + colorSpan, + 0, + content.length, + SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE + ) + contentView.text = this + } + } else { + titleView.text = title + contentView.text = content + } + addView(view) + } + + + data class TaskEntity(val title: String, val value: String) { + companion object { + fun toTaskList(titles: Array, contents: Array): List + { + val list :ArrayList = ArrayList() + for (i in titles.indices){ + list.add(TaskEntity(titles[i],contents[i])) + } + return list + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/relation/cp/widget/RelationCpCardView.kt b/app/src/main/java/com/chwl/app/relation/cp/widget/RelationCpCardView.kt new file mode 100644 index 0000000..44fe6f7 --- /dev/null +++ b/app/src/main/java/com/chwl/app/relation/cp/widget/RelationCpCardView.kt @@ -0,0 +1,174 @@ +package com.chwl.app.relation.cp.widget + +import android.content.Context +import android.graphics.Color +import android.util.AttributeSet +import android.view.Gravity +import android.view.LayoutInflater +import android.widget.FrameLayout +import androidx.core.content.ContextCompat +import androidx.core.view.isVisible +import androidx.databinding.DataBindingUtil +import com.netease.nim.uikit.common.util.sys.ScreenUtil +import com.chwl.app.R +import com.chwl.app.databinding.LayoutCpCardBinding +import com.chwl.app.relation.extention.visibility +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.core.relation.cp.bean.CpInvitePageEntity +import com.chwl.core.relation.cp.bean.CpRelation +import com.chwl.library.utils.ResUtil + +class RelationCpCardView(context: Context, attr: AttributeSet?, def: Int) : + FrameLayout(context, attr, def) { + constructor(context: Context, attr: AttributeSet?) : this(context, attr, 0) + constructor(context: Context) : this(context, null) + + private val binding: LayoutCpCardBinding + + init { + val inflater = LayoutInflater.from(context) + binding = DataBindingUtil.inflate(inflater, R.layout.layout_cp_card, this, false) + val params = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT) + params.gravity = Gravity.CENTER + addView(binding.root, params) + } + + private fun setPageData( + selfUId: Long, + type: Int, + cpRelation: CpRelation?, + inviteData: CpInvitePageEntity? + ) { + var userInfoVisibility = false + var cpLevelVisibility = false + var unbindVisibility = false + var unbindRecoverVisibility = false + var groupEmptyVisibility = false + var declarationVisibility = false + binding.cpEntity = cpRelation + setBackground(type, cpRelation) + inviteData?.let { binding.inviteData = it } + var height = 0 + when (type) { + PAGE_TYPE_SELF_CP -> { + if (cpRelation == null) return + userInfoVisibility = true + cpLevelVisibility = cpRelation.cpUid != 0.toLong() + binding.tvCpTime.setTextColor(context.resources.getColor(R.color.white)) + unbindRecoverVisibility = cpRelation.waitUnbound + unbindVisibility = cpRelation.cpUid != 0L && !cpRelation.waitUnbound//双方都能解绑 + setUnbindButton(cpRelation, selfUId) + height = ScreenUtil.dip2px(180f) + } + PAGE_TYPE_SELF_INFO -> { + if (cpRelation == null) return + userInfoVisibility = true + cpLevelVisibility = cpRelation.cpUid != 0.toLong() + binding.tvCpTime.setTextColor(Color.parseColor("#4514AF")) + height = LayoutParams.WRAP_CONTENT + declarationVisibility = cpRelation.cpUid != 0.toLong() + } + PAGE_TYPE_CUS_INFO -> { + if (cpRelation == null) return + userInfoVisibility = cpRelation.cpUid != 0.toLong() + cpLevelVisibility = cpRelation.cpUid != 0.toLong() + binding.tvCpTime.setTextColor(Color.parseColor("#4514AF")) + groupEmptyVisibility = cpRelation.cpUid == 0.toLong() + declarationVisibility = cpRelation.cpUid != 0.toLong() + height = LayoutParams.WRAP_CONTENT + } + PAGE_TYPE_INVITE_DIALOG -> { + userInfoVisibility = true + height = ScreenUtil.dip2px(80f) + binding.tvMineName.textSize=12f + binding.tvOtherName.textSize=12f + } + } + val centerHeartVisibility = userInfoVisibility + val keepTimeVisibility = cpLevelVisibility + + + binding.mineAvatar.visibility = userInfoVisibility.visibility() + binding.tvMineName.visibility = userInfoVisibility.visibility() + binding.ivCpHeart.visibility = centerHeartVisibility.visibility() + binding.tvLevel.visibility = cpLevelVisibility.visibility() + binding.tvCpTime.visibility = keepTimeVisibility.visibility() + binding.tvRecoveryUnbind.visibility = unbindRecoverVisibility.visibility() + binding.otherAvatar.visibility = userInfoVisibility.visibility() + binding.tvOtherName.visibility = userInfoVisibility.visibility() + binding.tvCpEmptyTip.visibility = groupEmptyVisibility.visibility() + binding.btnBind.visibility = groupEmptyVisibility.visibility() + binding.ivInvite.visibility = groupEmptyVisibility.visibility() + binding.tvDeclaration.visibility = declarationVisibility.visibility() + binding.flMenu.visibility = unbindVisibility.visibility() + binding.ivUnbind.visibility = false.visibility()//解绑按钮只有点击才可见 + binding.cpEntity = cpRelation + binding.root.layoutParams?.height = height + requestLayout() + } + + private fun setUnbindButton( + cpRelation: CpRelation, + selfUId: Long + ) { + if (cpRelation.waitUnbound) { + if (cpRelation.unboundUid != selfUId) { + binding.tvRecoveryUnbind.text = ResUtil.getString(R.string.cp_widget_relationcpcardview_01) + binding.tvRecoveryUnbind.isEnabled = false + binding.tvRecoveryUnbind.background = null + } else { + binding.tvRecoveryUnbind.text = ResUtil.getString(R.string.cp_widget_relationcpcardview_02) + binding.tvRecoveryUnbind.isEnabled = true + binding.tvRecoveryUnbind.background = + ContextCompat.getDrawable(context, R.drawable.bg_ff696f_ffafc3_cornor_4) + } + } + } + + private fun setBackground( + type: Int, + it: CpRelation? + ) { + when (type) { + PAGE_TYPE_SELF_CP -> { + ImageLoadUtils.loadRoundBackground( + context, null,//开始说是动态的,后来说这个页面背景是固定的 所以传空值直接设置默认的背景 + this, 16, + R.drawable.bg_cp_card + ) + } + PAGE_TYPE_CUS_INFO, PAGE_TYPE_SELF_INFO -> { + if (it?.cpUid ?: 0L == 0L) {//有CP时交由外面的容器加载背景 + ImageLoadUtils.loadRoundBackground( + context, it?.cpBackImg, + this, 16, + R.drawable.bg_cp_card + ) + } + } + } + } + + fun setInviteDialogPageData(inviteData: CpInvitePageEntity?) { + setPageData(0, PAGE_TYPE_INVITE_DIALOG, null, inviteData) + } + + fun setCpEntityData(selfUId: Long, type: Int, cpRelation: CpRelation?) { + setPageData(selfUId, type, cpRelation, null) + } + + fun setClick(click: OnClickListener) { + binding.click = click + binding.ivMore.setOnClickListener { + val visible = (!binding.ivUnbind.isVisible) + binding.ivUnbind.visibility = visible.visibility() + } + } + + companion object { + const val PAGE_TYPE_SELF_CP = 1//亲密关系页面 主态 + const val PAGE_TYPE_SELF_INFO = 2//个人中心主态 + const val PAGE_TYPE_CUS_INFO = 3//个人中心客态 + const val PAGE_TYPE_INVITE_DIALOG = 5//邀请弹窗 + } +} diff --git a/app/src/main/java/com/chwl/app/relation/extention/RelationExtention.kt b/app/src/main/java/com/chwl/app/relation/extention/RelationExtention.kt new file mode 100644 index 0000000..84c6d89 --- /dev/null +++ b/app/src/main/java/com/chwl/app/relation/extention/RelationExtention.kt @@ -0,0 +1,7 @@ +package com.chwl.app.relation.extention + +import android.view.View + +fun Boolean.visibility(): Int = if (this) View.VISIBLE else View.GONE + +fun Int.toTimeString() = if (this > 9) this.toString() else "0${this}" \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/service/DaemonService.java b/app/src/main/java/com/chwl/app/service/DaemonService.java new file mode 100644 index 0000000..d4d5cc6 --- /dev/null +++ b/app/src/main/java/com/chwl/app/service/DaemonService.java @@ -0,0 +1,117 @@ +package com.chwl.app.service; + +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.os.Build; +import android.os.IBinder; + +import androidx.annotation.Nullable; + +import com.chwl.app.R; +import com.chwl.app.reciever.NotificationClickReceiver; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.library.utils.ResUtil; + +/** + * @author chenran + * @date 2017/11/16 + */ + +public class DaemonService extends Service { + private static final String TAG = "DaemonService"; + public static final int NOTICE_ID = 100; + private static final String CHANNEL_ID = "IN_ROOM"; + private static final String CHANNEL_NAME = ResUtil.getString(R.string.erban_service_daemonservice_01); + private String title; + private boolean isStartForeground = false; + + public static void start(Context context, RoomInfo roomInfo) { + Intent intent = new Intent(context, DaemonService.class); + intent.putExtra("title", roomInfo.getTitle()); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + context.startForegroundService(intent); + } else { + context.startService(intent); + } + } + + public static void stop(Context context) { + Intent intent = new Intent(context, DaemonService.class); + context.stopService(intent); + } + + @Nullable + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo != null) { + title = roomInfo.getTitle(); + Notification.Builder builder = new Notification.Builder(this); + builder.setSmallIcon(R.mipmap.ic_launcher); + builder.setContentTitle(title); + builder.setContentText(ResUtil.getString(R.string.erban_service_daemonservice_02)); + builder.setTicker(ResUtil.getString(R.string.erban_service_daemonservice_03)); + Intent clickIntent = new Intent(this, NotificationClickReceiver.class); + int flag = PendingIntent.FLAG_UPDATE_CURRENT; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { + flag = flag | PendingIntent.FLAG_IMMUTABLE; + } + PendingIntent contentIntent = PendingIntent.getBroadcast( + this.getApplicationContext(), + (int) (System.currentTimeMillis() / 100000), + clickIntent, + flag); + builder.setContentIntent(contentIntent); + //8.0系统适配 + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { + String channelID = getPackageName() + "1"; + String channelName = ResUtil.getString(R.string.erban_service_daemonservice_04); + NotificationChannel channel = new NotificationChannel(channelID, channelName, NotificationManager.IMPORTANCE_HIGH); + channel.setSound(null, null); + NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + manager.createNotificationChannel(channel); + builder.setChannelId(channelID); + } + startForeground(NOTICE_ID, builder.build()); + isStartForeground = true; + } else { + Notification.Builder builder = new Notification.Builder(this); + builder.setSmallIcon(R.mipmap.ic_launcher); + builder.setContentText(ResUtil.getString(R.string.erban_service_daemonservice_05)); + builder.setTicker(ResUtil.getString(R.string.erban_service_daemonservice_06)); + //8.0系统适配 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + String channelID = getPackageName() + "1"; + String channelName = ResUtil.getString(R.string.erban_service_daemonservice_04); + NotificationChannel channel = new NotificationChannel(channelID, channelName, NotificationManager.IMPORTANCE_HIGH); + channel.setSound(null, null); + NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + manager.createNotificationChannel(channel); + builder.setChannelId(channelID); + } + startForeground(NOTICE_ID, builder.build()); + isStartForeground = true; + stopSelf(); + } + return START_NOT_STICKY; + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (isStartForeground) { + stopForeground(true); + } + } +} diff --git a/app/src/main/java/com/chwl/app/share/Holder.java b/app/src/main/java/com/chwl/app/share/Holder.java new file mode 100644 index 0000000..1073d5a --- /dev/null +++ b/app/src/main/java/com/chwl/app/share/Holder.java @@ -0,0 +1,8 @@ +package com.chwl.app.share; + +/** + * Created by MadisonRong on 08/06/2018. + */ + +public class Holder { +} diff --git a/app/src/main/java/com/chwl/app/share/viewholder/InAppSharingMsgViewHolder.java b/app/src/main/java/com/chwl/app/share/viewholder/InAppSharingMsgViewHolder.java new file mode 100644 index 0000000..d27fc6b --- /dev/null +++ b/app/src/main/java/com/chwl/app/share/viewholder/InAppSharingMsgViewHolder.java @@ -0,0 +1,113 @@ +package com.chwl.app.share.viewholder; + +import android.graphics.Color; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import com.netease.nim.uikit.business.session.viewholder.MsgViewHolderBase; +import com.netease.nim.uikit.common.ui.recyclerview.adapter.BaseMultiItemFetchLoadAdapter; +import com.chwl.app.R; +import com.chwl.app.ui.im.RouterHandler; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.im.custom.bean.CustomAttachment; +import com.chwl.core.im.custom.bean.InAppSharingFamilyAttachment; +import com.chwl.core.im.custom.bean.InAppSharingMiniWorldAttachment; +import com.chwl.core.im.custom.bean.InAppSharingRoomAttachment; +import com.chwl.core.im.custom.bean.InAppSharingTeamAttachment; +import com.chwl.core.im.custom.bean.RouterType; +import com.chwl.core.share.bean.InAppSharingInfo; +import com.chwl.core.share.bean.InAppSharingTeamInfo; +import com.chwl.core.team.bean.TeamInfo; + +/** + * Created by MadisonRong on 08/06/2018. + */ + +public class InAppSharingMsgViewHolder extends MsgViewHolderBase implements View.OnClickListener { + + private View layout; + private TextView title; + private ImageView avatar; + private TextView action; + private String routerValue; + private int routerType; + + public InAppSharingMsgViewHolder(BaseMultiItemFetchLoadAdapter adapter) { + super(adapter); + } + + @Override + public void onClick(View v) { + CustomAttachment attachment = (CustomAttachment) message.getAttachment(); + if (attachment.getSecond() == CustomAttachment.CUSTOM_MSG_SHARE_TEAM) { + InAppSharingTeamAttachment inAppSharingTeamAttachment = (InAppSharingTeamAttachment) attachment; + InAppSharingTeamInfo inAppSharingTeamInfo = inAppSharingTeamAttachment.getInfo(); + TeamInfo info = inAppSharingTeamInfo.getInfo(); + if (info == null) { + return; + } + // 分享群组时,点击动作打开家族客态页 + RouterHandler.handle(context, RouterType.FAMILY, info.getFamilyId()); + } else { + RouterHandler.handle(context, routerType, routerValue); + } + } + + @Override + protected int getContentResId() { + return R.layout.layout_msg_view_holder_in_app_sharing; + } + + @Override + protected void inflateContentView() { + layout = findViewById(R.id.ll_in_app_sharing_msg_view_holder); + title = findViewById(R.id.tv_title); + avatar = findViewById(R.id.iv_avatar); + action = findViewById(R.id.tv_action); + } + + @Override + protected void bindContentView() { + CustomAttachment customAttachment = (CustomAttachment) message.getAttachment(); + InAppSharingInfo inAppSharingInfo; + switch (customAttachment.getSecond()) { + default: + case CustomAttachment.CUSTOM_MSG_SHARE_ROOM: + InAppSharingRoomAttachment roomAttachment = (InAppSharingRoomAttachment) customAttachment; + inAppSharingInfo = roomAttachment.getInfo(); + break; + + case CustomAttachment.CUSTOM_MSG_SHARE_FAMILY: + InAppSharingFamilyAttachment familyAttachment = (InAppSharingFamilyAttachment) customAttachment; + inAppSharingInfo = familyAttachment.getInfo(); + break; + + case CustomAttachment.CUSTOM_MSG_SHARE_TEAM: + InAppSharingTeamAttachment teamAttachment = (InAppSharingTeamAttachment) customAttachment; + inAppSharingInfo = teamAttachment.getInfo(); + break; + + case CustomAttachment.CUSTOM_MSG_SHARE_MINI_WORLD: + InAppSharingMiniWorldAttachment miniWorldAttachment = (InAppSharingMiniWorldAttachment) customAttachment; + inAppSharingInfo = miniWorldAttachment.getInfo(); + break; + } + if (inAppSharingInfo != null) { + if (isReceivedMessage()) { + title.setTextColor(Color.BLACK); + action.setTextColor(Color.BLACK); + } else { + title.setTextColor(Color.WHITE); + action.setTextColor(Color.WHITE); + } + title.setText(inAppSharingInfo.getTitle()); + ImageLoadUtils.loadRectImage(context, inAppSharingInfo.getAvatar(), avatar, + R.drawable.default_avatar, 5); + action.setText(inAppSharingInfo.getActionName()); + routerType = inAppSharingInfo.getRouterType(); + routerValue = inAppSharingInfo.getRouterValue(); + layout.setOnClickListener(this); + } + } +} diff --git a/app/src/main/java/com/chwl/app/skill/SKillDataParser.kt b/app/src/main/java/com/chwl/app/skill/SKillDataParser.kt new file mode 100644 index 0000000..879e3ac --- /dev/null +++ b/app/src/main/java/com/chwl/app/skill/SKillDataParser.kt @@ -0,0 +1,106 @@ +package com.chwl.app.skill + +import com.chwl.app.skill.widget.ItemAttribute +import com.chwl.app.skill.widget.ItemEventListener +import com.chwl.app.skill.widget.SkillAttribute +import com.chwl.app.skill.widget.SkillItem +import com.chwl.core.skill.entity.* + +object SKillDataParser { + private fun parseItemRecordToAttribute( + cardId: Int, + isSelf: Boolean, + isEdit: Boolean, + itemEventListener: ItemEventListener? = null, + item: PropRecordVoEntity, + audioStatus: Int = 0 + ): ItemAttribute { + return ItemAttribute( + cardId, + isSelf, isEdit, + item.state, item.isMust, + item.parentId, item.parentVal, + itemEventListener, + item.refPropVos.toMutableList(), + ).apply { + this.audioStatus = audioStatus + } + } + + + fun parseSkillRecordToAttribute( + item: SkillRecordEntity, + itemEventListener: ItemEventListener? = null, + ): SkillAttribute { + val list: MutableList = ArrayList() + item.propRecordVo.forEach { + val element = parseItemRecordToAttribute( + item.cardId, + item.isSelf, + item.isEdit, + itemEventListener, + it + ).apply { + audioStatus = item.audioStatus + } + list.add(element) + } + return SkillAttribute( + item.id, item.type, item.cardId, + item.icon, item.name, + item.isSelf, item.isEdit, + item.pic, list + ) + } + + fun parseSkillPropertyToAttribute( + item: SkillPropertyEntity, + itemEventListener: ItemEventListener? = null, + ): SkillAttribute { + val list: MutableList = ArrayList() + item.props.forEach { + val element = parseItemRecordToAttribute( + item.cardId, + item.isSelf, + item.isEdit, + itemEventListener, + it.parsePropToRecord() + ) + list.add(element) + } + return SkillAttribute( + -1, item.type, item.cardId, + item.icon, item.name, + item.isSelf, item.isEdit, + item.pic, list + ).apply { + needBack = item.needBack + needTitle = item.needTitle + } + } + + /** + * 转换成服务器数据 + */ + fun parseSkillSelectedValue( + recordId: Int, + cardId: Int, + itemList: List + ): SkillPostServerEntity { + return if (itemList.isEmpty()) { + SkillPostServerEntity(propRecordVo = ArrayList(0)) + } else { + val list = ArrayList() + itemList.forEach { + val item = it.getContentEntity() + list.add( + SKillValueEntity( + item.parentId, + it.getContentEntity().selectedProperties + ) + ) + } + SkillPostServerEntity(recordId, cardId, list) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/skill/SkillDataDelegate.kt b/app/src/main/java/com/chwl/app/skill/SkillDataDelegate.kt new file mode 100644 index 0000000..b2e2003 --- /dev/null +++ b/app/src/main/java/com/chwl/app/skill/SkillDataDelegate.kt @@ -0,0 +1,203 @@ +package com.chwl.app.skill + +import android.annotation.SuppressLint +import com.chwl.app.R +import com.chwl.app.base.BaseActivity +import com.chwl.app.skill.dialog.SkillSelectionDialog +import com.chwl.app.skill.repository.SkillDataManager +import com.chwl.app.skill.repository.SkillModel +import com.chwl.app.skill.widget.* +import com.chwl.core.file.FileModel +import com.chwl.core.skill.entity.PropRefEntity +import com.chwl.core.skill.entity.PropsEntity +import com.chwl.core.skill.entity.SkillPostServerEntity +import com.chwl.core.skill.entity.SkillPropertyEntity +import com.chwl.core.skill.event.SkillEvent +import com.chwl.core.utils.extension.toast +import com.chwl.library.utils.ResUtil +import org.greenrobot.eventbus.EventBus +import java.io.File + +class SkillDataDelegate(private val skillView: SkillCardView, private val activity: BaseActivity) : + ItemEventListener { + @SuppressLint("CheckResult") + override fun onItemClick(item: SkillItem) { + onItemSelection(item) + } + + override fun onRecordSuccess(audioFile: File?, duration: Int) { + onRecordAudioSuccess(audioFile, duration) + } + + override fun onDeleteRecordClick() { + deleteSkill(false) + } + + + /** + * 上传音频文件 + */ + private fun onRecordAudioSuccess(audioFile: File?, duration: Int) { + val sourceItem = + skillView.getItems().find { it.getContentEntity().state == ItemAttribute.STATE_AUDIO }!! + val durationItem = + skillView.getItems() + .find { it.getContentEntity().state == ItemAttribute.STATE_DURATION }!! + + with(durationItem.getContentEntity()) { + if (selectedProperties.isEmpty()) { + val entity = PropRefEntity(parentId, duration.toString()) + selectedProperties.add(entity) + } else { + selectedProperties[0].propVal = duration.toString() + } + } + + audioFile?.absolutePath?.let { + activity.dialogManager.showProgressDialog(activity) + FileModel.get() + .uploadFile(audioFile.absolutePath) + .flatMap { + with(sourceItem.getContentEntity()) { + if (selectedProperties.isEmpty()) { + val entity = PropRefEntity(parentId, it) + selectedProperties.add(entity) + } else { + selectedProperties[0].propVal = it + } + } + SkillModel.instance.saveSkillInfo( + SKillDataParser.parseSkillSelectedValue( + skillView.getAttributes().id, + skillView.getAttributes().cardId, + skillView.getItems() + ) + ) + }.compose(activity.bindToLifecycle()) + .subscribe({ + activity.dialogManager.dismissDialog() + EventBus.getDefault().post(SkillEvent()) + if (skillView.getAttributes().id == -1) { + activity.finish() + } + }, { + activity.dialogManager.dismissDialog() + ResUtil.getString(R.string.erban_skill_skilldatadelegate_01).toast() + (sourceItem as RecordIResourceItem).setItemByState(RecordIResourceItem.RECORD_STATE_READY) + }) + } + } + + /** + * 选项 + */ + @SuppressLint("CheckResult") + private fun onItemSelection(item: SkillItem) { + val propertyEntity = + SkillDataManager.get().getPropertyEntity(item.getContentEntity().cardId) + if (propertyEntity == null) { + SkillModel.instance.getCardInfoById(item.getContentEntity().cardId) + .compose(activity.bindToLifecycle()) + .doOnSubscribe { activity.dialogManager.showProgressDialog(activity) } + .subscribe({ + SkillDataManager.get() + .setSkillPropertyEntity(item.getContentEntity().cardId, it) + showSelectionDialog(item, it) + activity.dialogManager.dismissDialog() + }, { th -> + th.printStackTrace() + activity.toast(th.message) + showSelectionDialog(item, null) + activity.dialogManager.dismissDialog() + }) + } else { + showSelectionDialog(item, propertyEntity) + } + } + + private fun showSelectionValueDialog(item: SkillItem, propertyEntity: PropsEntity?) { + val selectionDialog = SkillSelectionDialog(activity, propertyEntity) { + item.getContentEntity().selectedProperties.clear() + it.forEach { element -> item.getContentEntity().selectedProperties.add(element.parseToRecord()) } + item.invalidate() + } + selectionDialog.openDialog() + } + + /** + * 显示选择对话框 + */ + private fun showSelectionDialog(item: SkillItem, propertyEntity: SkillPropertyEntity?) { + val props = propertyEntity?.props + val propDictVos = props?.find { it.id == item.getContentEntity().parentId }?.apply { + propDictVos?.forEach { prop -> + //清空已选项 + prop.isSelected = false + //设置之前保存的选项,从服务器拉下来的数据 + val hasSelectBefore = + item.getContentEntity().selectedProperties.find { record -> record.propId == prop.id } + if (hasSelectBefore != null) { + //表示这个是上次存在服务器的值 设置为true + prop.isSelected = true + } + } + + } + showSelectionValueDialog(item, propDictVos) + } + + @SuppressLint("CheckResult") + internal fun saveSkill() { + if (!skillView.isValid()) { + activity.toast(ResUtil.getString(R.string.erban_skill_skilldatadelegate_02)) + return + } + val item = parseSelectedValues() + SkillModel.instance.saveSkillInfo(item).compose(activity.bindToLifecycle()) + .doOnSubscribe { activity.dialogManager.showProgressDialog(activity) } + .subscribe( + { + activity.dialogManager.dismissDialog() + val event = SkillEvent() + event.event = SkillEvent.ADD + EventBus.getDefault().post(event) + activity.finish() + }, + { th -> + th.printStackTrace() + activity.toast(th.message) + activity.dialogManager.dismissDialog() + }) + } + + /** + * 获取SkillView数据转换成提交服务器数据 + */ + private fun parseSelectedValues(): SkillPostServerEntity { + val itemList = skillView.getItems() + val skillAttr = skillView.getAttributes() + return SKillDataParser.parseSkillSelectedValue(skillAttr.id, skillAttr.cardId, itemList) + } + + /** + * 删除技能卡 + */ + @SuppressLint("CheckResult") + fun deleteSkill(needFinishCurrent: Boolean) { + activity.dialogManager.showProgressDialog(activity) + SkillModel.instance.deleteSkill(skillView.getAttributes().id) + .compose(activity.bindToLifecycle()) + .subscribe({ + activity.toast(ResUtil.getString(R.string.erban_skill_skilldatadelegate_03)) + val event = SkillEvent() + event.event = SkillEvent.REMOVE + EventBus.getDefault().post(event) + activity.dialogManager.dismissDialog() + if (needFinishCurrent) + activity.finish() + }, { th -> + th.printStackTrace() + activity.toast(th.message) + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/skill/activity/AddSkillActivity.kt b/app/src/main/java/com/chwl/app/skill/activity/AddSkillActivity.kt new file mode 100644 index 0000000..04ae4d7 --- /dev/null +++ b/app/src/main/java/com/chwl/app/skill/activity/AddSkillActivity.kt @@ -0,0 +1,132 @@ +package com.chwl.app.skill.activity + +import android.Manifest +import android.annotation.SuppressLint +import android.content.Context +import android.content.Intent +import android.view.View +import com.netease.nim.uikit.StatusBarUtil +import com.chwl.app.R +import com.chwl.app.base.BaseBindingActivity +import com.chwl.app.databinding.ActivitySkillEditBinding +import com.chwl.app.skill.repository.SkillDataManager +import com.chwl.app.skill.repository.SkillModel +import com.chwl.app.skill.widget.CARD_TYPE_AUDIO +import com.chwl.core.skill.entity.SkillPropertyEntity +import com.chwl.library.annatation.ActLayoutRes +import com.chwl.library.utils.ResUtil + +@ActLayoutRes(R.layout.activity_skill_edit) +class AddSkillActivity : BaseBindingActivity() { + private lateinit var delegate: SkillEditableDelegate + private var cardType = -1 + override fun init() { + delegate = SkillEditableDelegate(this) + initTitleBar(ResUtil.getString(R.string.skill_activity_addskillactivity_01)) + mBinding.click = this + mBinding.btnDelete.visibility = View.GONE + val cardId = intent?.getIntExtra(ITEM, -1) ?: -1 + if (cardId > 0) { + queryCardInfo(cardId) + } + } + + @SuppressLint("CheckResult") + private fun queryCardInfo(cardId: Int) { + val propertyEntity = SkillDataManager.get().getPropertyEntity(cardId) + if (propertyEntity != null) { + if (propertyEntity.type == CARD_TYPE_AUDIO) { + dealAudioView(propertyEntity) + } + setSkillViewData(propertyEntity) + } else { + SkillModel.instance.getCardInfoById(cardId) + .compose(bindToLifecycle()) + .subscribe({ + when (it.type) { + CARD_TYPE_AUDIO -> { + dealAudioView(it) + it.needBack = false + it.needTitle = false + checkPermissionAndDeal(it) + } + else -> { + it.needBack = true + it.needTitle = true + setSkillViewData(it) + } + } + SkillDataManager.get().setSkillPropertyEntity(cardId, it) + }, { th -> + th.printStackTrace() + toast(th.message) + }) + } + } + + private fun dealAudioView(propertyEntity: SkillPropertyEntity) { + checkPermissionAndDeal(propertyEntity) + mBinding.rootView.setBackgroundResource(R.drawable.bg_skill_add_audio) + mBinding.btnSave.visibility = View.GONE + cardType = propertyEntity.type + } + + + private fun setSkillViewData(it: SkillPropertyEntity) { + it.isSelf = true + it.isEdit = true + delegate.setSkillViewData(it) + } + + @SuppressLint("CheckResult") + private fun checkPermissionAndDeal(it: SkillPropertyEntity) { + checkPermission( + Manifest.permission.RECORD_AUDIO, + Manifest.permission.WRITE_EXTERNAL_STORAGE + ) + .subscribe { aBoolean: Boolean -> + if (aBoolean) { + setSkillViewData(it) + } else { + toast(ResUtil.getString(R.string.skill_activity_addskillactivity_02)) + finish() + } + } + } + + + override fun onLeftClickListener() { + delegate.onLeftClick() + } + + override fun onClick(v: View?) { + super.onClick(v) + when (v?.id) { + R.id.btn_save -> delegate.saveSkill() + } + } + + companion object { + private const val ITEM = "item" + fun start(context: Context, cardId: Int) { + val intent = Intent(context, AddSkillActivity::class.java) + intent.putExtra(ITEM, cardId) + context.startActivity(intent) + } + } + + override fun onBackPressed() { + if (cardType == CARD_TYPE_AUDIO) { + super.onBackPressed() + return + } + delegate.onLeftClick() + } + + override fun needSteepStateBar() = true + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/skill/activity/EditSkillActivity.kt b/app/src/main/java/com/chwl/app/skill/activity/EditSkillActivity.kt new file mode 100644 index 0000000..f8ecd6e --- /dev/null +++ b/app/src/main/java/com/chwl/app/skill/activity/EditSkillActivity.kt @@ -0,0 +1,101 @@ +package com.chwl.app.skill.activity + +import android.annotation.SuppressLint +import android.content.Context +import android.content.Intent +import android.view.View +import com.netease.nim.uikit.StatusBarUtil +import com.chwl.app.R +import com.chwl.app.base.BaseBindingActivity +import com.chwl.app.databinding.ActivitySkillEditBinding +import com.chwl.app.skill.repository.SkillModel +import com.chwl.app.ui.widget.dialog.CommonTipDialog +import com.chwl.library.annatation.ActLayoutRes + +@ActLayoutRes(R.layout.activity_skill_edit) +class EditSkillActivity : BaseBindingActivity() { + private lateinit var mDelegate: SkillEditableDelegate + private var deleteTipDialog: CommonTipDialog? = null + private var recordId = -1 + override fun init() { + mBinding.click = this + mDelegate = SkillEditableDelegate(this) + mDelegate.init() + recordId = intent?.getIntExtra(SkillEditableDelegate.RECORD_ID, -1) ?: -1 + if (recordId >= 0) { + loadData() + } + } + + override fun onClick(v: View) { + when (v.id) { + R.id.btn_delete -> showDeleteDialog() + R.id.btn_save -> { + mDelegate.saveSkill() + } + } + } + + override fun onLeftClickListener() { + mDelegate.onLeftClick() + } + + private fun showDeleteDialog() { + if (deleteTipDialog == null) { + deleteTipDialog = CommonTipDialog(this) + deleteTipDialog?.setTipMsg(resources.getString(R.string.tip_delete_skill)) + deleteTipDialog?.setOnActionListener(object : CommonTipDialog.OnActionListener { + override fun onOk() { + mDelegate.deleteSkill() + deleteTipDialog?.dismiss() + } + + override fun onCancel() { + deleteTipDialog?.dismiss() + } + }) + } + if (deleteTipDialog?.isShowing == true) { + deleteTipDialog?.dismiss() + } + deleteTipDialog?.show() + } + + + @SuppressLint("CheckResult") + private fun loadData() { + SkillModel.instance.getSkillDetailById(recordId) + .compose(bindToLifecycle()) + .doOnSubscribe { dialogManager.showProgressDialog(this) } + .subscribe({ + it.isSelf = true + it.isEdit = true + mDelegate.setSkillViewData(it) + dialogManager.dismissDialog() + }, { th -> + th.printStackTrace() + toast(th.message) + dialogManager.dismissDialog() + } + ) + } + + companion object { + fun start(context: Context, id: Int) { + val intent = Intent(context, EditSkillActivity::class.java) + intent.putExtra(SkillEditableDelegate.RECORD_ID, id) + context.startActivity(intent) + } + } + + override fun onBackPressed() { + mDelegate.onLeftClick() + } + + override fun needSteepStateBar() = true + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/skill/activity/SkillDetailActivity.kt b/app/src/main/java/com/chwl/app/skill/activity/SkillDetailActivity.kt new file mode 100644 index 0000000..77b22a6 --- /dev/null +++ b/app/src/main/java/com/chwl/app/skill/activity/SkillDetailActivity.kt @@ -0,0 +1,64 @@ +package com.chwl.app.skill.activity + +import android.annotation.SuppressLint +import android.content.Context +import android.content.Intent +import android.view.View +import com.netease.nim.uikit.StatusBarUtil +import com.chwl.app.R +import com.chwl.app.base.BaseBindingActivity +import com.chwl.app.databinding.ActivitySkillEditBinding +import com.chwl.app.skill.repository.SkillModel +import com.chwl.library.annatation.ActLayoutRes + +/** + * 客态显示 + */ +@ActLayoutRes(R.layout.activity_skill_edit) +class SkillDetailActivity : BaseBindingActivity() { + private lateinit var mDelegate: SkillEditableDelegate + private var recordId = -1 + override fun init() { + mDelegate = SkillEditableDelegate(this) + mDelegate.init() + mBinding.btnSave.visibility = View.GONE + mBinding.btnDelete.visibility = View.GONE + recordId = intent?.getIntExtra(SkillEditableDelegate.RECORD_ID, -1) ?: -1 + if (recordId >= 0) { + loadData() + } + } + + @SuppressLint("CheckResult") + private fun loadData() { + SkillModel.instance.getSkillDetailById(recordId) + .compose(bindToLifecycle()) + .doOnSubscribe { dialogManager.showProgressDialog(this) } + .subscribe({ + it.isSelf = false + it.isEdit = false + mDelegate.setSkillViewData(it) + dialogManager.dismissDialog() + }, { th -> + th.printStackTrace() + toast(th.message) + dialogManager.dismissDialog() + } + ) + } + + companion object { + fun start(context: Context, id: Int) { + val intent = Intent(context, SkillDetailActivity::class.java) + intent.putExtra(SkillEditableDelegate.RECORD_ID, id) + context.startActivity(intent) + } + } + + override fun needSteepStateBar() = true + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/skill/activity/SkillEditableDelegate.kt b/app/src/main/java/com/chwl/app/skill/activity/SkillEditableDelegate.kt new file mode 100644 index 0000000..a1fc56d --- /dev/null +++ b/app/src/main/java/com/chwl/app/skill/activity/SkillEditableDelegate.kt @@ -0,0 +1,90 @@ +package com.chwl.app.skill.activity + +import com.chwl.app.R +import com.chwl.app.base.BaseBindingActivity +import com.chwl.app.databinding.ActivitySkillEditBinding +import com.chwl.app.skill.SKillDataParser +import com.chwl.app.skill.SkillDataDelegate +import com.chwl.app.ui.widget.dialog.CommonTipDialog +import com.chwl.core.skill.entity.SkillPropertyEntity +import com.chwl.core.skill.entity.SkillRecordEntity +import com.chwl.library.utils.ResUtil + +/** + * 编辑-添加 界面 + */ +class SkillEditableDelegate( + private val activity: BaseBindingActivity +) { + internal fun init() { + activity.initTitleBar(ResUtil.getString(R.string.skill_activity_skilleditabledelegate_01)) + } + + private var saveTipDialog: CommonTipDialog = CommonTipDialog(activity) + + init { + saveTipDialog.setOkText(ResUtil.getString(R.string.skill_activity_skilleditabledelegate_02)) + saveTipDialog.setCancelText(ResUtil.getString(R.string.skill_activity_skilleditabledelegate_03)) + saveTipDialog.setTipMsg(activity.resources.getString(R.string.tip_save_skill)) + saveTipDialog.setOnActionListener(object : CommonTipDialog.OnActionListener { + override fun onOk() { + activity.finish() + saveTipDialog.dismiss() + } + + override fun onCancel() { + saveTipDialog.dismiss() + } + }) + } + + + internal fun onLeftClick() { + if (saveTipDialog.isShowing) { + saveTipDialog.dismiss() + } + saveTipDialog.show() + } + + /** + * 保存 添加 + */ + internal fun saveSkill() { + SkillDataDelegate(activity.mBinding.skillView, activity).saveSkill() + } + + /** + * 删除 + */ + internal fun deleteSkill() { + SkillDataDelegate(activity.mBinding.skillView, activity).deleteSkill(true) + } + + /** + * 记录 + */ + internal fun setSkillViewData(entity: SkillRecordEntity) { + val onItemCall = + if (entity.isEdit && entity.isSelf) + SkillDataDelegate(activity.mBinding.skillView, activity) + else null + val attr = SKillDataParser.parseSkillRecordToAttribute(entity, onItemCall) + activity.mBinding.skillView.initView(attr) + } + + /** + * 初值属性 + */ + internal fun setSkillViewData(entity: SkillPropertyEntity) { + val onItemCall = if (entity.isEdit && entity.isSelf) SkillDataDelegate( + activity.mBinding.skillView, + activity + ) else null + val attr = SKillDataParser.parseSkillPropertyToAttribute(entity, onItemCall) + activity.mBinding.skillView.initView(attr) + } + + companion object { + const val RECORD_ID = "record_id" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/skill/activity/SkillHomeActivity.kt b/app/src/main/java/com/chwl/app/skill/activity/SkillHomeActivity.kt new file mode 100644 index 0000000..4323e33 --- /dev/null +++ b/app/src/main/java/com/chwl/app/skill/activity/SkillHomeActivity.kt @@ -0,0 +1,178 @@ +package com.chwl.app.skill.activity + +import android.annotation.SuppressLint +import android.content.Context +import android.content.Intent +import android.view.Gravity +import android.view.View +import android.view.ViewGroup +import android.widget.FrameLayout +import android.widget.ImageView +import androidx.recyclerview.widget.LinearLayoutManager +import com.netease.nim.uikit.StatusBarUtil +import com.chwl.app.R +import com.chwl.app.base.BaseBindingActivity +import com.chwl.app.common.EmptyViewHelper +import com.chwl.app.databinding.ActivitySkillHomeBinding +import com.chwl.app.skill.adapter.MineSkillCardAdapter +import com.chwl.app.skill.decoration.SkillLinearVerticalDecoration +import com.chwl.app.skill.dialog.AddSkillCardDialog +import com.chwl.app.skill.repository.SkillDataManager +import com.chwl.app.skill.repository.SkillModel +import com.chwl.app.skill.widget.CARD_TYPE_AUDIO +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil +import com.chwl.core.skill.event.SkillEvent +import com.chwl.library.annatation.ActLayoutRes +import com.chwl.library.utils.ResUtil +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode + +@ActLayoutRes(R.layout.activity_skill_home) +class SkillHomeActivity : BaseBindingActivity() { + private lateinit var adapter: MineSkillCardAdapter + private var pageType = PAGE_TYPE_SELF //' 0 主态 + private var userId: Long = 0 + + @SuppressLint("CheckResult") + override fun init() { + initTitleBar(ResUtil.getString(R.string.skill_activity_skillhomeactivity_01)) + pageType = intent.getIntExtra(PAGE_TYPE, PAGE_TYPE_SELF) + userId = intent.getLongExtra(USER_ID, 0) + EventBus.getDefault().register(this) + mBinding.recyclerView.layoutManager = LinearLayoutManager(this) + adapter = MineSkillCardAdapter(pageType == PAGE_TYPE_SELF, this) + mBinding.recyclerView.adapter = adapter + mBinding.recyclerView.addItemDecoration(SkillLinearVerticalDecoration(this, 6, 16)) + adapter.setOnItemClickListener { _, _, position -> + if (pageType != PAGE_TYPE_SELF) return@setOnItemClickListener + val item = adapter.getItem(position) ?: return@setOnItemClickListener + if (item == null || item.type == CARD_TYPE_AUDIO) return@setOnItemClickListener + adapter.getItem(position)?.let { + EditSkillActivity.start(this, it.id) + } + } + if (pageType == PAGE_TYPE_SELF) { + adapter.addHeaderView(createHeaderView()) + } + mBinding.refreshLayout.setOnRefreshListener { + loadUserSkillList(userId) + } + mBinding.refreshLayout.isEnabled=false//禁用下拉刷新 + loadUserSkillList(userId) + } + + + @SuppressLint("CheckResult") + private fun loadUserSkillList(uid: Long) { + SkillModel.instance.getUserAllSkillCardDetail(uid) + .compose(bindToLifecycle()) + .doOnSubscribe { dialogManager.showProgressDialog(this) } + .subscribe( + { + if (mBinding.refreshLayout.isRefreshing) { + mBinding.refreshLayout.isRefreshing = false + } + if (pageType == PAGE_TYPE_SELF) { + adapter.setHeaderAndEmpty(true) + } + //这里没有做加载功能 + adapter.setNewData(it) + if (it.isEmpty()) { + adapter.setHeaderAndEmpty(false) + adapter.emptyView = createEmptyTextView() + } + dialogManager.dismissDialog() + }, + { th -> + th.printStackTrace() + toast(th.message) + mBinding.refreshLayout.isRefreshing = false + adapter.setHeaderAndEmpty(false) + adapter.emptyView = createEmptyTextView() + dialogManager.dismissDialog() + }) + + } + + private fun createEmptyTextView(): View { + if (pageType == PAGE_TYPE_CUSTOM) { + return EmptyViewHelper.createEmptyTextView(this, ResUtil.getString(R.string.skill_activity_skillhomeactivity_02)) + } + val rootView = FrameLayout(this) + rootView.layoutParams = + ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ) + rootView.background = resources.getDrawable(R.drawable.bg_skill_add) + val imageView = ImageView(this) + val height = UIUtil.dip2px(this, 50.0) + val width = UIUtil.dip2px(this, 50.0) + val imageParams = FrameLayout.LayoutParams(width, height) + imageParams.gravity = Gravity.CENTER + rootView.addView(imageView, imageParams) + rootView.setOnClickListener { + showAddableSkillDialog() + } + return rootView + } + + private fun createHeaderView(): View { + val height = UIUtil.dip2px(this, 64.0) + val view = View(this) + val params = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, height) + view.layoutParams = params + view.setBackgroundResource(R.drawable.ic_skill_add_header) + view.setOnClickListener { + showAddableSkillDialog() + } + return view + } + + @SuppressLint("CheckResult") + private fun showAddableSkillDialog() { + SkillModel.instance.getSkillTypeList() + .compose(bindToLifecycle()) + .subscribe({ it -> + val addDialog = AddSkillCardDialog(context, it) { + AddSkillActivity.start(this, it.cardId) + } + addDialog.openDialog() + }, { th -> + toast(th.message) + }) + } + + + companion object { + const val PAGE_TYPE = "page_type" + private const val USER_ID = "user_id" + const val PAGE_TYPE_SELF = 0 + const val PAGE_TYPE_CUSTOM = 1 + fun start(context: Context, pageType: Int, userId: Long) { + val intent = Intent(context, SkillHomeActivity::class.java) + intent.putExtra(PAGE_TYPE, pageType) + intent.putExtra(USER_ID, userId) + context.startActivity(intent) + } + } + + override fun onDestroy() { + EventBus.getDefault().unregister(this) + SkillDataManager.get().clear() + super.onDestroy() + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onDataChangedEvent(event: SkillEvent) { + loadUserSkillList(userId) + } + + override fun needSteepStateBar() = true + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/skill/adapter/AddSkillCardAdapter.kt b/app/src/main/java/com/chwl/app/skill/adapter/AddSkillCardAdapter.kt new file mode 100644 index 0000000..6e664d4 --- /dev/null +++ b/app/src/main/java/com/chwl/app/skill/adapter/AddSkillCardAdapter.kt @@ -0,0 +1,19 @@ +package com.chwl.app.skill.adapter + +import android.text.TextUtils +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.ui.utils.ImageLoadUtilsV2 +import com.chwl.core.skill.entity.SkillTypeEntity + +class AddSkillCardAdapter : + BaseQuickAdapter(R.layout.item_add_skill_select_card) { + override fun convert(helper: BaseViewHolder, item: SkillTypeEntity) { + helper.setGone(R.id.iv_icon, !TextUtils.isEmpty(item.icon)) + if (!TextUtils.isEmpty(item.icon)) { + ImageLoadUtilsV2.loadImage(helper.getView(R.id.iv_icon), item.icon) + } + helper.setText(R.id.tv_title, item.name) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/skill/adapter/MineSkillCardAdapter.kt b/app/src/main/java/com/chwl/app/skill/adapter/MineSkillCardAdapter.kt new file mode 100644 index 0000000..aa7711e --- /dev/null +++ b/app/src/main/java/com/chwl/app/skill/adapter/MineSkillCardAdapter.kt @@ -0,0 +1,38 @@ +package com.chwl.app.skill.adapter + +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.base.BaseActivity +import com.chwl.app.skill.SKillDataParser +import com.chwl.app.skill.SkillDataDelegate +import com.chwl.app.skill.widget.CARD_TYPE_AUDIO +import com.chwl.app.skill.widget.SkillCardView +import com.chwl.core.skill.entity.SkillRecordEntity + +/** + * 用户所有技能卡 显示 + */ +class MineSkillCardAdapter(private val isSelf: Boolean, private val activity: BaseActivity) : + BaseQuickAdapter(R.layout.item_mine_skill_card) { + override fun convert(helper: BaseViewHolder, item: SkillRecordEntity) { + val itemView = helper.itemView as SkillCardView + item.isEdit = false + when (item.type) { + CARD_TYPE_AUDIO -> { + //声音秀没有编辑选项 + item.isSelf = false + itemView.initView( + SKillDataParser.parseSkillRecordToAttribute( + item, + SkillDataDelegate(itemView, activity) + ) + ) + } + else -> { + item.isSelf = isSelf + itemView.initView(SKillDataParser.parseSkillRecordToAttribute(item)) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/skill/adapter/SkillSelectionAdapter.kt b/app/src/main/java/com/chwl/app/skill/adapter/SkillSelectionAdapter.kt new file mode 100644 index 0000000..7cea84a --- /dev/null +++ b/app/src/main/java/com/chwl/app/skill/adapter/SkillSelectionAdapter.kt @@ -0,0 +1,104 @@ +package com.chwl.app.skill.adapter + +import android.content.Context +import android.graphics.Color +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.skill.widget.ItemAttribute +import com.chwl.core.skill.entity.PropDictVo +import com.chwl.core.utils.extension.toast + + +class SkillSelectionAdapter( + private val context: Context, + private val itemState: Int, + private var maxSelectNumber: Int +) : + BaseQuickAdapter(R.layout.item_skill_selection) { + init { + //-1 不限制 + maxSelectNumber = + if (maxSelectNumber == 0 || maxSelectNumber == -1) Int.MAX_VALUE + else maxSelectNumber + } + + private var refreshByUser = false//标志是否是用户选择后刷新Adapter,在用户选择后设置为true + private var selectedCount = 0 + override fun convert(helper: BaseViewHolder, item: PropDictVo) { + helper.setText(R.id.tv_item, item.propVal) + helper.setBackgroundRes( + R.id.tv_item, + if (item.isSelected) R.drawable.bg_round_ffbc51_8 + else R.drawable.bg_f1f1fa_8 + ) + helper.setTextColor( + R.id.tv_item, + if (item.isSelected) Color.parseColor("#FFBC51") + else context.resources.getColor(R.color.color_333333) + ) + if (item.isSelected && !refreshByUser) { + selectedCount++ + } + } + + fun select(position: Int) { + refreshByUser = true + getItem(position)?.let { + when (itemState) { + //0 单选 1 输入 2多选 3 音频 4 音频时长 + ItemAttribute.STATE_SINGLE_CHOICE -> singleSelect(it) + ItemAttribute.STATE_MULTIPLE_CHOICE -> multiSelect(it) + } + } + notifyDataSetChanged() + } + + fun getSelectedItems(): List { + return data.filter { it.isSelected } + } + + private fun singleSelect(item: PropDictVo) { + data.forEach { it.isSelected = false } + selectedCount = 1 + item.isSelected = true + } + + private fun multiSelect(item: PropDictVo) { + item.isSelected = !item.isSelected + when (item.refIsOnlyCheck) { + 0 -> { + when (item.isSelected) { + false -> { + selectedCount-- + } + true -> { + selectedCount++ + if (selectedCount > maxSelectNumber) { + "最多只能选择${maxSelectNumber}项".toast() + selectedCount-- + item.isSelected = false + return + } else { + data.find { e -> e.refIsOnlyCheck == 1 }?.let { + if (it.isSelected) { + it.isSelected = false + selectedCount-- + } + } + } + } + } + } + 1 -> { + if (item.isSelected) { + data.forEach { that -> that.isSelected = false } + item.isSelected = true + selectedCount = 1 + } else { + selectedCount = 0 + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/skill/decoration/SkillGridDecoration.kt b/app/src/main/java/com/chwl/app/skill/decoration/SkillGridDecoration.kt new file mode 100644 index 0000000..dff5336 --- /dev/null +++ b/app/src/main/java/com/chwl/app/skill/decoration/SkillGridDecoration.kt @@ -0,0 +1,29 @@ +package com.chwl.app.skill.decoration + +import android.content.Context +import android.graphics.Rect +import android.view.View +import androidx.recyclerview.widget.RecyclerView +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil + +class SkillGridDecoration(context: Context, horizontalDp: Int, verticalDp: Int) : + RecyclerView.ItemDecoration() { + private val horizontalDp: Int = UIUtil.dip2px(context, horizontalDp.toDouble()) + private val verticalDp: Int = UIUtil.dip2px(context, verticalDp.toDouble()) + + override fun getItemOffsets( + outRect: Rect, + view: View, + parent: RecyclerView, + state: RecyclerView.State + ) { + super.getItemOffsets(outRect, view, parent, state) + val position = parent.getChildAdapterPosition(view) + if (position % 2 == 0) { + outRect.right = horizontalDp / 2 + } else { + outRect.left = horizontalDp / 2 + } + outRect.bottom=verticalDp + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/skill/decoration/SkillLinearVerticalDecoration.kt b/app/src/main/java/com/chwl/app/skill/decoration/SkillLinearVerticalDecoration.kt new file mode 100644 index 0000000..42a164b --- /dev/null +++ b/app/src/main/java/com/chwl/app/skill/decoration/SkillLinearVerticalDecoration.kt @@ -0,0 +1,36 @@ +package com.chwl.app.skill.decoration + +import android.content.Context +import android.graphics.Rect +import android.view.View +import androidx.recyclerview.widget.RecyclerView +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil + +class SkillLinearVerticalDecoration(context: Context, topSpaceDp: Int, bottomSpaceDp: Int) : + RecyclerView.ItemDecoration() { + private var topSpace = 0 + private var bottomSpace = 0 + + init { + topSpace = UIUtil.dip2px(context, topSpaceDp.toDouble()) + bottomSpace = UIUtil.dip2px(context, bottomSpaceDp.toDouble()) + } + + override fun getItemOffsets( + outRect: Rect, + view: View, + parent: RecyclerView, + state: RecyclerView.State + ) { + super.getItemOffsets(outRect, view, parent, state) + val position = parent.getChildAdapterPosition(view) + val childCount = parent.adapter?.itemCount?:0 + if (childCount == 1) return + if (position != childCount - 1) { + outRect.bottom = bottomSpace + } + if (position == 1) { + outRect.top = topSpace + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/skill/dialog/AddSkillCardDialog.kt b/app/src/main/java/com/chwl/app/skill/dialog/AddSkillCardDialog.kt new file mode 100644 index 0000000..039cdfd --- /dev/null +++ b/app/src/main/java/com/chwl/app/skill/dialog/AddSkillCardDialog.kt @@ -0,0 +1,45 @@ +package com.chwl.app.skill.dialog + +import android.content.Context +import android.view.Gravity +import android.view.View +import androidx.recyclerview.widget.GridLayoutManager +import com.chwl.app.R +import com.chwl.app.databinding.DialogAddSkillItemBinding +import com.chwl.app.skill.adapter.AddSkillCardAdapter +import com.chwl.app.skill.decoration.SkillGridDecoration +import com.chwl.app.base.BaseBindingDialog +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil +import com.chwl.core.skill.entity.SkillTypeEntity +import com.chwl.library.annatation.ActLayoutRes + +@ActLayoutRes(R.layout.dialog_add_skill_item) +class AddSkillCardDialog( + context: Context, + data: List, + var callback: (entity: SkillTypeEntity) -> Unit +) : + BaseBindingDialog(context) { + private val data: List + + init { + width = UIUtil.getScreenWidth(context) + height = UIUtil.dip2px(context, 366.0) + gravity = Gravity.BOTTOM + this.data = data + } + + private lateinit var adapter: AddSkillCardAdapter + override fun init() { + binding.btnEnsure.visibility = View.GONE + binding.recyclerView.layoutManager = GridLayoutManager(context, 2) + binding.recyclerView.addItemDecoration(SkillGridDecoration(context, 26, 15)) + adapter = AddSkillCardAdapter() + adapter.setOnItemClickListener { _, _, position -> + callback(adapter.getItem(position)!!)//能到这里肯定是点击了某个item ,肯定获取的是有效值 + closeDialog() + } + adapter.setNewData(data) + binding.recyclerView.adapter = adapter + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/skill/dialog/SkillSelectionDialog.kt b/app/src/main/java/com/chwl/app/skill/dialog/SkillSelectionDialog.kt new file mode 100644 index 0000000..0afc573 --- /dev/null +++ b/app/src/main/java/com/chwl/app/skill/dialog/SkillSelectionDialog.kt @@ -0,0 +1,43 @@ +package com.chwl.app.skill.dialog + +import android.content.Context +import android.view.Gravity +import android.view.View +import androidx.recyclerview.widget.GridLayoutManager +import com.chwl.app.R +import com.chwl.app.databinding.DialogAddSkillItemBinding +import com.chwl.app.skill.adapter.SkillSelectionAdapter +import com.chwl.app.skill.decoration.SkillGridDecoration +import com.chwl.app.base.BaseBindingDialog +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil +import com.chwl.core.skill.entity.PropDictVo +import com.chwl.core.skill.entity.PropsEntity +import com.chwl.library.annatation.ActLayoutRes + +@ActLayoutRes(R.layout.dialog_add_skill_item) +class SkillSelectionDialog( + context: Context, var item: PropsEntity?, + val callback: (value: List) -> Unit +) : + BaseBindingDialog(context) { + private lateinit var adapter: SkillSelectionAdapter + override fun init() { + width = UIUtil.getScreenWidth(context) + height = UIUtil.dip2px(context, 406.0) + gravity = Gravity.BOTTOM + binding.tvTitle.visibility = View.VISIBLE + binding.tvTitle.text = item?.propVal ?: "" + adapter = SkillSelectionAdapter(context, item?.state ?: 0,item?.checkLimitNum?:-1) + adapter.setOnItemClickListener { _, _, position -> + adapter.select(position) + } + binding.recyclerView.layoutManager = GridLayoutManager(context, 2) + binding.recyclerView.addItemDecoration(SkillGridDecoration(context, 30, 15)) + binding.recyclerView.adapter = adapter + adapter.setNewData(item?.propDictVos) + binding.btnEnsure.setOnClickListener { + callback.invoke(adapter.getSelectedItems()) + closeDialog() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/skill/repository/Api.kt b/app/src/main/java/com/chwl/app/skill/repository/Api.kt new file mode 100644 index 0000000..4d8cdea --- /dev/null +++ b/app/src/main/java/com/chwl/app/skill/repository/Api.kt @@ -0,0 +1,35 @@ +package com.chwl.app.skill.repository + +import com.google.gson.JsonElement +import com.chwl.core.bean.response.ServiceResult +import com.chwl.core.skill.entity.SkillPropertyEntity +import com.chwl.core.skill.entity.SkillRecordEntity +import com.chwl.core.skill.entity.SkillTypeEntity +import com.chwl.core.user.bean.UserInfoSkillEntity +import io.reactivex.Single +import okhttp3.RequestBody +import retrofit2.http.* + +interface Api { + @GET("/skillCard/getUserAllSkillCardDetail") + fun getUserAllSkillCardDetail(@Query("uid")uid:Long): Single>> + + @GET("/skillCard/getTypeList") + fun getSkillTypeList(): Single>> + + @GET("/skillCard/getCardInfoById") + fun getCardInfoById(@Query("cardId") cardId: String): Single> + + @Headers("Content-Type: application/json") + @POST("/skillCard/saveOrUpdate") + fun saveCardInfo(@Body body: RequestBody): Single> + + @POST("/skillCard/delete") + fun deleteSkill(@Query("id") id: String): Single> + + @GET("/skillCard/get") + fun getSkillDetailById(@Query("id") id: String): Single> + + @GET("/skillCard/cardList") + fun getUserInfoSkillList(@Query("uid")userId:Long): Single>> +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/skill/repository/ISkillModel.kt b/app/src/main/java/com/chwl/app/skill/repository/ISkillModel.kt new file mode 100644 index 0000000..79367f8 --- /dev/null +++ b/app/src/main/java/com/chwl/app/skill/repository/ISkillModel.kt @@ -0,0 +1,19 @@ +package com.chwl.app.skill.repository + +import com.chwl.core.skill.entity.SkillPostServerEntity +import com.chwl.core.skill.entity.SkillPropertyEntity +import com.chwl.core.skill.entity.SkillRecordEntity +import com.chwl.core.skill.entity.SkillTypeEntity +import com.chwl.core.user.bean.UserInfoSkillEntity +import io.reactivex.Single + + +interface ISkillModel { + fun getUserAllSkillCardDetail(uid:Long): Single> + fun getSkillTypeList(): Single> + fun getCardInfoById(id: Int): Single + fun saveSkillInfo(entity: SkillPostServerEntity): Single + fun deleteSkill(id: Int): Single + fun getSkillDetailById(id: Int): Single + fun getUserInfoSkillList(uid:Long): Single> +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/skill/repository/SkillDataManager.java b/app/src/main/java/com/chwl/app/skill/repository/SkillDataManager.java new file mode 100644 index 0000000..4d4395c --- /dev/null +++ b/app/src/main/java/com/chwl/app/skill/repository/SkillDataManager.java @@ -0,0 +1,31 @@ +package com.chwl.app.skill.repository; + + +import android.util.SparseArray; + +import com.chwl.core.skill.entity.SkillPropertyEntity; + +public class SkillDataManager { + private static final class Helper { + private static final SkillDataManager INSTANCE = new SkillDataManager(); + } + + public static SkillDataManager get() { + return Helper.INSTANCE; + } + + + private final SparseArray propertyCache = new SparseArray<>(); + + public SkillPropertyEntity getPropertyEntity(int cardId) { + return propertyCache.get(cardId); + } + + public void setSkillPropertyEntity(int cardId, SkillPropertyEntity entity) { + propertyCache.put(cardId, entity); + } + + public void clear() { + propertyCache.clear(); + } +} diff --git a/app/src/main/java/com/chwl/app/skill/repository/SkillModel.kt b/app/src/main/java/com/chwl/app/skill/repository/SkillModel.kt new file mode 100644 index 0000000..0878ce3 --- /dev/null +++ b/app/src/main/java/com/chwl/app/skill/repository/SkillModel.kt @@ -0,0 +1,59 @@ +package com.chwl.app.skill.repository + +import com.google.gson.Gson +import com.chwl.core.base.BaseModel +import com.chwl.core.skill.entity.SkillPostServerEntity +import com.chwl.core.skill.entity.SkillPropertyEntity +import com.chwl.core.skill.entity.SkillRecordEntity +import com.chwl.core.skill.entity.SkillTypeEntity +import com.chwl.core.user.bean.UserInfoSkillEntity +import com.chwl.core.utils.net.RxHelper +import com.chwl.library.net.rxnet.RxNet +import io.reactivex.Single +import okhttp3.MediaType.Companion.toMediaType +import okhttp3.RequestBody.Companion.toRequestBody + +class SkillModel : BaseModel(), ISkillModel { + private val api: Api = RxNet.create(Api::class.java) + override fun getUserAllSkillCardDetail(uid: Long): Single> = + api.getUserAllSkillCardDetail(uid).compose(RxHelper.handleCommon { + ArrayList(0) + }) + + override fun getSkillTypeList(): Single> { + return api.getSkillTypeList().compose(RxHelper.handleCommon { + ArrayList(0) + }) + } + + override fun getCardInfoById(id: Int): Single { + return api.getCardInfoById(id.toString()) + .compose(RxHelper.handleCommon()) + } + + override fun saveSkillInfo(entity: SkillPostServerEntity): Single { + val json = Gson().toJson(entity) + val requestBody = json.toRequestBody("Content-Type, application/json".toMediaType()) + return api.saveCardInfo(requestBody) + .compose(RxHelper.handleIgnoreData()) + } + + override fun deleteSkill(id: Int): Single { + return api.deleteSkill(id.toString()) + .compose(RxHelper.handleIgnoreData()) + } + + override fun getSkillDetailById(id: Int): Single { + return api.getSkillDetailById(id.toString()) + .compose(RxHelper.handleCommon()) + } + + override fun getUserInfoSkillList(uid: Long): Single> { + return api.getUserInfoSkillList(uid) + .compose(RxHelper.handleCommon { ArrayList(0) }) + } + + companion object { + val instance = SkillModel() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/skill/widget/EditItem.kt b/app/src/main/java/com/chwl/app/skill/widget/EditItem.kt new file mode 100644 index 0000000..87dc08a --- /dev/null +++ b/app/src/main/java/com/chwl/app/skill/widget/EditItem.kt @@ -0,0 +1,55 @@ +package com.chwl.app.skill.widget + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.widget.EditText +import android.widget.TextView +import com.chwl.app.R +import com.chwl.core.skill.entity.PropRefEntity +import com.chwl.core.utils.CoreTextUtils + +class EditItem(private val itemAttr: ItemAttribute) : SkillItem { + private lateinit var contentView: EditText + private lateinit var titleVIew: TextView + private fun initItem() { + if (isContentEditable()) { + SkillItemHelper.enableEdit(contentView) + } else { + SkillItemHelper.disableEdit(contentView) + contentView.setCompoundDrawables(null, null, null, null) + } + SkillItemHelper.setTitleText(titleVIew, itemAttr.parentVol, itemAttr.isMust) + itemAttr.selectedProperties.getOrNull(0)?.propVal?.let { contentView.setText(it) } + } + + override fun getContentEntity(): ItemAttribute { + itemAttr.selectedProperties.apply { + if (isEmpty()) { + val entity = PropRefEntity(itemAttr.parentId, null) + add(entity) + } + get(0).propVal = contentView.text.toString() + } + return itemAttr + } + + + override fun createItem(context: Context): View { + val view = LayoutInflater.from(context).inflate(R.layout.layout_skill_edit, null, false) + contentView = view.findViewById(R.id.edit_content) + titleVIew = view.findViewById(R.id.title_view) + initItem() + return view + } + + override fun invalidate() {} + + override fun isValid() = + if (itemAttr.isMust == 0) true else { + itemAttr.selectedProperties.isNotEmpty() && + !CoreTextUtils.isEmptyText(itemAttr.selectedProperties[0].propVal) + } + + private fun isContentEditable() = itemAttr.isSelf && itemAttr.editable +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/skill/widget/ItemAttribute.kt b/app/src/main/java/com/chwl/app/skill/widget/ItemAttribute.kt new file mode 100644 index 0000000..d865f5a --- /dev/null +++ b/app/src/main/java/com/chwl/app/skill/widget/ItemAttribute.kt @@ -0,0 +1,29 @@ +package com.chwl.app.skill.widget + +import com.chwl.core.skill.entity.PropRefEntity + +data class ItemAttribute( + val cardId: Int, + val isSelf: Boolean = false, + val editable: Boolean = false, + val state: Int = STATE_SINGLE_CHOICE,//0 单选 1 编辑 2 多选 3 音频 + val isMust: Int = 0, + val parentId: Int, + val parentVol: String, + val itemEventListener: ItemEventListener? = null, + var selectedProperties: MutableList + +) { + companion object { + const val STATE_SINGLE_CHOICE = 0 + const val STATE_EDIT = 1 + const val STATE_MULTIPLE_CHOICE = 2 + const val STATE_AUDIO = 3 + const val STATE_DURATION = 4 + } + + var audioDuration: String? = null + var audioStatus: Int = 0//声音秀审核状态 +} + + diff --git a/app/src/main/java/com/chwl/app/skill/widget/ItemEventListener.kt b/app/src/main/java/com/chwl/app/skill/widget/ItemEventListener.kt new file mode 100644 index 0000000..d510879 --- /dev/null +++ b/app/src/main/java/com/chwl/app/skill/widget/ItemEventListener.kt @@ -0,0 +1,9 @@ +package com.chwl.app.skill.widget + +import java.io.File + +interface ItemEventListener { + fun onItemClick(item: SkillItem) {} + fun onRecordSuccess(audioFile: File?, duration: Int) {} + fun onDeleteRecordClick() {} +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/skill/widget/RecordDurationItem.kt b/app/src/main/java/com/chwl/app/skill/widget/RecordDurationItem.kt new file mode 100644 index 0000000..7f238a1 --- /dev/null +++ b/app/src/main/java/com/chwl/app/skill/widget/RecordDurationItem.kt @@ -0,0 +1,21 @@ +package com.chwl.app.skill.widget + +import android.content.Context +import android.view.View +import android.view.ViewGroup +import android.widget.Space + +class RecordDurationItem(private val attr: ItemAttribute) : SkillItem { + override fun createItem(context: Context): View { + val view = Space(context) + val layoutParams = ViewGroup.LayoutParams(1, 1) + view.layoutParams = layoutParams + return view + } + + override fun invalidate() {} + + override fun isValid() = true + + override fun getContentEntity() = attr +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/skill/widget/RecordIResourceItem.kt b/app/src/main/java/com/chwl/app/skill/widget/RecordIResourceItem.kt new file mode 100644 index 0000000..f5f1425 --- /dev/null +++ b/app/src/main/java/com/chwl/app/skill/widget/RecordIResourceItem.kt @@ -0,0 +1,202 @@ +package com.chwl.app.skill.widget + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import com.netease.nim.uikit.common.util.sys.ScreenUtil +import com.netease.nimlib.sdk.media.record.RecordType +import com.chwl.app.R +import com.chwl.app.audio.helper.AudioPlayerHelper +import com.chwl.app.audio.helper.OnPlayListener +import com.chwl.app.databinding.LayoutSkillAudioBinding +import com.chwl.app.ui.widget.dialog.CommonTipDialog +import com.chwl.core.utils.CoreTextUtils +import com.chwl.core.utils.extension.toast +import com.chwl.library.utils.ResUtil +import java.io.File + +class RecordIResourceItem(private val itemAttribute: ItemAttribute) : SkillItem, + TimerRecorderView.RecordListener, View.OnClickListener { + private lateinit var binding: LayoutSkillAudioBinding + private lateinit var context: Context + private var audioLength = 0 + private var playState = PLAY_STATE_READY + + + //重新录制 + private val reStartTipDialog by lazy { + CommonTipDialog(context).apply { + itemAttribute + setTipMsg( + if (itemAttribute.audioStatus == RECORD_STATE_JUDGE) + ResUtil.getString(R.string.skill_widget_recordiresourceitem_01) + else ResUtil.getString(R.string.skill_widget_recordiresourceitem_02) + ) + setCancelText(ResUtil.getString(R.string.skill_widget_recordiresourceitem_03)) + setOkText(ResUtil.getString(R.string.skill_widget_recordiresourceitem_04)) + setBold(true) + setTextSize(ScreenUtil.dip2px(16f)) + setOnActionListener(object : CommonTipDialog.OnActionListener { + override fun onCancel() {} + override fun onOk() { + if (AudioPlayerHelper.get().isPlaying) { + stopAudio() + } + binding.recordState = RECORD_STATE_READY + } + }) + } + } + + //删除录制 + private val deleteTipDialog by lazy { + CommonTipDialog(context).apply { + setTipMsg(ResUtil.getString(R.string.skill_widget_recordiresourceitem_05)) + setCancelText(ResUtil.getString(R.string.skill_widget_recordiresourceitem_06)) + setBold(true) + setTextSize(ScreenUtil.dip2px(16f)) + setOkText(ResUtil.getString(R.string.skill_widget_recordiresourceitem_07)) + setOnActionListener(object : CommonTipDialog.OnActionListener { + override fun onCancel() { + if (AudioPlayerHelper.get().isPlaying) { + stopAudio() + } + itemAttribute.itemEventListener?.onDeleteRecordClick() + } + + override fun onOk() {} + }) + } + } + + override fun createItem(context: Context): View { + this.context = context + val inflater = LayoutInflater.from(context) + binding = LayoutSkillAudioBinding.inflate(inflater) + initItem() + return binding.root + } + + private fun initItem() { + binding.recordView.recordListener = this + binding.recordView.recordDuration = MAX_RECORD_DURATION + binding.recordState = itemAttribute.audioStatus + itemAttribute.audioDuration?.let { binding.duration = it } + binding.btnCancel.text = if (itemAttribute.isSelf) ResUtil.getString(R.string.skill_widget_recordiresourceitem_08) else ResUtil.getString(R.string.skill_widget_recordiresourceitem_09) + + binding.click = this + } + + override fun invalidate() {} + + override fun isValid() = true + + override fun getContentEntity() = itemAttribute + + override fun onRecordTimeUpdate(remain: Int) { + audioLength = binding.recordView.recordDuration - remain + } + + override fun onRecordStart(file: File?, recordType: RecordType?) { + binding.recordState = RECORD_STATE_RECORDING + } + + override fun onRecordCancel() { + //审核通过后 重新录制取消 要设置为之前审核通过的状态 + binding.recordState = itemAttribute.audioStatus + } + + override fun onRecordSuccess(file: File?) { + if (audioLength < 3) { + ResUtil.getString(R.string.skill_widget_recordiresourceitem_010).toast() + binding.recordState = RECORD_STATE_READY + return + } + itemAttribute.itemEventListener?.onRecordSuccess(file, audioLength) + } + + override fun onRecordFail() { + ResUtil.getString(R.string.skill_widget_recordiresourceitem_011).toast() + setItemByState(RECORD_STATE_READY) + } + + + /** + * 根据状态设置View + */ + fun setItemByState(state: Int) { + binding.recordState = state + } + + private fun playAudio(url: String?) { + if (playState == PLAY_STATE_PLAYING || CoreTextUtils.isEmptyText(url)) return + playState = PLAY_STATE_PLAYING + binding.palyState = playState + AudioPlayerHelper.get().playInThread(url, object : OnPlayListener { + override fun onError(error: String?) { + ResUtil.getString(R.string.skill_widget_recordiresourceitem_012).toast() + playState = PLAY_STATE_READY + binding.palyState = playState + } + + override fun onPrepared() {} + + override fun onPlaying(currDuration: Long) {} + + override fun onCompletion() { + playState = PLAY_STATE_READY + binding.palyState = playState + } + }) + } + + private fun stopAudio() { + if (playState == PLAY_STATE_READY) return + AudioPlayerHelper.get().endPlay() + playState = PLAY_STATE_READY + binding.palyState = playState + } + + + companion object { + //录制 + const val MAX_RECORD_DURATION = 15//最大录音时长 + const val RECORD_STATE_READY = 0//初态 即将录制 + const val RECORD_STATE_RECORDING = 5//正在录制 + const val RECORD_STATE_AGREE = 1//上传成功 审核通过 + const val RECORD_STATE_JUDGE = 2//上传成功 正在审核 + const val RECORD_STATE_REFUSE = 3//上传成功 审核不通过 + + //播放 + const val PLAY_STATE_PLAYING = 10 + const val PLAY_STATE_READY = 11//播放出错失败按完成处理,设置为初态 + } + + override fun onClick(v: View) { + when (v.id) { + R.id.btn_cancel -> { + binding.recordView.endAudioRecord(true) + } + R.id.tv_sound, R.id.iv_play -> { + if (playState == PLAY_STATE_READY) { + playAudio(itemAttribute.selectedProperties.getOrNull(0)?.propVal) + } else { + stopAudio() + } + } + R.id.btn_delete -> { + if (deleteTipDialog.isShowing) { + deleteTipDialog.dismiss() + } + deleteTipDialog.show() + } + + R.id.btn_restart -> { + if (reStartTipDialog.isShowing) { + reStartTipDialog.dismiss() + } + reStartTipDialog.show() + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/skill/widget/SelectionItem.kt b/app/src/main/java/com/chwl/app/skill/widget/SelectionItem.kt new file mode 100644 index 0000000..1fdeb00 --- /dev/null +++ b/app/src/main/java/com/chwl/app/skill/widget/SelectionItem.kt @@ -0,0 +1,58 @@ +package com.chwl.app.skill.widget + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.widget.TextView +import androidx.constraintlayout.widget.ConstraintLayout +import com.chwl.app.R +import com.chwl.core.utils.CoreTextUtils + +class SelectionItem(private val itemAttr: ItemAttribute) : SkillItem { + private lateinit var contentView: TextView + private lateinit var titleVIew: TextView + private lateinit var contentFrame: ConstraintLayout + override fun getContentEntity() = itemAttr + override fun createItem(context: Context): View { + val view = + LayoutInflater.from(context).inflate(R.layout.layout_skill_selection, null, false) + contentView = view.findViewById(R.id.edit_content) + titleVIew = view.findViewById(R.id.title_view) + contentFrame = view.findViewById(R.id.fl_content) + initItem() + return view + } + + private fun initItem() { + if (!isContentEditable()) { + contentView.setCompoundDrawables(null, null, null, null) + } else { + contentFrame.setOnClickListener { + itemAttr.itemEventListener?.onItemClick(this) + } + } + SkillItemHelper.setTitleText(titleVIew, itemAttr.parentVol, itemAttr.isMust) + setContent() + } + + private fun setContent() { + val builder = StringBuilder() + itemAttr.selectedProperties.forEach { + if (!CoreTextUtils.isEmptyText(it.propVal)) { + builder.append(it.propVal).append("、") + } + } + if (builder.isNotEmpty()) builder.deleteCharAt(builder.length - 1) + contentView.text = builder.toString() + builder.delete(0, builder.length) + } + + override fun invalidate() { + setContent() + } + + override fun isValid() = + itemAttr.isMust == 0 || itemAttr.selectedProperties.isNotEmpty() + + private fun isContentEditable() = itemAttr.isSelf && itemAttr.editable +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/skill/widget/SkillAttribute.kt b/app/src/main/java/com/chwl/app/skill/widget/SkillAttribute.kt new file mode 100644 index 0000000..57615dd --- /dev/null +++ b/app/src/main/java/com/chwl/app/skill/widget/SkillAttribute.kt @@ -0,0 +1,20 @@ +package com.chwl.app.skill.widget + +const val CARD_TYPE_GAME = 1 +const val CARD_TYPE_ART = 2 +const val CARD_TYPE_AUDIO = 3 + +data class SkillAttribute( + val id: Int, + val type: Int, + val cardId: Int, + val skillRes: String?, + val skillName: String, + val isSelf: Boolean = false, + val isEdit: Boolean = false, + val background: String?, + val itemAttributes: List +) { + var needBack = true + var needTitle = true +} diff --git a/app/src/main/java/com/chwl/app/skill/widget/SkillCardView.kt b/app/src/main/java/com/chwl/app/skill/widget/SkillCardView.kt new file mode 100644 index 0000000..9721737 --- /dev/null +++ b/app/src/main/java/com/chwl/app/skill/widget/SkillCardView.kt @@ -0,0 +1,135 @@ +package com.chwl.app.skill.widget + +import android.content.Context +import android.text.TextUtils +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import androidx.annotation.Nullable +import com.chwl.app.R +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.app.ui.utils.ImageLoadUtilsV2 +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil + +/** + * 技能卡 + */ +class SkillCardView( + context: Context, + @Nullable attrs: AttributeSet?, + defStyleAttr: Int +) : + LinearLayout(context, attrs, defStyleAttr) { + constructor(context: Context) : this(context, null) + constructor(context: Context, @Nullable attrs: AttributeSet?) : this(context, attrs, 0) + + private var itemList: MutableList = emptyList().toMutableList() + private lateinit var skillAttr: SkillAttribute + + init { + orientation = VERTICAL + } + + //标题 + private fun setSkillTitle(res: String?, skillTitle: String, isSelf: Boolean, isEdit: Boolean) { + val titleView = + LayoutInflater.from(context).inflate(R.layout.layout_skill_card_title, this, false) + titleView.findViewById(R.id.tv_title).text = skillTitle + titleView.findViewById(R.id.tv_edit).visibility = + if (isSelf && !isEdit) View.VISIBLE else View.GONE + val iconView = titleView.findViewById(R.id.iv_icon) + if (TextUtils.isEmpty(res)) { + iconView.visibility = View.GONE + } else { + ImageLoadUtilsV2.loadImage(iconView, res) + } + addView(titleView) + } + + //Item + private fun setChildItems() { + val layoutParams = LayoutParams( + LayoutParams.MATCH_PARENT, + LayoutParams.WRAP_CONTENT + ) + val lineHeight = UIUtil.dip2px(context, 0.5) + val lineMargin = UIUtil.dip2px(context, 16.0) + val lineParams = MarginLayoutParams(LayoutParams.MATCH_PARENT, lineHeight) + lineParams.leftMargin = lineMargin + lineParams.rightMargin = lineMargin + for ((index, item) in itemList.withIndex()) { + val itemView = item.createItem(context) + addView(itemView, layoutParams) + val state = item.getContentEntity().state + if (state == ItemAttribute.STATE_AUDIO || state == ItemAttribute.STATE_DURATION) { + continue + } + if (index != itemList.size - 1) { + val lineView = View(context) + lineView.setBackgroundColor(context.resources.getColor(R.color.color_F1F1FA)) + addView(lineView, lineParams) + } + } + } + + //根据state创建Item视图 + private fun createItemView(item: ItemAttribute): SkillItem { + return when (item.state) { + ItemAttribute.STATE_EDIT -> EditItem(item) + ItemAttribute.STATE_SINGLE_CHOICE, ItemAttribute.STATE_MULTIPLE_CHOICE -> SelectionItem( + item + ) + ItemAttribute.STATE_AUDIO -> RecordIResourceItem(item) + else -> RecordDurationItem(item) + } + } + + + //设置SkillView背景 + private fun setBackgroundImg(url: String?) { + if (TextUtils.isEmpty(url)) { + return + } + ImageLoadUtils.loadRoundBackground(context, url, this, 8, R.drawable.bg_corner_shadow_12) + } + + fun initView(attr: SkillAttribute) { + this.skillAttr = attr + itemList.clear() + attr.itemAttributes.forEach { + this.itemList.add(createItemView(it)) + } + //暂时处理 + SkillItemHelper.wrapAudio(attr) + if (attr.needBack) { + setBackgroundImg(attr.background) + } + removeAllViews() + if (attr.needTitle) { + setSkillTitle(attr.skillRes, attr.skillName, attr.isSelf, attr.isEdit) + } + setChildItems() + requestLayout() + } + + fun isValid(): Boolean { + if (!this::skillAttr.isInitialized) return false + var isValid = true + run outer@{ + itemList.forEach { + if (!it.isValid()) { + isValid = false + return@outer + } + } + } + return isValid + } + + fun getItems(): List = itemList + + fun getAttributes() = skillAttr +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/skill/widget/SkillItem.kt b/app/src/main/java/com/chwl/app/skill/widget/SkillItem.kt new file mode 100644 index 0000000..e6544af --- /dev/null +++ b/app/src/main/java/com/chwl/app/skill/widget/SkillItem.kt @@ -0,0 +1,11 @@ +package com.chwl.app.skill.widget + +import android.content.Context +import android.view.View + +interface SkillItem { + fun createItem(context: Context): View + fun invalidate() + fun isValid(): Boolean + fun getContentEntity(): ItemAttribute +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/skill/widget/SkillItemHelper.kt b/app/src/main/java/com/chwl/app/skill/widget/SkillItemHelper.kt new file mode 100644 index 0000000..7ba8865 --- /dev/null +++ b/app/src/main/java/com/chwl/app/skill/widget/SkillItemHelper.kt @@ -0,0 +1,58 @@ +package com.chwl.app.skill.widget + +import android.graphics.Color +import android.text.SpannableStringBuilder +import android.text.style.ForegroundColorSpan +import android.widget.EditText +import android.widget.TextView +import com.chwl.app.skill.widget.ItemAttribute.Companion.STATE_AUDIO +import com.chwl.app.skill.widget.ItemAttribute.Companion.STATE_DURATION + +object SkillItemHelper { + /** + * 设置Item标题 + */ + fun setTitleText(titleView: TextView, title: String, isMust: Int) { + if (isMust == 0) { + titleView.text = title + return + } + val spannableStringBuilder = SpannableStringBuilder(title) + val length = spannableStringBuilder.length + spannableStringBuilder.append("*") + spannableStringBuilder.setSpan( + ForegroundColorSpan(Color.parseColor("#FF2222")), + length, + spannableStringBuilder.length, + SpannableStringBuilder.SPAN_INCLUSIVE_EXCLUSIVE + ) + titleView.text = spannableStringBuilder + } + + /** + * 禁用EditText编辑 + */ + + fun disableEdit(contentView: EditText) { + contentView.isFocusableInTouchMode = false + contentView.isFocusable = false + contentView.isCursorVisible = false + } + + /** + * 启用EditText编辑 + */ + fun enableEdit(contentView: EditText) { + contentView.isFocusableInTouchMode = true + contentView.isFocusable = true + contentView.isCursorVisible = true + } + + fun wrapAudio(attr: SkillAttribute) { + if (attr.type == CARD_TYPE_AUDIO) { + val sourceItem = attr.itemAttributes.find { it.state == STATE_AUDIO } + val durationItem = attr.itemAttributes.find { it.state == STATE_DURATION } + sourceItem?.audioDuration = durationItem?.selectedProperties?.getOrNull(0)?.propVal + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/skill/widget/TimerRecorderView.kt b/app/src/main/java/com/chwl/app/skill/widget/TimerRecorderView.kt new file mode 100644 index 0000000..0cd062e --- /dev/null +++ b/app/src/main/java/com/chwl/app/skill/widget/TimerRecorderView.kt @@ -0,0 +1,179 @@ +package com.chwl.app.skill.widget + +import android.animation.ValueAnimator +import android.content.Context +import android.graphics.Canvas +import android.graphics.Paint +import android.graphics.RectF +import android.util.AttributeSet +import android.view.animation.LinearInterpolator +import androidx.annotation.Nullable +import androidx.appcompat.widget.AppCompatImageView +import com.netease.nim.uikit.impl.NimUIKitImpl +import com.netease.nimlib.sdk.media.record.AudioRecorder +import com.netease.nimlib.sdk.media.record.IAudioRecordCallback +import com.netease.nimlib.sdk.media.record.RecordType +import com.chwl.app.R +import java.io.File + +private const val STATE_PAUSED = 0 +private const val STATE_PLAYED = 1 + +class TimerRecorderView(context: Context, @Nullable attrs: AttributeSet?, defStyleAttr: Int) : + AppCompatImageView(context, attrs, defStyleAttr), IAudioRecordCallback { + + private var progressWidth = 0 + private var outerWidth = 0 + private var progressColor = 0 + private val progressPaint by lazy { + Paint(Paint.ANTI_ALIAS_FLAG) + } + private var state = STATE_PAUSED + private var animator: ValueAnimator? = null + private var animatedPercent = 0f + internal var recordDuration = 15 + private var audioMessageHelper: AudioRecorder? = null + + var recordListener: RecordListener? = null + + constructor(context: Context) : this(context, null) + + constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0) { + val array = context.obtainStyledAttributes(attrs, R.styleable.TimerRecorderView) + progressWidth = array.getDimension(R.styleable.TimerRecorderView_progressWidth, 0f).toInt() + outerWidth = array.getDimension(R.styleable.TimerRecorderView_outerWidth, 0f).toInt() + progressColor = array.getColor(R.styleable.TimerRecorderView_progressColor, 0).toInt() + progressPaint.style = Paint.Style.STROKE + progressPaint.strokeWidth = progressWidth.toFloat() + progressPaint.color = progressColor + array.recycle() + setOnClickListener { + when (state) { + STATE_PAUSED -> { + startRecord() + } + STATE_PLAYED -> { + endAudioRecord(false) + } + } + } + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + val width = MeasureSpec.getSize(widthMeasureSpec) + val height = MeasureSpec.getSize(heightMeasureSpec) + setMeasuredDimension(width, height) + } + + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + if (state == STATE_PLAYED) { + val rectF = RectF() + val swipe = animatedPercent * 360 + rectF.left = outerWidth.toFloat() + rectF.top = outerWidth.toFloat() + rectF.right = measuredWidth.toFloat() - outerWidth + rectF.bottom = measuredHeight.toFloat() - outerWidth + canvas.drawArc(rectF, -90f, swipe, false, progressPaint) + } + } + + + //开始录制 + private fun startRecord() { + if (audioMessageHelper == null) { + val options = NimUIKitImpl.getOptions() + options.audioRecordMaxTime = recordDuration + audioMessageHelper = AudioRecorder( + context, options.audioRecordType, + options.audioRecordMaxTime, this + ) + } + setImageResource(R.drawable.ic_skill_audio_recording) + audioMessageHelper!!.startRecord() + } + + /** + * 结束语音录制 + * + * @param cancel -- true 取消 重新录制 false 录制完成 + */ + fun endAudioRecord(cancel: Boolean) { + state = STATE_PAUSED + audioMessageHelper?.completeRecord(cancel) + setImageResource(R.drawable.ic_skill_audio_ready) + clearRecordAnim() + } + + + private fun playRecordAnim() { + animator = ValueAnimator.ofFloat(0f, 360f) + ?.apply { + duration = (recordDuration * 1000).toLong() + addUpdateListener { + animatedPercent = it.animatedFraction + recordListener?.onRecordTimeUpdate((recordDuration * (1 - animatedPercent)).toInt()) + invalidate() + } + interpolator = LinearInterpolator() + start() + } + } + + + private fun clearRecordAnim() { + animator?.let { + it.removeAllUpdateListeners() + if (it.isRunning) it.end() + } + animator = null + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + clearRecordAnim() + audioMessageHelper?.destroyAudioRecorder() + } + + override fun onRecordReady() {} + + override fun onRecordStart(audioFile: File?, recordType: RecordType?) { + state = STATE_PLAYED + playRecordAnim() + recordListener?.onRecordStart(audioFile, recordType) + } + + override fun onRecordSuccess(audioFile: File?, audioLength: Long, recordType: RecordType?) { + state = STATE_PAUSED + clearRecordAnim() + recordListener?.onRecordSuccess(audioFile) + } + + override fun onRecordFail() { + state = STATE_PAUSED + recordListener?.onRecordFail() + clearRecordAnim() + } + + override fun onRecordCancel() { + state = STATE_PAUSED + recordListener?.onRecordCancel() + clearRecordAnim() + } + + override fun onRecordReachedMaxTime(maxTime: Int) { + state = STATE_PAUSED + clearRecordAnim() + audioMessageHelper?.handleEndRecord(true, maxTime) + } + + interface RecordListener { + fun onRecordTimeUpdate(remain: Int) + fun onRecordStart(file: File?, recordType: RecordType?) + fun onRecordCancel() + fun onRecordSuccess(file: File?) + fun onRecordFail() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/star/DefAnimatorListener.kt b/app/src/main/java/com/chwl/app/star/DefAnimatorListener.kt new file mode 100644 index 0000000..3113cf5 --- /dev/null +++ b/app/src/main/java/com/chwl/app/star/DefAnimatorListener.kt @@ -0,0 +1,18 @@ +package com.chwl.app.star + +import android.animation.Animator +import android.animation.Animator.AnimatorListener + +abstract class DefAnimatorListener : AnimatorListener { + override fun onAnimationStart(animation: Animator) { + } + + override fun onAnimationEnd(animation: Animator) { + } + + override fun onAnimationCancel(animation: Animator) { + } + + override fun onAnimationRepeat(animation: Animator) { + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/star/SendGiftTipsDialog.kt b/app/src/main/java/com/chwl/app/star/SendGiftTipsDialog.kt new file mode 100644 index 0000000..b31b750 --- /dev/null +++ b/app/src/main/java/com/chwl/app/star/SendGiftTipsDialog.kt @@ -0,0 +1,71 @@ +package com.chwl.app.star + +import android.content.Context +import android.os.Bundle +import android.view.View +import android.widget.ImageView +import android.widget.TextView +import com.chwl.app.R +import com.chwl.app.ui.widget.dialog.BaseDialog +import com.chwl.library.common.util.SPUtils +import com.chwl.library.utils.TimeUtils + +class SendGiftTipsDialog(context: Context, val message: String, var goListener: Runnable?) : + BaseDialog(context, R.style.dialog) { + + private var checked = false + + companion object { + /** + * 是否需要提示 + */ + fun isNeedTips(): Boolean { + val time = SPUtils.getLong("star_send_gift_ignore_tips_time", 0) + return !TimeUtils.isSameDay(time, System.currentTimeMillis()) + } + + /** + * 忽略提示/不在提示(今天) + */ + private fun ignoreTips() { + SPUtils.putLong("star_send_gift_ignore_tips_time", System.currentTimeMillis()) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.star_send_gift_dialog) + findViewById(R.id.tv_message)?.text = message + findViewById(R.id.tv_cancel)?.setOnClickListener { + dismiss() + } + + findViewById(R.id.tv_ok)?.setOnClickListener { + goListener?.run() + dismiss() + } + + findViewById(R.id.layout_ignore_today)?.setOnClickListener { + checked = !checked + loadCheckBox() + } + loadCheckBox() + } + + private fun loadCheckBox() { + val view = findViewById(R.id.iv_ignore) + if (checked) { + view?.setImageResource(R.drawable.star_send_gift_checkbox_checked) + } else { + view?.setImageDrawable(null) + } + } + + override fun dismiss() { + super.dismiss() + if (checked) { + ignoreTips() + } + goListener = null + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/star/StarAdapter.kt b/app/src/main/java/com/chwl/app/star/StarAdapter.kt new file mode 100644 index 0000000..763cb83 --- /dev/null +++ b/app/src/main/java/com/chwl/app/star/StarAdapter.kt @@ -0,0 +1,28 @@ +package com.chwl.app.star + +import android.content.res.ColorStateList +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.ui.utils.loadAvatar +import com.chwl.core.home.bean.StarUser +import com.example.lib_utils.AppUtils +import com.example.lib_utils.ktx.getColorById +import com.google.android.material.imageview.ShapeableImageView + +class StarAdapter : BaseQuickAdapter(R.layout.star_item) { + private val maleColor = + ColorStateList.valueOf(AppUtils.getApp().getColorById(R.color.color_57CDFF)) + private val femaleColor = + ColorStateList.valueOf(AppUtils.getApp().getColorById(R.color.color_D667FF)) + + override fun convert(helper: BaseViewHolder, item: StarUser?) { + val imageView = helper.getView(R.id.iv_avatar) + if (item?.gender == 1) { + imageView.strokeColor = maleColor + } else { + imageView.strokeColor = femaleColor + } + imageView.loadAvatar(item?.avatar) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/star/StarFragment.kt b/app/src/main/java/com/chwl/app/star/StarFragment.kt new file mode 100644 index 0000000..fb06139 --- /dev/null +++ b/app/src/main/java/com/chwl/app/star/StarFragment.kt @@ -0,0 +1,355 @@ +package com.chwl.app.star + +import android.animation.Animator +import android.content.res.ColorStateList +import androidx.core.view.isVisible +import androidx.fragment.app.activityViewModels +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import com.chwl.app.MainTabContentView +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingFragment +import com.chwl.app.databinding.StarFragmentBinding +import com.chwl.app.support.FragmentVisibleStateHelper +import com.chwl.app.ui.im.avtivity.NimP2PMessageActivity +import com.chwl.app.ui.pay.ChargeActivity +import com.chwl.app.ui.utils.loadAvatar +import com.chwl.app.ui.utils.loadFromAssets +import com.chwl.app.view.layoutmanager.CenterSnapHelper +import com.chwl.app.view.layoutmanager.CircleLayoutManager +import com.chwl.app.view.layoutmanager.ScrollHelper +import com.chwl.core.gift.bean.GiftInfo +import com.chwl.core.home.bean.StarUser +import com.chwl.core.utils.net.BalanceNotEnoughExeption +import com.chwl.library.utils.ResUtil +import com.example.lib_utils.UiUtils +import com.example.lib_utils.ktx.getColorById +import com.example.lib_utils.ktx.singleClick +import com.opensource.svgaplayer.SVGADrawable +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.launch +import java.io.File + +class StarFragment : BaseViewBindingFragment(), MainTabContentView { + + private val viewModel: StarViewModel by activityViewModels() + + private val adapter = StarAdapter() + + private var animFile: File? = null + + private var currentUser: StarUser? = null + + override fun init() { + FragmentVisibleStateHelper(this).start { + onVisibleChanged(it) + } + initView() + initObserve() + viewModel.refreshList() + } + + private fun initView() { + initRecyclerView() + initAnimView() + + binding.ivClose.setOnClickListener { + hideUserPanel() + } + + binding.ivGift.setOnClickListener { + dialogManager.showProgressDialog(context) + viewModel.getGiftInfo() + } + + binding.ivRefresh.singleClick { + dialogManager.showProgressDialog(context) + viewModel.refreshList() + } + + binding.ivFollow.singleClick { + currentUser?.let { + dialogManager.showProgressDialog(context) + viewModel.follow(it) + } + } + + binding.ivChat.singleClick { + currentUser?.uid?.let { + NimP2PMessageActivity.start(context, it.toString()) + } + } + } + + private fun initObserve() { + viewModel.starUserLiveData.observe(this) { + dialogManager.dismissDialog() + if (adapter.data.isNotEmpty() && it.isNullOrEmpty()) { + return@observe + } + adapter.setNewData(it) + } + + lifecycleScope.launch { + lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { + viewModel.giftInfoFlow.collectLatest { + val user = currentUser ?: return@collectLatest + val gift = it.data + if (it.isSuccess && gift != null) { + if (showSendGiftDialog(gift, user)) { + dialogManager.dismissDialog() + } + } else { + dialogManager.dismissDialog() + if (it.code == BalanceNotEnoughExeption.code) { + showBalanceNotEnoughDialog() + } else { + it.message?.let { msg -> + toast(msg) + } + } + } + } + } + } + lifecycleScope.launch { + lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { + viewModel.sendGiftFlow.collectLatest { + dialogManager.dismissDialog() + if (it.isSuccess) { + toast(R.string.decoration_helper_decorationdialoghelper_010) + currentUser?.uid?.let { uid -> + NimP2PMessageActivity.start(context, uid.toString()) + } + } else { + if (it.code == BalanceNotEnoughExeption.code) { + showBalanceNotEnoughDialog() + } else { + it.message?.let { msg -> + toast(msg) + } + } + } + } + } + } + lifecycleScope.launch { + lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { + viewModel.followFlow.collectLatest { result -> + dialogManager.dismissDialog() + if (result.isSuccess) { + if (currentUser == result.data) { + currentUser?.let { + loadUserFollowState(it) + } + } + } else if (result.message != null) { + toast(result.message) + } + } + } + } + } + + private fun initRecyclerView() { + val layoutManager = CircleLayoutManager(context) + layoutManager.infinite = true + layoutManager.angleRotate = false + layoutManager.gravity = if (UiUtils.isRtl(requireContext())) { + CircleLayoutManager.RIGHT + } else { + CircleLayoutManager.LEFT + } + layoutManager.minRemoveAngle = -120f + layoutManager.maxRemoveAngle = 120f + layoutManager.moveSpeed = 0.12f + CenterSnapHelper().attachToRecyclerView(binding.recyclerView) + binding.recyclerView.post { + val width = binding.recyclerView.width + layoutManager.radius = (width * 0.6).toInt() + layoutManager.angleInterval = 20 + layoutManager.distanceToBottom = if (UiUtils.isRtl(requireContext())) { + (width * 0.54f).toInt() + } else { + (width * 0.3f).toInt() + } + } + binding.recyclerView.layoutManager = layoutManager + adapter.setOnItemClickListener { adapter, view, position -> + ScrollHelper.smoothScrollToTargetView(binding.recyclerView, view) + (adapter.getItem(position) as? StarUser)?.let { + showUserPanel(it) + } + } + binding.recyclerView.adapter = adapter + } + + private fun initAnimView() { + binding.animView.setLoop(Int.MAX_VALUE) + lifecycleScope.launchWhenResumed { + animFile = viewModel.loadMp4File() + animFile?.let { + if (binding.animView.isVisible) { + binding.animView.startPlay(it) + } + } + } + } + + private fun showUserPanel(user: StarUser) { + binding.recyclerView.disableTouchMove() + binding.recyclerView.pause() + currentUser = user + loadUserPanelLeft(user) + loadUserPanelRight(user) + val rtl = if (UiUtils.isRtl(requireContext())) { + -1f + } else { + 1f + } + binding.layoutUserPanelRight.translationX = + binding.layoutUserPanelRight.width.toFloat() * rtl + binding.layoutUserPanelLeft.alpha = 0f + binding.layoutUserPanelLeft.translationX = binding.layoutUserPanelLeft.width * -0.1f * rtl + binding.layoutUserPanelRight.isVisible = true + binding.layoutUserPanelLeft.isVisible = true + switchGiftAnimState(true) + binding.layoutUserPanelRight.animate().translationX(0f) + .setListener(object : DefAnimatorListener() {}).start() + binding.animView.animate().translationX(-binding.animView.width.toFloat() * rtl) + .scaleX(0f).scaleY(0f).alpha(0f).setListener(object : DefAnimatorListener() { + override fun onAnimationEnd(p0: Animator) { + switchStarAnimState(false) + binding.ivRefresh.isVisible = false + binding.animView.isVisible = false + } + }).start() + binding.layoutUserPanelLeft.animate().translationX(0f).alpha(1f) + .setListener(object : DefAnimatorListener() {}).start() + } + + private fun loadUserPanelRight(user: StarUser) { + binding.ivUserAvatar.loadAvatar(user.avatar) + if (user.gender == 1) { + binding.ivUserAvatar.strokeColor = + ColorStateList.valueOf(binding.ivUserAvatar.context.getColorById(R.color.color_57CDFF)) + } else { + binding.ivUserAvatar.strokeColor = + ColorStateList.valueOf(binding.ivUserAvatar.context.getColorById(R.color.color_D667FF)) + } + } + + private fun loadUserPanelLeft(user: StarUser) { + binding.tvUserName.text = user.nick + binding.tvUserDesc.text = user.userDesc + loadUserFollowState(user) + } + + private fun loadUserFollowState(user: StarUser) { + if (user.hasLike == true) { + binding.ivFollow.setImageResource(R.drawable.star_ic_followed) + } else { + binding.ivFollow.setImageResource(R.drawable.star_ic_unfollowed) + } + } + + private fun hideUserPanel() { + binding.recyclerView.enableTouchMove() + binding.recyclerView.start() + currentUser = null + binding.ivRefresh.isVisible = true + binding.animView.isVisible = true + switchStarAnimState(true) + val rtl = if (UiUtils.isRtl(requireContext())) { + -1f + } else { + 1f + } + binding.animView.animate().alpha(1f).translationX(0f).scaleX(1f).scaleY(1f) + .setListener(object : DefAnimatorListener() {}).start() + binding.layoutUserPanelRight.animate() + .translationX(binding.layoutUserPanelRight.width.toFloat() * rtl) + .setListener(object : DefAnimatorListener() { + override fun onAnimationEnd(p0: Animator) { + switchGiftAnimState(false) + binding.layoutUserPanelRight.isVisible = false + } + }).start() + binding.layoutUserPanelLeft.animate() + .translationX(binding.layoutUserPanelLeft.width * -0.1f * rtl) + .alpha(0f).setListener(object : DefAnimatorListener() { + + override fun onAnimationEnd(p0: Animator) { + binding.layoutUserPanelLeft.isVisible = false + } + }).start() + } + + private fun showSendGiftDialog(gift: GiftInfo, user: StarUser): Boolean { + val next = { + dialogManager.showProgressDialog(context) + viewModel.sendGift(user.uid ?: 0) + } + if (SendGiftTipsDialog.isNeedTips()) { + var message = ResUtil.getString(R.string.star_send_gift_tips) + message = message.format(gift.giftName ?: "", gift.goldPrice.toString()) + SendGiftTipsDialog(requireContext(), message) { + next.invoke() + }.show() + return true + } else { + next.invoke() + return false + } + } + + private fun showBalanceNotEnoughDialog() { + dialogManager.showOkCancelDialog( + ResUtil.getString(R.string.widget_dialog_dialoguihelper_04), + ResUtil.getString(R.string.treasure_to_charge) + ) { + ChargeActivity.start(context) + } + } + + private fun switchStarAnimState(play: Boolean) { + if (play) { + animFile?.let { + binding.animView.startPlay(it) + } + } else { + binding.animView.stopPlay() + } + } + + private fun switchGiftAnimState(play: Boolean) { + if (play) { + if ((binding.ivGift.drawable as? SVGADrawable) == null) { + binding.ivGift.loadFromAssets("svga/home_star_gift.svga") + } else { + binding.ivGift.startAnimation() + } + } else { + binding.ivGift.pauseAnimation() + } + } + + private fun onVisibleChanged(isVisible: Boolean) { + if (isVisible) { + if (binding.ivGift.isVisible) { + switchGiftAnimState(true) + } + if (binding.animView.isVisible) { + switchStarAnimState(true) + } + if (!binding.layoutUserPanelRight.isVisible) { + binding.recyclerView.start() + } + } else { + binding.recyclerView.pause() + switchStarAnimState(false) + switchGiftAnimState(false) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/star/StarViewModel.kt b/app/src/main/java/com/chwl/app/star/StarViewModel.kt new file mode 100644 index 0000000..f642396 --- /dev/null +++ b/app/src/main/java/com/chwl/app/star/StarViewModel.kt @@ -0,0 +1,121 @@ +package com.chwl.app.star + +import android.content.Context +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.viewModelScope +import com.chwl.app.base.BaseViewModel +import com.chwl.core.bean.response.BeanResult +import com.chwl.core.gift.GiftModel +import com.chwl.core.gift.bean.GiftInfo +import com.chwl.core.home.bean.StarUser +import com.chwl.core.home.model.HomeModel +import com.chwl.core.praise.PraiseModel +import com.chwl.core.utils.extension.toast +import com.chwl.library.common.file.FileHelper +import com.example.lib_utils.AppUtils +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.launch +import java.io.File + +class StarViewModel : BaseViewModel() { + + private var starUserListPage = 1 + + val starUserLiveData = MutableLiveData>(listOf()) + + val followFlow = MutableSharedFlow>() + + val giftInfoFlow = MutableSharedFlow>() + + val sendGiftFlow = MutableSharedFlow>() + + fun refreshList() { + safeLaunch( + onError = { + starUserLiveData.value = emptyList() + it.message.toast() + }, + block = { + val pageSize = 20 + val result = HomeModel.getStarUserList(starUserListPage, pageSize) + if (!result.isNullOrEmpty()) { + if (result.size < pageSize) { + starUserListPage = 1 + } else { + starUserListPage++ + } + starUserLiveData.value = result ?: emptyList() + } else { + starUserListPage = 1 + starUserLiveData.value = emptyList() + } + } + ) + } + + suspend fun loadMp4File(): File? { + try { + val fileDir = getMp4FileDir(AppUtils.getApp()) + val fileName = "mp4/home_star.mp4" + if (FileHelper.copyFileFromAssets(fileDir, fileName, false)) { + return File(fileDir, fileName) + } + } catch (e: Exception) { + e.printStackTrace() + } + return null + } + + private fun getMp4FileDir(context: Context): String { + var dir: String + try { + dir = context.getExternalFilesDir(null)?.absolutePath ?: "" + if (dir.isEmpty()) { + dir = context.filesDir.absolutePath + } + } catch (e: Exception) { + dir = context.filesDir.absolutePath + } + return dir + } + + fun follow(starUser: StarUser) { + val like = !(starUser.hasLike ?: false) + addDisposable( + PraiseModel.get().praise(starUser.uid ?: 0, !(starUser.hasLike ?: false)).subscribe({ + viewModelScope.launch { + starUser.hasLike = like + followFlow.emit(BeanResult.success(starUser)) + } + }, { + viewModelScope.launch { + followFlow.emit(BeanResult.failed(it)) + } + }) + ) + } + + fun getGiftInfo() { + addDisposable(GiftModel.get().specialGift.subscribe({ + viewModelScope.launch { + giftInfoFlow.emit(BeanResult.success(it)) + } + }, { + viewModelScope.launch { + giftInfoFlow.emit(BeanResult.failed(it)) + } + })) + } + + fun sendGift(uid: Long) { + addDisposable(GiftModel.get().sendSpecialGift(uid).subscribe({ + viewModelScope.launch { + sendGiftFlow.emit(BeanResult.success(it)) + } + }, { + viewModelScope.launch { + sendGiftFlow.emit(BeanResult.failed(it)) + } + })) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/support/FragmentVisibleStateHelper.kt b/app/src/main/java/com/chwl/app/support/FragmentVisibleStateHelper.kt new file mode 100644 index 0000000..e29699a --- /dev/null +++ b/app/src/main/java/com/chwl/app/support/FragmentVisibleStateHelper.kt @@ -0,0 +1,57 @@ +package com.chwl.app.support + +import androidx.core.util.Consumer +import androidx.fragment.app.Fragment +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleEventObserver +import androidx.lifecycle.LifecycleOwner +import com.chwl.app.base.BaseFragment + +class FragmentVisibleStateHelper( + private val fragment: Fragment +) : LifecycleEventObserver { + private var onVisibleChanged: ((Boolean) -> Unit)? = null + private var isRealVisible = false + private var visibleCount = 0 + val isVisible get() = isRealVisible + val isFirstVisible get() = isVisible && visibleCount == 1 + + fun start(onVisibleChanged: (Boolean) -> Unit): FragmentVisibleStateHelper { + this.onVisibleChanged = onVisibleChanged + fragment.lifecycle.addObserver(this) + (fragment as? BaseFragment)?.let { + it.onHiddenChangedListener = Consumer { + checkVisibleState() + } + } + return this + } + + fun checkVisibleState() { + val newRealVisible = + fragment.isAdded && !fragment.isHidden && fragment.lifecycle.currentState.isAtLeast( + Lifecycle.State.RESUMED + ) + if (isRealVisible != newRealVisible) { + isRealVisible = newRealVisible + if (newRealVisible) { + visibleCount++ + } + onVisibleChanged(newRealVisible) + } + } + + private fun onVisibleChanged(isVisible: Boolean) { + onVisibleChanged?.invoke(isVisible) + } + + override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) { + if (event == Lifecycle.Event.ON_RESUME) { + checkVisibleState() + } else if (event == Lifecycle.Event.ON_PAUSE) { + checkVisibleState() + } else if (event == Lifecycle.Event.ON_DESTROY) { + fragment.lifecycle.removeObserver(this) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/support/IMUserInfoProvider.kt b/app/src/main/java/com/chwl/app/support/IMUserInfoProvider.kt new file mode 100644 index 0000000..e4bbd31 --- /dev/null +++ b/app/src/main/java/com/chwl/app/support/IMUserInfoProvider.kt @@ -0,0 +1,26 @@ +package com.chwl.app.support + +import com.chwl.core.settings.SettingsModel +import com.netease.nim.uikit.impl.provider.DefaultUserInfoProvider + +class IMUserInfoProvider : DefaultUserInfoProvider() { + override fun getUserAvatar(account: String?): String? { + if (account == null) { + return null + } + val sysAccount = SettingsModel.get().localSysAccount + return when (account) { + sysAccount.secretaryUid -> { + "https://img.molistar.xyz/secret_message_avatar_molistar.png" + } + + sysAccount.hallMessageUid -> { + "https://img.molistar.xyz/hall_message_avatar_molistar.png" + } + + else -> { + super.getUserAvatar(account) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/support/PreloadResourceViewModel.kt b/app/src/main/java/com/chwl/app/support/PreloadResourceViewModel.kt new file mode 100644 index 0000000..b772aef --- /dev/null +++ b/app/src/main/java/com/chwl/app/support/PreloadResourceViewModel.kt @@ -0,0 +1,202 @@ +package com.chwl.app.support + +import android.annotation.SuppressLint +import android.content.Context +import androidx.lifecycle.viewModelScope +import com.bumptech.glide.load.DataSource +import com.bumptech.glide.load.engine.GlideException +import com.bumptech.glide.request.RequestListener +import com.bumptech.glide.request.target.Target +import com.chwl.app.base.BaseViewModel +import com.chwl.core.home.model.HomeModel +import com.chwl.core.utils.LogUtils +import com.chwl.library.common.glide.GlideUtils +import com.chwl.library.common.util.SPUtils +import com.chwl.library.utils.NetworkUtils +import com.chwl.library.utils.PathHelper +import com.example.lib_utils.AppUtils +import com.example.lib_utils.BuildConfig +import com.example.lib_utils.FileUtils2 +import com.example.lib_utils.log.ILog +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import java.io.File + +@SuppressLint("StaticFieldLeak") +class PreloadResourceViewModel : BaseViewModel(), ILog , RequestListener { + + private val DOWNLOAD_TAG = "RESOURCE_DOWNLOAD_TAG" + + private var preloadResourceList: MutableList? = null + + private var isStarted = false + + private var mContext : Context? = null + + private var mPreLoadJob : Job? = null + + //todo 预加载 + fun start(context: Context) { + mContext = context + + if (BuildConfig.DEBUG) { + // 太多请求了,影响查看控制台日志 + return + } + + if (isStarted) { + return + } + + mPreLoadJob = viewModelScope?.launch(Dispatchers.IO) { + getPreloadResourceList { + isStarted = true + nextTask(null) + } + } + mPreLoadJob?.start() + } + + fun stopPreLoad() { + mContext = null + mPreLoadJob?.cancel() + } + + private fun getPreloadResourceList(block: suspend CoroutineScope.() -> Unit) { + logI("getPreloadResourceList()") + safeLaunch(false, onError = { + logI("getPreloadResourceList() onError:${it.message}") + it.printStackTrace() + }) { + val set = getDownloadRecord() + logI("getPreloadResourceList() set:${set.size}") + preloadResourceList = HomeModel.getEffectResourceList()?.filter { + if (it.isEmpty()) { + return@filter false + } + if (set.contains(it)) { + val path = PathHelper.generateResourcesFilePath(it) + if (FileUtils2.isFileExists(path)) { + return@filter false + } + } + return@filter true + }?.toMutableList() + logI("getPreloadResourceList() it:${preloadResourceList?.size}") + block.invoke(this) + } + } + + private fun nextTask(lastTaskUrl: String? = null) { + logI("nextTask() lastTaskUrl:${lastTaskUrl} preloadResourceList:${preloadResourceList?.size}") + if (lastTaskUrl != null) { + preloadResourceList?.removeAll { + it == lastTaskUrl + } + } + if (!isWifiNet()) { + logI("nextTask() isWifiNet==false") + delayLoopTask() + return + } + logI("nextTask() preloadResourceList:${preloadResourceList?.size}") + preloadResourceList?.firstOrNull()?.let { + downloadTask(it) + } + } + + private fun downloadTask(url: String?) { + +// val path = PathHelper.generateResourcesFilePath(url) +// logI("downloadTask() url:${url} path:${path}") +// val request = DownloadRequest.build( +// url = url, +// path = path, +// tag = DOWNLOAD_TAG, +// header = null, +// timeout = null +// ) +// DownloadManager.download(request, this) + + viewModelScope.launch { + delay(500) + LogUtils.d("预加载 -> downloadTask url = ${url?.trim()}") + if (url != null) { + GlideUtils.instance().downloadFromUrl2(mContext,url.trim(),this@PreloadResourceViewModel) + } + } + } + + override fun onLoadFailed( + e: GlideException?, + model: Any?, + target: Target?, + isFirstResource: Boolean + ): Boolean { + if (model is String) { + logI("onDownloadError() url:${model} message:${e?.message}") + nextTask(model) + } + LogUtils.d("预加载 onLoadFailed 失败 url = ${model}") + return true + } + + override fun onResourceReady( + resource: File?, + model: Any?, + target: Target?, + dataSource: DataSource?, + isFirstResource: Boolean + ): Boolean { + if (model is String) { + logI("onDownloadCompleted() url:${model} path:${resource?.path}") + makeDownloadRecord(model) + nextTask(null) + } + LogUtils.d("预加载 onResourceReady 成功 url = ${model}") + return true + } + + + private fun isWifiNet(): Boolean { + return getNetType() == NetworkUtils.NET_WIFI + } + + private fun isNetAvailable(): Boolean { + return NetworkUtils.isNetworkStrictlyAvailable(AppUtils.getApp()) + } + + private fun getNetType(): Int { + return NetworkUtils.getNetworkType(AppUtils.getApp()) + } + + private fun delayLoopTask() { + logI( + "delayLoopTask()" + ) + viewModelScope.launch { + delay(10000) + nextTask(null) + } + } + + private fun getDownloadRecord(): MutableSet { + return SPUtils.getStringSet("RESOURCE_DOWNLOAD_COMPLETE", setOf()).toMutableSet() + } + + private fun makeDownloadRecord(url: String) { + val set = getDownloadRecord() + set.add(url) + SPUtils.putStringSet("RESOURCE_DOWNLOAD_COMPLETE", set) + preloadResourceList?.remove(url) + } + + override fun onCleared() { + super.onCleared() + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/support/float/BaseFloatView.kt b/app/src/main/java/com/chwl/app/support/float/BaseFloatView.kt new file mode 100644 index 0000000..b90b1f8 --- /dev/null +++ b/app/src/main/java/com/chwl/app/support/float/BaseFloatView.kt @@ -0,0 +1,91 @@ +package com.chwl.app.support.float + +import android.content.Context +import android.util.AttributeSet +import android.view.View +import android.view.animation.Animation +import android.view.animation.AnimationUtils +import androidx.annotation.CallSuper +import androidx.constraintlayout.widget.ConstraintLayout +import com.chwl.app.R + + +abstract class BaseFloatView : ConstraintLayout, FloatView { + private var window: FloatWindow? = null + + constructor(context: Context) : super(context) + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) + + constructor( + context: Context, + attrs: AttributeSet?, + defStyleAttr: Int, + defStyleRes: Int + ) : super(context, attrs, defStyleAttr, defStyleRes) + + @CallSuper + override fun onAttached(window: FloatWindow, item: Any) { + this.window = window + onBind(item) + } + + @CallSuper + override fun onDetached() { + this.window = null + } + + protected fun requestRemoveSelf(): Boolean { + if (this.window == null) { + return false + } else { + post { + this.window?.removeChild(this) + } + return true + } + } + + abstract fun onBind(item: Any) + + override fun getView(): View { + return this + } + + + protected open fun startEnterAnim() { + val inAnimation = AnimationUtils.loadAnimation(context, R.anim.anim_right_in) + this.startAnimation(inAnimation) + } + + var run : Runnable ? = null + protected open fun startDelayRemove(delayMillis: Long = 5000) { + run = object : Runnable { + override fun run() { + val outAnimation = AnimationUtils.loadAnimation(context, R.anim.anim_left_out) + outAnimation.setAnimationListener(object : Animation.AnimationListener { + override fun onAnimationStart(animation: Animation?) { + } + + override fun onAnimationEnd(animation: Animation?) { + requestRemoveSelf() + } + + override fun onAnimationRepeat(animation: Animation?) { + } + }) + this@BaseFloatView.startAnimation(outAnimation) + } + } + postDelayed(run, delayMillis) + } + + override fun onDetachedFromWindow() { + removeCallbacks(run) + super.onDetachedFromWindow() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/support/float/DoubleQueue.kt b/app/src/main/java/com/chwl/app/support/float/DoubleQueue.kt new file mode 100644 index 0000000..931208c --- /dev/null +++ b/app/src/main/java/com/chwl/app/support/float/DoubleQueue.kt @@ -0,0 +1,62 @@ +package com.chwl.app.support.float + +import com.example.lib_utils.log.ILog + + +open class DoubleQueue( + val queueA: FloatQueue, + val queueB: FloatQueue +) : FloatQueue, FloatQueue.QueueObserver, ILog { + + private val queueObservable = FloatQueue.QueueObservable() + + override fun pollFirst(): QueueItem? { + return getFirstQueue()?.pollFirst() + } + + override fun peekFirst(): QueueItem? { + return getFirstQueue()?.peekFirst() + } + + protected open fun getFirstQueue(): FloatQueue? { + val itemA = queueA.peekFirst() + val itemB = queueB.peekFirst() + if (itemA != null && itemB != null) { + if (itemA.time <= itemB.time) { + return queueA + } else { + return queueB + } + } + if (itemA != null) { + return queueA + } + if (itemB != null) { + return queueB + } + return null + } + + override fun addLast(data: Any) { + } + + override fun registerObserver(observer: FloatQueue.QueueObserver) { + queueObservable.registerObserver(observer) + if (queueObservable.getCount() == 1) { + queueA.registerObserver(this) + queueB.registerObserver(this) + } + } + + override fun unregisterObserver(observer: FloatQueue.QueueObserver) { + queueObservable.unregisterObserver(observer) + if (queueObservable.getCount() == 0) { + queueA.unregisterObserver(this) + queueB.unregisterObserver(this) + } + } + + override fun onInserted() { + queueObservable.notifyInserted() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/support/float/FloatQueue.kt b/app/src/main/java/com/chwl/app/support/float/FloatQueue.kt new file mode 100644 index 0000000..47f7b52 --- /dev/null +++ b/app/src/main/java/com/chwl/app/support/float/FloatQueue.kt @@ -0,0 +1,48 @@ +package com.chwl.app.support.float + +import android.database.Observable + + +interface FloatQueue { + fun pollFirst(): QueueItem? + + fun peekFirst(): QueueItem? + + fun addLast(data: Any) + + fun registerObserver(observer: QueueObserver) + + fun unregisterObserver(observer: QueueObserver) + + interface QueueObserver { + fun onInserted() + } + + class QueueObservable : Observable() { + fun notifyInserted() { + mObservers.forEach { + it.onInserted() + } + } + + override fun registerObserver(observer: QueueObserver?) { + try { + super.registerObserver(observer) + } catch (e: Exception) { + e.printStackTrace() + } + } + + override fun unregisterObserver(observer: QueueObserver?) { + try { + super.unregisterObserver(observer) + } catch (e: Exception) { + e.printStackTrace() + } + } + + fun getCount(): Int { + return mObservers.size + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/support/float/FloatView.kt b/app/src/main/java/com/chwl/app/support/float/FloatView.kt new file mode 100644 index 0000000..510290b --- /dev/null +++ b/app/src/main/java/com/chwl/app/support/float/FloatView.kt @@ -0,0 +1,12 @@ +package com.chwl.app.support.float + +import android.view.View + + +interface FloatView { + fun onAttached(window: FloatWindow, item: Any) + + fun onDetached() + + fun getView(): View +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/support/float/FloatViewAdapter.kt b/app/src/main/java/com/chwl/app/support/float/FloatViewAdapter.kt new file mode 100644 index 0000000..dfd18bd --- /dev/null +++ b/app/src/main/java/com/chwl/app/support/float/FloatViewAdapter.kt @@ -0,0 +1,10 @@ +package com.chwl.app.support.float + +import android.content.Context + + +interface FloatViewAdapter { + fun onCreateFloatView(context: Context, item: Any): FloatView? + + fun onBindFloatView(window: FloatWindow, floatView: FloatView, item: Any) +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/support/float/FloatWindow.kt b/app/src/main/java/com/chwl/app/support/float/FloatWindow.kt new file mode 100644 index 0000000..e0cb1ba --- /dev/null +++ b/app/src/main/java/com/chwl/app/support/float/FloatWindow.kt @@ -0,0 +1,41 @@ +package com.chwl.app.support.float + +import android.app.Activity +import android.view.View +import android.view.ViewGroup +import androidx.core.view.contains +import com.example.lib_utils.log.ILog + + +interface FloatWindow : ILog { + + fun bindActivity(activity: Activity) { + val contentView = activity.window.decorView.findViewById(android.R.id.content) + if (contentView == null) { + logE("bindActivity() contentView=null") + return + } + val view = getView() + if (contentView.contains(view)) { + return + } + if (view.layoutParams == null) { + view.layoutParams = ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT + ) + } + contentView.addView(view) + } + + + fun getView(): View + + fun onBindEngine(engine: FloatWindowEngine) + + fun removeChild(floatView: FloatView) + + fun canShow(): Boolean + + fun onShow(item: Any) +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/support/float/FloatWindowEngine.kt b/app/src/main/java/com/chwl/app/support/float/FloatWindowEngine.kt new file mode 100644 index 0000000..9e5b393 --- /dev/null +++ b/app/src/main/java/com/chwl/app/support/float/FloatWindowEngine.kt @@ -0,0 +1,90 @@ +package com.chwl.app.support.float + +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleEventObserver +import androidx.lifecycle.LifecycleOwner +import com.example.lib_utils.log.ILog + + +open class FloatWindowEngine( + val window: FloatWindow, + val queue: FloatQueue +) : LifecycleEventObserver, FloatQueue.QueueObserver, ILog { + + private var isAvailable = true + + /** + * 拦截器 + * -1:直接消费掉(本次不展示,继续下一个) + * 1:拦截(等于暂停展示) + * 其他:默认处理 + */ + var interceptor: ((QueueItem) -> Int)? = null + + fun bindLifecycle(lifecycle: Lifecycle) { + lifecycle.addObserver(this) + } + + fun start() { + window.onBindEngine(this) + queue.registerObserver(this) + loop() + } + + fun stop() { + queue.unregisterObserver(this) + } + + override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) { + val isAvailableOld = isAvailable + isAvailable = event.targetState.isAtLeast(Lifecycle.State.STARTED) + if (isAvailableOld != isAvailable && isAvailable) { + loop() + } + + if (event == Lifecycle.Event.ON_DESTROY) { + stop() + } + } + + fun loop() { + if (!isAvailable) { + return + } + val item = queue.peekFirst() ?: return + when (interceptor?.invoke(item)) { + -1 -> { + // 直接消费掉,不进行展示,继续下一个 + logD("loop() -1") + queue.pollFirst() + loop() + } + + 1 -> { + // 拦截 + logD("loop() 1") + return + } + + else -> { + // 默认处理:尝试消费 + handleFirstItem() + } + } + } + + protected open fun handleFirstItem() { + if (window.canShow()) { + logD("handleFirstItem() pollFirst") + queue.pollFirst()?.let { + window.onShow(it.data) + } + } else { + logD("handleFirstItem() canShow==false") + } + } + + override fun onInserted() { + loop() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/support/float/QueueItem.kt b/app/src/main/java/com/chwl/app/support/float/QueueItem.kt new file mode 100644 index 0000000..8489dd4 --- /dev/null +++ b/app/src/main/java/com/chwl/app/support/float/QueueItem.kt @@ -0,0 +1,8 @@ +package com.chwl.app.support.float + +import androidx.annotation.Keep +import java.io.Serializable + +@Keep +data class QueueItem(val time: Long, val data: Any) : Serializable { +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/support/float/SimpleFloatQueue.kt b/app/src/main/java/com/chwl/app/support/float/SimpleFloatQueue.kt new file mode 100644 index 0000000..6639f2b --- /dev/null +++ b/app/src/main/java/com/chwl/app/support/float/SimpleFloatQueue.kt @@ -0,0 +1,101 @@ +package com.chwl.app.support.float + +import com.chwl.core.auth.AuthModel +import com.chwl.core.gift.bean.LuckyBagNoticeInfo +import com.chwl.core.im.custom.bean.RoomBoxPrizeAttachment +import com.chwl.core.im.custom.bean.RoomTemplateNotifyMsgBean +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.noble.bean.AllServiceGiftProtocol +import com.chwl.core.utils.CurrentTimeUtils +import com.chwl.library.common.util.doLog +import com.chwl.library.common.util.isVerify +import java.util.LinkedList + + +class SimpleFloatQueue : FloatQueue { + + private val queueObservable = FloatQueue.QueueObservable() + + private val queue: LinkedList = LinkedList() + + override fun pollFirst(): QueueItem? { + return queue.pollFirst() + } + + override fun peekFirst(): QueueItem? { + return queue.peekFirst() + } + + override fun addLast(data: Any) { + val item = QueueItem(CurrentTimeUtils.getCurrentTime(), data) + queue.addLast(item) + sortBy() + queueObservable.notifyInserted() + } + + override fun registerObserver(observer: FloatQueue.QueueObserver) { + queueObservable.registerObserver(observer) + } + + override fun unregisterObserver(observer: FloatQueue.QueueObserver) { + queueObservable.unregisterObserver(observer) + } + + public fun clear() { + queue.clear() + } + + private fun sortBy() { + //执行排序 + + val roomUid = AvRoomDataManager.get().roomUid + val uid = AuthModel.get().currentUid + + // RoomTemplateNotifyMsgBean 通用模版 + // AllServiceGiftProtocol.DataBean 礼物 + // LuckyBagNoticeInfo 福袋 + // RoomBoxPrizeAttachment 寻爱 + + queue.sortWith(compareBy { data-> + try { + if (data.data is RoomTemplateNotifyMsgBean) { + if (data.data.uidList?.contains(uid) == true) { + 1 + }else if (data.data.roomUid == roomUid) { + 2 + } else { + 10 + } + }else if (data.data is AllServiceGiftProtocol.DataBean) { + if (data.data.recvUserUid == uid || data.data.sendUserUid == uid) { + 1 + }else if (data.data.roomUid == roomUid) { + 2 + } else { + 10 + } + }else if(data.data is LuckyBagNoticeInfo){ + if (data.data.uid == uid) { + 1 + }else if (data.data.roomUid == roomUid){ + 2 + }else{ + 10 + } + }else if(data.data is RoomBoxPrizeAttachment){ + if (data.data.uid == uid) { + 1 + }else if (data.data.roomUid == roomUid){ + 2 + }else{ + 10 + } + } else { + 10 + } + } catch (e: Exception) { + 10 + } + }.thenBy { queue.indexOf(it) }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/support/float/SimpleFloatWindow.kt b/app/src/main/java/com/chwl/app/support/float/SimpleFloatWindow.kt new file mode 100644 index 0000000..cfe728e --- /dev/null +++ b/app/src/main/java/com/chwl/app/support/float/SimpleFloatWindow.kt @@ -0,0 +1,83 @@ +package com.chwl.app.support.float + +import android.animation.LayoutTransition +import android.content.Context +import android.util.AttributeSet +import android.view.View +import android.widget.LinearLayout +import com.chwl.app.BuildConfig +import java.lang.Exception + +open class SimpleFloatWindow : LinearLayout, FloatWindow { + + var adapter: FloatViewAdapter? = null + private var engine: FloatWindowEngine? = null + + var maxVisibleCount: Int = 1 + + constructor(context: Context?) : super(context) + constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) + constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) + + constructor( + context: Context?, + attrs: AttributeSet?, + defStyleAttr: Int, + defStyleRes: Int + ) : super(context, attrs, defStyleAttr, defStyleRes) + + init { + orientation = VERTICAL + initLayoutTransition() + } + + private fun initLayoutTransition() { + val transition = LayoutTransition() + transition.setAnimator( + LayoutTransition.APPEARING, null + ) + transition.setAnimator( + LayoutTransition.DISAPPEARING, null + ) + layoutTransition = transition + } + + override fun removeChild(floatView: FloatView) { + floatView.onDetached() + removeView(floatView.getView()) + engine?.loop() + } + + override fun getView(): View { + return this + } + + override fun onBindEngine(engine: FloatWindowEngine) { + this.engine = engine + } + + override fun canShow(): Boolean { + return this.childCount < maxVisibleCount + } + + override fun onShow(item: Any) { + try { + val floatView = adapter?.onCreateFloatView(context, item) + if (floatView == null) { + engine?.loop() + return + } + addView(floatView.getView()) + adapter?.onBindFloatView(this, floatView, item) + } catch (e: Exception) { + e.printStackTrace() + if (BuildConfig.DEBUG) { + throw e + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/sys/ErbanSysMsgViewModel.java b/app/src/main/java/com/chwl/app/sys/ErbanSysMsgViewModel.java new file mode 100644 index 0000000..33c31ce --- /dev/null +++ b/app/src/main/java/com/chwl/app/sys/ErbanSysMsgViewModel.java @@ -0,0 +1,30 @@ +package com.chwl.app.sys; + +import com.chwl.core.auth.AuthModel; +import com.chwl.core.msg.sys.bean.ApproveMsgInfo; +import com.chwl.core.msg.sys.ErbanSysMsgModel; +import com.chwl.core.utils.net.RxHelper; +import com.chwl.library.net.rxnet.RxNet; + +import java.util.Map; + +import io.reactivex.Single; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; + +/** + * Created by MadisonRong on 03/07/2018. + */ + +public class ErbanSysMsgViewModel { + + private ErbanSysMsgModel.Api api = RxNet.create(ErbanSysMsgModel.Api.class); + + public Single requestUrl(String url, int type, Map params) { + String uid = String.valueOf(AuthModel.get().getCurrentUid()); + return api.requestUrl(url, type, uid, params) + .compose(RxHelper.handleBeanData()) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()); + } +} diff --git a/app/src/main/java/com/chwl/app/team/adapter/AddTeamMemberAdapter.java b/app/src/main/java/com/chwl/app/team/adapter/AddTeamMemberAdapter.java new file mode 100644 index 0000000..5ece0e7 --- /dev/null +++ b/app/src/main/java/com/chwl/app/team/adapter/AddTeamMemberAdapter.java @@ -0,0 +1,62 @@ +package com.chwl.app.team.adapter; + +import android.content.Context; +import android.view.View; +import android.widget.TextView; + +import com.chwl.app.BR; +import com.chwl.app.R; +import com.chwl.app.bindadapter.BaseAdapter; +import com.chwl.app.bindadapter.BindingViewHolder; +import com.chwl.core.family.bean.FamilyMemberInfo; + +/** + * Created by MadisonRong on 29/05/2018. + */ + +public class AddTeamMemberAdapter extends BaseAdapter { + + protected Context context; + + public AddTeamMemberAdapter(Context context) { + this(R.layout.item_add_team_member, BR.memberInfo, context); + } + + public AddTeamMemberAdapter(int layoutResId, int brid, Context context) { + super(layoutResId, brid); + this.context = context; + } + + @Override + protected void convert(BindingViewHolder helper, FamilyMemberInfo item) { + super.convert(helper, item); +// helper.getBinding().setVariable(BR.memberInfo, item); + TextView tvMemberAdd = helper.getView(R.id.tv_member_add); + tvMemberAdd.setSelected(item.isSelect()); + helper.getView(R.id.ll_member_layout).setOnClickListener(v -> { + if (onCheckedChangeListener != null) { + if (item.isSelect()) { + onCheckedChangeListener.onUnSelect(item); + }else { + onCheckedChangeListener.onSelect(item); + } + } + }); + + if (this.mData.indexOf(item) == this.mData.size() - 1) { + helper.getView(R.id.diver).setVisibility(View.GONE); + } + } + + private OnCheckedChangeListener onCheckedChangeListener; + + public void setOnCheckedChangeListener(OnCheckedChangeListener onCheckedChangeListener) { + this.onCheckedChangeListener = onCheckedChangeListener; + } + + public interface OnCheckedChangeListener { + void onSelect(FamilyMemberInfo familyMemberInfo); + + void onUnSelect(FamilyMemberInfo familyMemberInfo); + } +} diff --git a/app/src/main/java/com/chwl/app/team/adapter/TeamListAdapter.java b/app/src/main/java/com/chwl/app/team/adapter/TeamListAdapter.java new file mode 100644 index 0000000..5ec61a3 --- /dev/null +++ b/app/src/main/java/com/chwl/app/team/adapter/TeamListAdapter.java @@ -0,0 +1,48 @@ +package com.chwl.app.team.adapter; + +import android.content.Context; +import android.widget.ImageView; +import android.widget.TextView; + +import com.chwl.app.BR; +import com.chwl.app.R; +import com.chwl.app.bindadapter.BaseAdapter; +import com.chwl.app.bindadapter.BindingViewHolder; +import com.chwl.app.friend.action.AbstractSelectFriendAction; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.team.bean.TeamInfo; + +/** + * Created by MadisonRong on 11/06/2018. + */ + +public class TeamListAdapter extends BaseAdapter { + + private int type = AbstractSelectFriendAction.TYPE_NORMAL; + private Context context; + + public TeamListAdapter(Context context) { + this(R.layout.item_team_list, BR.teamInfo, context); + } + + public TeamListAdapter(int layoutResId, int brid, Context context) { + super(layoutResId, brid); + this.context = context; + } + + public void setType(int type) { + this.type = type; + } + + @Override + protected void convert(BindingViewHolder helper, TeamInfo item) { + super.convert(helper, item); + ImageView avatar = helper.getView(R.id.iv_avatar); + TextView teamName = helper.getView(R.id.tv_team_name); + + helper.addOnClickListener(R.id.ll_container); + ImageLoadUtils.loadAvatar(context, item.getIcon(), avatar); + teamName.setText(item.getName()); + } + +} diff --git a/app/src/main/java/com/chwl/app/team/adapter/TeamMemberListAdapter.java b/app/src/main/java/com/chwl/app/team/adapter/TeamMemberListAdapter.java new file mode 100644 index 0000000..344e749 --- /dev/null +++ b/app/src/main/java/com/chwl/app/team/adapter/TeamMemberListAdapter.java @@ -0,0 +1,154 @@ +package com.chwl.app.team.adapter; + +import android.content.Context; +import android.text.TextUtils; +import android.view.View; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.databinding.ViewDataBinding; + +import com.netease.nim.uikit.common.ui.imageview.HeadImageView; +import com.netease.nim.uikit.support.glide.GlideApp; +import com.chwl.app.BR; +import com.chwl.app.R; +import com.chwl.app.bindadapter.BaseAdapter; +import com.chwl.app.bindadapter.BindingViewHolder; +import com.chwl.app.team.view.TeamMemberListActivity; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.level.UserLevelVo; +import com.chwl.core.team.bean.TeamMemberInfo; + +/** + * Created by MadisonRong on 30/05/2018. + */ + +public class TeamMemberListAdapter extends BaseAdapter { + + private Context context; + private int type; + + public TeamMemberListAdapter(Context context, int type) { + this(R.layout.item_team_member_list, BR.memberInfo, context, type); + } + + public TeamMemberListAdapter(int layoutResId, int brid, Context context, int type) { + super(layoutResId, brid); + this.context = context; + this.type = type; + } + + @Override + protected void convert(BindingViewHolder helper, TeamMemberInfo item) { + ViewDataBinding binding = helper.getBinding(); + + HeadImageView ivAvatar = helper.getView(R.id.iv_avatar); + ImageView officePosition = helper.getView(R.id.iv_user_office_position); + TextView tvName = helper.getView(R.id.tv_name); + TextView tvErbanId = helper.getView(R.id.tv_erban_id); + TextView tvMemberRemove = helper.getView(R.id.tv_member_remove); + + + GlideApp.with(context) + .load(TextUtils.isEmpty(item.getAvatar()) ? R.drawable.default_avatar : item.getAvatar()) + .placeholder(R.drawable.default_avatar) + .error(R.drawable.default_avatar) + .into(ivAvatar); + + tvName.setText(item.getNick()); + tvErbanId.setText(context.getString(R.string.family_member_erban_id, String.valueOf(item.getErbanNo()))); + ImageButton button = helper.getView(R.id.btn_member_operation); + + UserLevelVo userLevelVo = item.getUserLevelVo(); + ImageView ivUserLevel = helper.getView(R.id.iv_user_level); + ImageView ivUserCharm = helper.getView(R.id.iv_user_charm); + ivUserLevel.setVisibility(userLevelVo == null ? View.GONE : View.VISIBLE); + ivUserLevel.setVisibility(userLevelVo == null ? View.GONE : View.VISIBLE); + if (userLevelVo != null) { + ivUserLevel.setVisibility(TextUtils.isEmpty(userLevelVo.getExperUrl()) ? View.GONE : View.VISIBLE); + if (!TextUtils.isEmpty(userLevelVo.getExperUrl())) { + ImageLoadUtils.loadImage(mContext, userLevelVo.getExperUrl(), ivUserLevel); + } + ivUserCharm.setVisibility(TextUtils.isEmpty(userLevelVo.getCharmUrl()) ? View.GONE : View.VISIBLE); + if (!TextUtils.isEmpty(userLevelVo.getCharmUrl())) { + ivUserCharm.setVisibility(View.VISIBLE); + ImageLoadUtils.loadImage(mContext, userLevelVo.getCharmUrl(), ivUserCharm); + } + } + +// if (item.getUid() == AuthModel.get().getCurrentUid()) { +// button.setVisibility(View.GONE); +// } else { +// button.setVisibility(View.VISIBLE); +// } +// int role = TeamModel.get().getTeamInfoCache(item.getTid()).getRole(); + switch (item.getRole()) { + case TeamMemberInfo.ROLE_TEAM_OWNER: + officePosition.setVisibility(View.VISIBLE); + officePosition.setImageResource(R.drawable.icon_family_office_position_boss); + button.setVisibility(View.GONE); + break; + + case TeamMemberInfo.ROLE_TEAM_MANAGER: + officePosition.setVisibility(View.VISIBLE); + officePosition.setImageResource(R.drawable.icon_family_office_position_manager); + button.setVisibility(item.getUid() == AuthModel.get().getCurrentUid() ? + View.GONE : View.VISIBLE); + break; + + case TeamMemberInfo.ROLE_TEAM_MEMBER: + officePosition.setVisibility(View.GONE); + button.setVisibility(item.getUid() == AuthModel.get().getCurrentUid() ? + View.GONE : View.VISIBLE); + break; + } + + switch (type) { + default: + case TeamMemberListActivity.OP_TEAM_MEMBER_NORMAL: + button.setVisibility(View.GONE); + break; + + case TeamMemberListActivity.OP_TEAM_MEMBER_REMOVE: + button.setImageResource(R.drawable.ic_family_remove_person); + break; + + case TeamMemberListActivity.OP_TEAM_MEMBER_MANAGEMENT: + if (item.getRole() == TeamMemberInfo.ROLE_TEAM_MANAGER) { + button.setImageResource(R.drawable.ic_family_remove_manager); + } else { + button.setImageResource(R.drawable.ic_family_add_manager); + } + break; + + case TeamMemberListActivity.OP_TEAM_MEMBER_MUTE: + if (item.isDisable()) { + button.setImageResource(R.drawable.ic_family_remove_mute); + + } else { + button.setImageResource(R.drawable.ic_family_add_mute); + } + break; + } + + if (this.mData != null && this.mData.size() > 0 && + this.mData.indexOf(item) == this.mData.size() - 1) { + helper.getView(R.id.diver).setVisibility(View.GONE); + } + + button.setOnClickListener(v -> onOperationButtonClickedListener.onOperationButtonClicked(helper.getAdapterPosition(), item, type)); + } + + private OnOperationButtonClickedListener onOperationButtonClickedListener; + + public void setOnOperationButtonClickedListener(OnOperationButtonClickedListener onOperationButtonClickedListener) { + this.onOperationButtonClickedListener = onOperationButtonClickedListener; + } + + public interface OnOperationButtonClickedListener { + void onOperationButtonClicked(int position, TeamMemberInfo teamMemberInfo, int type); + } + +} diff --git a/app/src/main/java/com/chwl/app/team/adapter/TeamWeeklyBillAdapter.java b/app/src/main/java/com/chwl/app/team/adapter/TeamWeeklyBillAdapter.java new file mode 100644 index 0000000..51e4b08 --- /dev/null +++ b/app/src/main/java/com/chwl/app/team/adapter/TeamWeeklyBillAdapter.java @@ -0,0 +1,71 @@ +package com.chwl.app.team.adapter; + +import android.content.Context; +import android.view.View; +import android.widget.TextView; + +import com.netease.nim.uikit.support.glide.GlideApp; +import com.chwl.app.BR; +import com.chwl.app.R; +import com.chwl.app.bindadapter.BaseAdapter; +import com.chwl.app.bindadapter.BindingViewHolder; +import com.chwl.app.common.widget.CircleImageView; +import com.chwl.app.ui.widget.UserInfoDialog; +import com.chwl.core.family.model.FamilyModel; +import com.chwl.core.team.bean.TeamTransactionRecordInfo; +import com.chwl.library.utils.FormatUtils; +import com.chwl.library.utils.ResUtil; + +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * Created by MadisonRong on 31/05/2018. + */ + +public class TeamWeeklyBillAdapter extends BaseAdapter { + + private Context context; + private SimpleDateFormat simpleDateFormat = new SimpleDateFormat(ResUtil.getString(R.string.team_adapter_teamweeklybilladapter_01)); + + public TeamWeeklyBillAdapter(Context context) { + this(R.layout.item_team_weekly_bill_transcation_record, BR.transactionRecordInfo, context); + } + + public TeamWeeklyBillAdapter(int layoutResId, int brid, Context context) { + super(layoutResId, brid); + this.context = context; + } + + @Override + protected void convert(BindingViewHolder helper, TeamTransactionRecordInfo item) { + if (null == item) return; + + CircleImageView civImg = helper.getView(R.id.civ_img); + TextView tvNick = helper.getView(R.id.tv_nick); + TextView tvFrom = helper.getView(R.id.tv_from); + TextView tvData = helper.getView(R.id.tv_data); + TextView tvTime = helper.getView(R.id.tv_time); + + + GlideApp.with(context) + .load(item.getAvatar()) + .placeholder(R.drawable.default_avatar) + .dontAnimate() + .into(civImg); + + civImg.setOnClickListener(v -> { + UserInfoDialog.showNewUserInfoDialog(context,item.getUid()); + }); + + tvNick.setText(item.getNick()); + tvFrom.setText(item.getSource()); + tvData.setText(FormatUtils.formatToShortDown(item.getAmount()) + FamilyModel.Instance().getMyFamily().getMoneyName()); + tvTime.setText(simpleDateFormat.format(new Date(item.getTime()))); + + if (this.mData != null && this.mData.size() > 0 && + this.mData.indexOf(item) == this.mData.size() - 1) { + helper.getView(R.id.diver).setVisibility(View.GONE); + } + } +} diff --git a/app/src/main/java/com/chwl/app/team/bean/NimTeamMember.java b/app/src/main/java/com/chwl/app/team/bean/NimTeamMember.java new file mode 100644 index 0000000..1cd57ae --- /dev/null +++ b/app/src/main/java/com/chwl/app/team/bean/NimTeamMember.java @@ -0,0 +1,85 @@ +package com.chwl.app.team.bean; + +import com.netease.nimlib.sdk.team.constant.TeamMemberType; +import com.netease.nimlib.sdk.team.model.TeamMember; + +import java.util.Map; + +/** + * 为了实现自定义@人的界面而产生的中间数据结构,里面的数据不一定准确 + * Created by MadisonRong on 31/05/2018. + */ + +public class NimTeamMember implements TeamMember { + + private String tid; + private String account; + private TeamMemberType type; + private String teamNick; + private boolean isInTeam; + + public void setTid(String tid) { + this.tid = tid; + } + + public void setAccount(String account) { + this.account = account; + } + + public void setType(TeamMemberType type) { + this.type = type; + } + + public void setTeamNick(String teamNick) { + this.teamNick = teamNick; + } + + public void setInTeam(boolean inTeam) { + isInTeam = inTeam; + } + + @Override + public String getTid() { + return tid; + } + + @Override + public String getAccount() { + return account; + } + + @Override + public TeamMemberType getType() { + return type; + } + + @Override + public String getTeamNick() { + return teamNick; + } + + @Override + public boolean isInTeam() { + return isInTeam; + } + + @Override + public Map getExtension() { + return null; + } + + @Override + public boolean isMute() { + return false; + } + + @Override + public long getJoinTime() { + return 0; + } + + @Override + public String getInvitorAccid() { + return ""; + } +} diff --git a/app/src/main/java/com/chwl/app/team/dialog/QuitTeamDialog.java b/app/src/main/java/com/chwl/app/team/dialog/QuitTeamDialog.java new file mode 100644 index 0000000..a5f8b48 --- /dev/null +++ b/app/src/main/java/com/chwl/app/team/dialog/QuitTeamDialog.java @@ -0,0 +1,14 @@ +package com.chwl.app.team.dialog; + +import androidx.appcompat.app.AppCompatDialogFragment; + +import com.chwl.app.R; +import com.chwl.library.annatation.ActLayoutRes; + +/** + * Created by MadisonRong on 29/05/2018. + */ +@ActLayoutRes(R.layout.dialog_quit_team) +public class QuitTeamDialog extends AppCompatDialogFragment { + +} diff --git a/app/src/main/java/com/chwl/app/team/event/TeamMemberUpdateEvent.java b/app/src/main/java/com/chwl/app/team/event/TeamMemberUpdateEvent.java new file mode 100644 index 0000000..4eb5649 --- /dev/null +++ b/app/src/main/java/com/chwl/app/team/event/TeamMemberUpdateEvent.java @@ -0,0 +1,11 @@ +package com.chwl.app.team.event; + +/** + * @author jack + * @Description + * @Date 2018/7/26 + */ + +public class TeamMemberUpdateEvent { + +} diff --git a/app/src/main/java/com/chwl/app/team/view/AddMemberActivity.java b/app/src/main/java/com/chwl/app/team/view/AddMemberActivity.java new file mode 100644 index 0000000..55a2818 --- /dev/null +++ b/app/src/main/java/com/chwl/app/team/view/AddMemberActivity.java @@ -0,0 +1,265 @@ +package com.chwl.app.team.view; + +import android.app.Activity; +import android.content.Intent; +import android.view.View; + +import androidx.recyclerview.widget.LinearLayoutManager; + +import com.chwl.app.R; +import com.chwl.app.base.BaseBindingActivity; +import com.chwl.app.databinding.ActivityAddTeamMemberBinding; +import com.chwl.app.team.adapter.AddTeamMemberAdapter; +import com.chwl.app.team.viewmodel.FamilyMemberVM; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.family.bean.FamilyMemberInfo; +import com.chwl.library.annatation.ActLayoutRes; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; +import com.netease.nim.uikit.common.util.sys.NetworkUtil; +import com.scwang.smart.refresh.layout.api.RefreshLayout; +import com.scwang.smart.refresh.layout.listener.OnRefreshLoadMoreListener; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +; +; + +/** + * 查询出家族里所有成员的人,从中筛选 + * Created by MadisonRong on 29/05/2018. + */ +@ActLayoutRes(R.layout.activity_add_team_member) +public class AddMemberActivity extends BaseBindingActivity + implements AddTeamMemberAdapter.OnCheckedChangeListener { + + public static final int FIRST_PAGE = 1; + public static final int REQUEST_CODE_SELECT_MEMBER = 100; + public static final String EXTRA_TEAM_ID = "EXTRA_TEAM_ID"; + public static final String EXTRA_SELECTED_MEMBER = "EXTRA_SELECTED_MEMBER"; + + private FamilyMemberVM familyMemberViewModel; + private AddTeamMemberAdapter addTeamMemberAdapter; + private String teamId; + private int page = FIRST_PAGE; + private ArrayList selectMembers = new ArrayList<>(); + + public static void start(Activity activity) { + Intent intent = new Intent(activity, AddMemberActivity.class); + activity.startActivityForResult(intent, REQUEST_CODE_SELECT_MEMBER); + } + + + public static void start(Activity activity,ArrayList memberInfoList) { + Intent intent = new Intent(activity, AddMemberActivity.class); + intent.putExtra(EXTRA_SELECTED_MEMBER, memberInfoList); + activity.startActivityForResult(intent, REQUEST_CODE_SELECT_MEMBER); + } + + public static void start(Activity activity, String tid) { + Intent intent = new Intent(activity, AddMemberActivity.class); + intent.putExtra(EXTRA_TEAM_ID, tid); + activity.startActivityForResult(intent, REQUEST_CODE_SELECT_MEMBER); + } + + @Override + protected void init() { + initTitleBar(getString(R.string.family_member_list)); + + if (getIntent() != null) { + teamId = getIntent().getStringExtra(EXTRA_TEAM_ID); + ArrayList serializableExtra = (ArrayList) getIntent().getSerializableExtra(EXTRA_SELECTED_MEMBER); + if (serializableExtra != null) { + selectMembers = serializableExtra; + } + } + + familyMemberViewModel = new FamilyMemberVM(); + addTeamMemberAdapter = new AddTeamMemberAdapter(this); + mBinding.rvMember.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)); + mBinding.rvMember.setAdapter(addTeamMemberAdapter); + + addTeamMemberAdapter.setOnCheckedChangeListener(this); + mBinding.setClick(this); + showLoading(); + + mBinding.srlMemberList.setEnableLoadMore(true); + mBinding.srlMemberList.setOnRefreshLoadMoreListener(new OnRefreshLoadMoreListener() { + @Override + public void onLoadMore(RefreshLayout refreshLayout) { + if (!NetworkUtil.isNetAvailable(AddMemberActivity.this)) { + mBinding.srlMemberList.finishLoadMore(); + return; + } + List data = addTeamMemberAdapter.getData(); + if (ListUtils.isListEmpty(data)) { + mBinding.srlMemberList.finishLoadMore(); + return; + } + loadData(); + } + + @Override + public void onRefresh(RefreshLayout refreshLayout) { + if (!NetworkUtil.isNetAvailable(AddMemberActivity.this)) { + mBinding.srlMemberList.finishRefresh(); + return; + } + firstLoad(); + } + }); + } + + private void firstLoad() { + page = FIRST_PAGE; + loadData(); + } + + private void loadData() { + familyMemberViewModel.getNotInTeamFamilyMembers(teamId, null, page) + .compose(bindToLifecycle()) + .subscribe((respFamilymember, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + finishLoadingData(); + } else { + mBinding.tvMemberCount.setText(getString(R.string.family_member_label2, + String.valueOf(respFamilymember.getCount()))); + List teamMemberInfos = respFamilymember.getMembers(); + if (!ListUtils.isListEmpty(teamMemberInfos)) { + Iterator iterator = teamMemberInfos.iterator(); + while (iterator.hasNext()){ + FamilyMemberInfo teamMemberInfo = iterator.next(); + if (teamMemberInfo.getUid() == AuthModel.get().getCurrentUid()) { + iterator.remove(); + } + if (isMemberInSelect(teamMemberInfo)){ + teamMemberInfo.setSelect(true); + } + } + hideStatus(); + if (page == FIRST_PAGE) { + addTeamMemberAdapter.setNewData(teamMemberInfos); + mBinding.srlMemberList.finishRefresh(); + } else { + addTeamMemberAdapter.addData(teamMemberInfos); + mBinding.srlMemberList.finishLoadMore(); + } + } else { + finishLoadingData(); + } + page++; + } + }); + } + + private void finishLoadingData() { + if (page == FIRST_PAGE) { + showNoData(ResUtil.getString(R.string.team_view_addmemberactivity_01)); + mBinding.srlMemberList.finishRefresh(); + } else { + mBinding.srlMemberList.finishLoadMore(); + } + } + + private boolean isMemberInSelect(FamilyMemberInfo familyMemberInfo){ + boolean isContain = false; + if (selectMembers != null) { + for (FamilyMemberInfo selectMember : selectMembers) { + if (selectMember.getUid() == familyMemberInfo.getUid()){ + isContain = true; + break; + } + } + } + return isContain; + } + + @Override + protected void onResume() { + super.onResume(); + firstLoad(); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (resultCode == RESULT_OK) { + if (requestCode == REQUEST_CODE_SELECT_MEMBER) { + ArrayList searchMembers = + (ArrayList) data.getSerializableExtra(AddMemberSearchActivity.EXTRA_SEARCH_MEMBER); + for (FamilyMemberInfo searchMember : searchMembers) { + if (searchMember.isSelect()){ + onSelect(searchMember); + }else { + onUnSelect(searchMember); + } + } + + } + + } + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.ll_search: + AddMemberSearchActivity.start(this, teamId, selectMembers); + break; + + case R.id.btn_confirm: + Intent intent = new Intent(); + intent.putExtra(EXTRA_SELECTED_MEMBER, selectMembers); + setResult(RESULT_OK, intent); + finish(); + break; + } + } + + + @Override + public void onSelect(FamilyMemberInfo familyMemberInfo) { + if (!isMemberInSelect(familyMemberInfo)) { + if (selectMembers != null) { + selectMembers.add(familyMemberInfo); + for (int i = 0; i < addTeamMemberAdapter.getData().size(); i++) { + if (addTeamMemberAdapter.getData().get(i).getUid() == familyMemberInfo.getUid()){ + addTeamMemberAdapter.getData().get(i).setSelect(true); + addTeamMemberAdapter.notifyDataSetChanged(); + break; + } + + } + } + } + + } + + @Override + public void onUnSelect(FamilyMemberInfo familyMemberInfo) { + boolean isRemove = false; + if (selectMembers != null) { + for (int i = 0; i < selectMembers.size(); i++) { + if (selectMembers.get(i).getUid() == familyMemberInfo.getUid()){ + selectMembers.remove(i); + isRemove = true; + break; + } + } + } + if (isRemove){ + for (int i = 0; i < addTeamMemberAdapter.getData().size(); i++) { + if (addTeamMemberAdapter.getData().get(i).getUid() == familyMemberInfo.getUid()){ + addTeamMemberAdapter.getData().get(i).setSelect(false); + addTeamMemberAdapter.notifyDataSetChanged(); + break; + } + + } + } + } + +} diff --git a/app/src/main/java/com/chwl/app/team/view/AddMemberSearchActivity.java b/app/src/main/java/com/chwl/app/team/view/AddMemberSearchActivity.java new file mode 100644 index 0000000..5abbb0d --- /dev/null +++ b/app/src/main/java/com/chwl/app/team/view/AddMemberSearchActivity.java @@ -0,0 +1,221 @@ +package com.chwl.app.team.view; + +import android.app.Activity; +import android.content.Intent; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.KeyEvent; +import android.view.View; +import android.view.inputmethod.EditorInfo; + +import androidx.recyclerview.widget.LinearLayoutManager; + +import com.chwl.app.R; +import com.chwl.app.base.BaseBindingActivity; +import com.chwl.app.databinding.ActivityAddTeamMemberSearchListBinding; +import com.chwl.app.team.adapter.AddTeamMemberAdapter; +import com.chwl.app.team.viewmodel.FamilyMemberVM; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.family.bean.FamilyMemberInfo; +import com.chwl.library.annatation.ActLayoutRes; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * Created by MadisonRong on 31/05/2018. + */ +@ActLayoutRes(R.layout.activity_add_team_member_search_list) +public class AddMemberSearchActivity extends BaseBindingActivity + implements AddTeamMemberAdapter.OnCheckedChangeListener { + + public static final String EXTRA_TEAM_ID = "EXTRA_TEAM_ID"; + public static final String EXTRA_TEAM_SELECT_MEMBERS = "EXTRA_TEAM_SELECT_MEMBERS"; + public static final String EXTRA_SEARCH_MEMBER = "EXTRA_SEARCH_MEMBER"; + + private FamilyMemberVM familyMemberViewModel; + private AddTeamMemberAdapter addTeamMemberAdapter; + private String teamId; + private ArrayList selectMembers = new ArrayList<>(); + + public static void start(Activity context, String tid, ArrayList selectMembers) { + Intent intent = new Intent(context, AddMemberSearchActivity.class); + intent.putExtra(EXTRA_TEAM_ID, tid); + intent.putExtra(EXTRA_TEAM_SELECT_MEMBERS, selectMembers); + context.startActivityForResult(intent, AddMemberActivity.REQUEST_CODE_SELECT_MEMBER); + } + + @Override + protected void init() { + + if (getIntent() != null) { + teamId = getIntent().getStringExtra(EXTRA_TEAM_ID); + ArrayList serializableExtra = (ArrayList) getIntent().getSerializableExtra(EXTRA_TEAM_SELECT_MEMBERS); + if (serializableExtra != null) { + selectMembers = serializableExtra; + } + } + + familyMemberViewModel = new FamilyMemberVM(); + addTeamMemberAdapter = new AddTeamMemberAdapter(this); + mBinding.rvMember.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)); + mBinding.rvMember.setAdapter(addTeamMemberAdapter); + + mBinding.searchEdit.addTextChangedListener(textWatcher); + mBinding.searchEdit.setImeOptions(EditorInfo.IME_ACTION_SEARCH); + mBinding.searchEdit.setOnEditorActionListener((v, actionId, event) -> { + if (actionId == EditorInfo.IME_ACTION_SEARCH || (event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) { + String str = v.getText().toString(); + if (!searchMemberList(str)) return false; + hideIME(); + return true; + } + return false; + + }); + + mBinding.ivClearText.setVisibility(View.GONE); + + addTeamMemberAdapter.setOnCheckedChangeListener(this); + mBinding.setClick(this); + } + + private TextWatcher textWatcher = new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + if (TextUtils.isEmpty(s.toString())) { + mBinding.ivClearText.setVisibility(View.GONE); + } else { + mBinding.ivClearText.setVisibility(View.VISIBLE); + } + } + }; + + private boolean searchMemberList(String str) { + if (TextUtils.isEmpty(str)) { +// Toast.makeText(this, ResUtil.getString(R.string.team_view_addmembersearchactivity_01), Toast.LENGTH_SHORT).show(); + SingleToastUtil.showToastShort(ResUtil.getString(R.string.team_view_addmembersearchactivity_02)); + return true; + } + familyMemberViewModel.getNotInTeamFamilyMembers(teamId, mBinding.searchEdit.getText().toString(), 0) + .compose(bindToLifecycle()) + .subscribe((respFamilymember, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + } else { + List familyMemberInfos = respFamilymember.getMembers(); + if (!ListUtils.isListEmpty(familyMemberInfos)) { + Iterator iterator = familyMemberInfos.iterator(); + while (iterator.hasNext()) { + FamilyMemberInfo teamMemberInfo = iterator.next(); + if (teamMemberInfo.getUid() == AuthModel.get().getCurrentUid()) { + iterator.remove(); + } + if (isMemberInSelect(teamMemberInfo)) { + teamMemberInfo.setSelect(true); + } + } + hideStatus(); + addTeamMemberAdapter.setNewData(familyMemberInfos); + addTeamMemberAdapter.notifyDataSetChanged(); + } else { + showNoData(); + } + } + }); + return false; + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.iv_back: + finish(); + break; + + case R.id.tv_search: + String str = mBinding.searchEdit.getText().toString(); + if (searchMemberList(str)) return; + hideIME(); + break; + + case R.id.iv_clear_text: + mBinding.searchEdit.setText(""); + break; + + case R.id.btn_confirm: + Intent intent = new Intent(); + ArrayList searchMemberList = new ArrayList<>(addTeamMemberAdapter.getData()); + intent.putExtra(EXTRA_SEARCH_MEMBER, searchMemberList); + setResult(RESULT_OK, intent); + finish(); + break; + } + } + + @Override + public void onSelect(FamilyMemberInfo familyMemberInfo) { + if (!isMemberInSelect(familyMemberInfo)) { + if (selectMembers != null) { + selectMembers.add(familyMemberInfo); + for (int i = 0; i < addTeamMemberAdapter.getData().size(); i++) { + if (addTeamMemberAdapter.getData().get(i).getUid() == familyMemberInfo.getUid()) { + addTeamMemberAdapter.getData().get(i).setSelect(true); + addTeamMemberAdapter.notifyDataSetChanged(); + break; + } + + } + } + } + } + + @Override + public void onUnSelect(FamilyMemberInfo familyMemberInfo) { + boolean isRemove = false; + if (selectMembers != null) { + for (int i = 0; i < selectMembers.size(); i++) { + if (selectMembers.get(i).getUid() == familyMemberInfo.getUid()) { + selectMembers.remove(i); + isRemove = true; + break; + } + } + } + if (isRemove) { + for (int i = 0; i < addTeamMemberAdapter.getData().size(); i++) { + if (addTeamMemberAdapter.getData().get(i).getUid() == familyMemberInfo.getUid()) { + addTeamMemberAdapter.getData().get(i).setSelect(false); + addTeamMemberAdapter.notifyDataSetChanged(); + break; + } + + } + } + } + + private boolean isMemberInSelect(FamilyMemberInfo familyMemberInfo) { + boolean isContain = false; + for (FamilyMemberInfo selectMember : selectMembers) { + if (selectMember.getUid() == familyMemberInfo.getUid()) { + isContain = true; + break; + } + } + return isContain; + } +} diff --git a/app/src/main/java/com/chwl/app/team/view/CreateTeamMessageActivity.java b/app/src/main/java/com/chwl/app/team/view/CreateTeamMessageActivity.java new file mode 100644 index 0000000..6a4448b --- /dev/null +++ b/app/src/main/java/com/chwl/app/team/view/CreateTeamMessageActivity.java @@ -0,0 +1,196 @@ +package com.chwl.app.team.view; + +import android.content.Context; +import android.content.Intent; +import android.text.Editable; +import android.text.TextWatcher; +import android.util.Log; +import android.view.View; +import android.widget.ImageView; + +import com.netease.nim.uikit.support.glide.GlideApp; +import com.chwl.app.R; +import com.chwl.app.base.BaseBindingTakePhotoActivity; +import com.chwl.app.databinding.ActivityCreateTeamMessageBinding; +import com.chwl.app.team.viewmodel.TeamVM; +import com.chwl.app.utils.KeyBoardUtils; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.family.bean.FamilyMemberInfo; +import com.chwl.core.family.model.FamilyModel; +import com.chwl.library.annatation.ActLayoutRes; +import com.chwl.library.utils.ResUtil; + +import java.util.ArrayList; +import java.util.Objects; + +/** + * Created by MadisonRong on 28/05/2018. + */ +@ActLayoutRes(R.layout.activity_create_team_message) +public class CreateTeamMessageActivity extends BaseBindingTakePhotoActivity + implements BaseBindingTakePhotoActivity.OnUploadListener { + + private static final String TAG = "CreateTeamMessageActivi"; + + private TeamVM teamViewModel; + private String url = "https://image.zhongjialx.com/default_group_avatar.png"; + private ArrayList members = new ArrayList<>(); + + public static void start(Context context) { + context.startActivity(new Intent(context, CreateTeamMessageActivity.class)); + } + + @Override + protected void init() { + initTitleBar(getString(R.string.title_create_team)); + + teamViewModel = new TeamVM(); + + mBinding.etTeamName.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + // 有输入,则按钮变成可按状态 + if (!Objects.equals(s.toString(), "")) { + if (s.toString().length() <= 15) { + mBinding.btnCreateTeam.setEnabled(true); + } else { + toast(ResUtil.getString(R.string.team_view_createteammessageactivity_01)); + } + } else { + mBinding.btnCreateTeam.setEnabled(false); + } + } + }); + mBinding.setClick(this); + mBinding.switchAuthMethod.setOn(true,false); + setOnUploadListener(this); + + GlideApp.with(this) + .load(url) + .dontAnimate() + .into(mBinding.ivTeamIcon); + + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (resultCode == RESULT_OK) { + switch (requestCode) { + case AddMemberActivity.REQUEST_CODE_SELECT_MEMBER: + ArrayList listExtra = (ArrayList) + data.getSerializableExtra(AddMemberActivity.EXTRA_SELECTED_MEMBER); + if (listExtra != null) { + Log.e(TAG, "onActivityResult: " + listExtra); + members = listExtra; + showSelectMemberView(members); + } + break; + } + } + } + + private void showSelectMemberView(ArrayList members) { + ImageView[] avatars = new ImageView[]{mBinding.ivSelectMember1, + mBinding.ivSelectMember2, mBinding.ivSelectMember3, + mBinding.ivSelectMember4, mBinding.ivSelectMember5, mBinding.ivSelectMember6}; + for (int i = 0; i < avatars.length; i++) { + avatars[i].setVisibility(View.GONE); + } + mBinding.tvSelectMember.setVisibility(View.GONE); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < members.size(); i++) { + if (i < avatars.length){ + avatars[i].setVisibility(View.VISIBLE); + GlideApp.with(this) + .load(members.get(i).getIcon()) + .dontAnimate() + .into(avatars[i]); + }else { + sb.append(" "); + break; + } + } + if (members.size() > 0){ + mBinding.tvSelectMember.setVisibility(View.VISIBLE); + mBinding.tvSelectMember.setText(sb.append(ResUtil.getString(R.string.team_view_createteammessageactivity_02)).append(members.size()).append(ResUtil.getString(R.string.team_view_createteammessageactivity_03)).toString()); + } + + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.btn_create_team: + mBinding.btnCreateTeam.setEnabled(false); + KeyBoardUtils.hideKeyBoard(this, mBinding.etTeamName); + // 输入内容为空格,不允许提交 + if (!Objects.equals(mBinding.etTeamName.getText().toString().trim(), "")) { + String[] teamMembers = new String[members.size()]; + for (int i = 0; i < members.size() ; i++) { + teamMembers[i] = String.valueOf(members.get(i).getUid()); + } + boolean isVerify = mBinding.switchAuthMethod.isOn(); + teamViewModel.createTeam( + FamilyModel.Instance().getMyFamily().getFamilyId(), + String.valueOf(AuthModel.get().getCurrentUid()), + url, + mBinding.etTeamName.getText().toString(), + isVerify, + teamMembers) + .compose(bindToLifecycle() + ) + .subscribe((serviceResult, throwable) -> { + mBinding.btnCreateTeam.setEnabled(true); + if (throwable != null) { + throwable.printStackTrace(); + toast(throwable.getMessage()); + } else { + FamilyModel.Instance().syncMyFamilyFromServer().subscribe(); + toast(ResUtil.getString(R.string.team_view_createteammessageactivity_04)); + finish(); + } + }); + } else { + mBinding.btnCreateTeam.setEnabled(true); + toast(ResUtil.getString(R.string.team_view_createteammessageactivity_05)); + } + break; + + case R.id.rl_upload_team_icon: + showTakePhotoOperationDialog(); + break; + + case R.id.rl_select_member: + AddMemberActivity.start(this, members); + break; + + case R.id.rl_switch_auth_method: + mBinding.switchAuthMethod.performClick(); + break; + + case R.id.switch_auth_method: + mBinding.switchAuthMethod.setOn(!mBinding.switchAuthMethod.isOn(), true); + break; + } + } + + @Override + public void onUploadSuccess(String url) { + this.url = url; + GlideApp.with(this) + .load(url) + .dontAnimate() + .into(mBinding.ivTeamIcon); + } +} diff --git a/app/src/main/java/com/chwl/app/team/view/NimTeamManagementActivity.java b/app/src/main/java/com/chwl/app/team/view/NimTeamManagementActivity.java new file mode 100644 index 0000000..58bf45b --- /dev/null +++ b/app/src/main/java/com/chwl/app/team/view/NimTeamManagementActivity.java @@ -0,0 +1,387 @@ +package com.chwl.app.team.view; + +import android.content.Context; +import android.content.Intent; +import android.view.View; + +import com.netease.nim.uikit.business.session.helper.MessageListPanelHelper; +import com.netease.nim.uikit.support.glide.GlideApp; +import com.trello.rxlifecycle3.android.ActivityEvent; +import com.chwl.app.R; +import com.chwl.app.base.BaseBindingTakePhotoActivity; +import com.chwl.app.base.TitleBar; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.app.databinding.ActivityTeamManagementBinding; +import com.chwl.app.friend.view.SelectFriendActivity; +import com.chwl.app.team.viewmodel.TeamVM; +import com.chwl.app.ui.widget.ButtonItem; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.family.bean.FamilyInfo; +import com.chwl.core.family.model.FamilyModel; +import com.chwl.core.manager.IMNetEaseManager; +import com.chwl.core.share.bean.SessionType; +import com.chwl.core.team.bean.TeamEvent; +import com.chwl.core.team.bean.TeamInfo; +import com.chwl.core.team.bean.TeamMemberInfo; +import com.chwl.core.team.model.TeamModel; +import com.chwl.library.annatation.ActLayoutRes; +import com.chwl.library.rxbus.RxBus; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.widget.IOSSwitchView; + +import java.util.ArrayList; +import java.util.List; + +import io.reactivex.SingleObserver; +import io.reactivex.disposables.Disposable; + +/** + * Created by MadisonRong on 29/05/2018. + */ +@ActLayoutRes(R.layout.activity_team_management) +public class NimTeamManagementActivity extends BaseBindingTakePhotoActivity + implements BaseBindingTakePhotoActivity.OnUploadListener { + + private static final String TAG = "NimTeamManagementActivi"; + + public static final String EXTRA_TEAM_ID = "EXTRA_TEAM_ID"; + + private String teamId; + private TeamVM teamViewModel; + private TeamInfo teamInfo; + + public static void start(Context context, String teamId) { + Intent intent = new Intent(context, NimTeamManagementActivity.class); + intent.putExtra(EXTRA_TEAM_ID, teamId); + context.startActivity(intent); + } + + @Override + protected void init() { + initTitleBar(getString(R.string.text_team_info_title)); + mBinding.setClick(this); + setOnUploadListener(this); + teamViewModel = new TeamVM(); + if (getIntent() != null) { + teamId = getIntent().getStringExtra(EXTRA_TEAM_ID); + } + mBinding.titleBar.addAction(new TitleBar.Action() { + @Override + public String getText() { + return null; + } + + @Override + public int getDrawable() { + return R.drawable.ic_share; + } + + @Override + public int getTextColor() { + return 0; + } + + @Override + public int getTextDrawableLeft() { + return 0; + } + + @Override + public void performAction(View view) { + } + }); + + mBinding.switchMessageNotifyType.setOnSwitchStateChangeListener(new IOSSwitchView.OnSwitchStateChangeListener() { + @Override + public void onStateSwitched(boolean isOn) { + mBinding.switchMessageNotifyType.setEnabled(false); + if (teamInfo == null) return; + boolean muteState = teamInfo.isPromt(); + teamViewModel.muteNotification(teamInfo.getId(), String.valueOf(AuthModel.get().getCurrentUid()), isOn) + .compose(bindToLifecycle()) + .subscribe((s, throwable) -> { + mBinding.switchMessageNotifyType.setEnabled(true); + if (throwable != null) { + throwable.printStackTrace(); + toast(ResUtil.getString(R.string.team_view_nimteammanagementactivity_01)); + mBinding.switchMessageNotifyType.setOn(muteState,true,false); + } else { + // update cache + teamInfo.setPromt(isOn); + TeamModel.get().setTeamInfoCache(teamInfo.getTid(), teamInfo); + } + }); + } + }); + + mBinding.switchJoinAuth.setOnSwitchStateChangeListener(new IOSSwitchView.OnSwitchStateChangeListener() { + @Override + public void onStateSwitched(boolean isOn) { + mBinding.switchJoinAuth.setEnabled(false); + boolean on = TeamModel.get().getCurrentTeamInfo().isVerify(); + teamViewModel.updateTeamJoinAuthMethod(teamInfo.getId(), isOn) + .compose(bindToLifecycle()) + .subscribe((teamInfo, throwable) -> { + mBinding.switchJoinAuth.setEnabled(true); + if (throwable != null) { + throwable.printStackTrace(); + toast(ResUtil.getString(R.string.team_view_nimteammanagementactivity_02)); + mBinding.switchJoinAuth.setOn(on,true,false); + } else { + NimTeamManagementActivity.this.teamInfo.setVerify(teamInfo.isVerify()); + TeamModel.get().setTeamInfoCache(teamInfo.getTid(), teamInfo); + // 显示身份验证方式的 text + mBinding.tvTeamAuth.setText(teamInfo.isVerify() ? getString(R.string.text_team_join_auth_on) + : getString(R.string.text_team_join_auth_off)); + } + }); + } + }); + + } + + + @Override + protected void onResume() { + super.onResume(); + teamInfo = TeamModel.get().getTeamInfoCache(teamId); + if (teamInfo == null) { + teamViewModel.getTeamInfo(teamId) + .subscribe((teamInfo, throwable) -> { + if (throwable != null){ + toast(throwable.getMessage()); + finish(); + return; + } + if (teamInfo != null) { + TeamModel.get().setTeamInfoCache(teamId, teamInfo); + mBinding.setTeamInfo(teamInfo); + this.teamInfo = teamInfo; + // 显示身份验证方式的 text + mBinding.tvTeamAuth.setText(teamInfo.isVerify() ? getString(R.string.text_team_join_auth_on) + : getString(R.string.text_team_join_auth_off)); + //根据角色显示相关界面 + showViewByRole(teamInfo.getRole()); + } + }); + } else { + mBinding.setTeamInfo(teamInfo); + // 显示身份验证方式的 text + mBinding.tvTeamAuth.setText(teamInfo.isVerify() ? getString(R.string.text_team_join_auth_on) + : getString(R.string.text_team_join_auth_off)); + //根据角色显示相关界面 + showViewByRole(teamInfo.getRole()); + } + } + + + + private void showViewByRole(int role){ + // 根据用户的权限显示「退出群」text 还是 「删除群」text + switch (role) { + case TeamMemberInfo.ROLE_TEAM_OWNER: + mBinding.btnOperation.setText(R.string.btn_text_delete_team); + mBinding.rlTeamJoinAuth.setVisibility(View.VISIBLE); + requestFamilyInfo(); + break; + + case TeamMemberInfo.ROLE_TEAM_MANAGER: + mBinding.btnOperation.setText(R.string.btn_text_quit_team); + mBinding.rlTeamMuteMember.setVisibility(View.GONE); + mBinding.vDiv2.setVisibility(View.GONE); + mBinding.rlSetTeamManagers.setVisibility(View.GONE); + mBinding.vDiv3.setVisibility(View.GONE); + mBinding.rlTeamJoinAuth.setVisibility(View.GONE); + mBinding.vDiv4.setVisibility(View.GONE); + mBinding.rlGroupStatistics.setVisibility(View.GONE); + mBinding.vDiv5.setVisibility(View.GONE); + break; + + case TeamMemberInfo.ROLE_TEAM_MEMBER: + mBinding.btnOperation.setText(R.string.btn_text_quit_team); + mBinding.rlTeamJoinAuth.setVisibility(View.GONE); + mBinding.llTeamManageLabel.setVisibility(View.GONE); + mBinding.llTeamManageContainer.setVisibility(View.GONE); + break; + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == SelectFriendActivity.CODE_REQUEST_TO_SHARE_TEAM && resultCode == RESULT_OK) { + String targetUid = data.getStringExtra(SelectFriendActivity.EXTRA_TARGET_UID); + String nick = data.getStringExtra(SelectFriendActivity.EXTRA_TARGET_NAME); + int sessionType = data.getIntExtra(SelectFriendActivity.EXTRA_SESSION_TYPE, SessionType.P2P); + IMNetEaseManager.get().sendSharingTeamMessage(sessionType, targetUid, mBinding.getTeamInfo()); + } + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.rl_team_member_count: + if (teamInfo == null) return; + if (TeamModel.get().getTeamInfoCache(teamInfo.getTid()).getRole() == TeamMemberInfo.ROLE_TEAM_OWNER || + TeamModel.get().getTeamInfoCache(teamInfo.getTid()).getRole() == TeamMemberInfo.ROLE_TEAM_MANAGER) { + TeamMemberListActivity.start(this, teamInfo.getTid(), teamInfo.getId(), TeamMemberListActivity.OP_TEAM_MEMBER_REMOVE); + } else { + TeamMemberListActivity.start(this, teamInfo.getTid(), teamInfo.getId(), TeamMemberListActivity.OP_TEAM_MEMBER_NORMAL); + } + break; + case R.id.rl_clear_chat_history: + displayClearChatHistoryDialog(); + break; + + case R.id.rl_team_icon: + if (teamInfo == null) return; + if (teamInfo.getRole() == TeamMemberInfo.ROLE_TEAM_MEMBER){ + return; + } + showTakePhotoOperationDialog(); + break; + + case R.id.rl_team_name: + if (teamInfo == null) return; + if (teamInfo.getRole() == TeamMemberInfo.ROLE_TEAM_MEMBER){ + return; + } + UpdateTeamNameActivity.start(this, teamInfo.getTid()); + break; + + case R.id.rl_set_team_managers: + if (teamInfo == null) return; + if (teamInfo.getRole() == TeamMemberInfo.ROLE_TEAM_MEMBER){ + return; + } + TeamMemberListActivity.start(this, teamInfo.getTid(), teamInfo.getId(), TeamMemberListActivity.OP_TEAM_MEMBER_MANAGEMENT); + break; + + case R.id.rl_team_mute_member: + if (teamInfo == null) return; + if (teamInfo.getRole() == TeamMemberInfo.ROLE_TEAM_MEMBER){ + return; + } + TeamMemberListActivity.start(this, teamInfo.getTid(), teamInfo.getId(), TeamMemberListActivity.OP_TEAM_MEMBER_MUTE); + break; + case R.id.rl_group_statistics: + TeamWeeklyBillActivity.start(this, teamInfo.getId()); + break; + + case R.id.btn_operation: + if (teamInfo == null) return; + // 根据用户的权限显示「退出群」dialog 还是 「删除群」dialog + switch (teamInfo.getRole()) { + case TeamMemberInfo.ROLE_TEAM_OWNER: + displayDeleteTeamDialog(); + break; + + case TeamMemberInfo.ROLE_TEAM_MANAGER: + case TeamMemberInfo.ROLE_TEAM_MEMBER: + displayQuitTeamDialog(); + break; + } + break; + } + } + + private void displayClearChatHistoryDialog() { + List buttonItems = new ArrayList<>(); + ButtonItem buttonItem1 = new ButtonItem(getString(R.string.text_clear_chat_history), () -> { + teamViewModel.clearChattingHistory(teamId); + MessageListPanelHelper.getInstance().notifyClearMessages(teamId); + toast(ResUtil.getString(R.string.team_view_nimteammanagementactivity_03)); + }); + buttonItems.add(buttonItem1); + + DialogManager dialogManager = getDialogManager(); + if (dialogManager != null) { + dialogManager.showCommonPopupDialog(buttonItems, getString(R.string.cancel)); + } + } + + private void displayDeleteTeamDialog() { + getDialogManager().showOkCancelWithTitleDialog(getString(R.string.tips_delete_team), + () -> teamViewModel.deleteTeam(teamInfo.getId(), teamInfo.getUid()) + .compose(bindToLifecycle()) + .subscribe((s, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + toast(ResUtil.getString(R.string.team_view_nimteammanagementactivity_04) + throwable.getMessage()); + } else { + toast(ResUtil.getString(R.string.team_view_nimteammanagementactivity_05)); + RxBus.get().post(new TeamEvent().setOperation(TeamEvent.OP_DELETE_TEAM)); + finish(); + } + })); + } + + private void displayQuitTeamDialog() { + String[] tips = new String[]{ResUtil.getString(R.string.team_view_nimteammanagementactivity_06), teamInfo.getName(), ResUtil.getString(R.string.team_view_nimteammanagementactivity_07)}; + getDialogManager().showOkCancelWithTitleDialog(tips, + () -> teamViewModel.quiteTeam(teamInfo.getId()) + .compose(bindToLifecycle()) + .subscribe((s, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + toast(ResUtil.getString(R.string.team_view_nimteammanagementactivity_08) + throwable.getMessage()); + } else { + toast(ResUtil.getString(R.string.team_view_nimteammanagementactivity_09)); + RxBus.get().post(new TeamEvent().setOperation(TeamEvent.OP_QUIT_TEAM)); + finish(); + } + })); + } + + @Override + public void onUploadSuccess(String url) { + teamViewModel.updateTeamIcon(teamInfo.getId(), url) + .compose(bindToLifecycle()) + .subscribe((teamInfo, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + toast(ResUtil.getString(R.string.team_view_nimteammanagementactivity_010)); + } else { + GlideApp.with(this) + .load(url) + .dontAnimate() + .into(mBinding.ivTeamIcon); + TeamModel.get().setTeamInfoCache(teamInfo.getTid(), teamInfo); + } + }); + } + + + /** + * 获取家族信息,决定输入面板的红包,家族游戏是否出现 + */ + private void requestFamilyInfo() { + if (FamilyModel.Instance().getMyFamily() != null) { + FamilyModel.Instance().loadFamilySimpleInfo( + FamilyModel.Instance().getMyFamily().getFamilyId() + ) + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onSuccess(FamilyInfo familyInfo) { + if (familyInfo.isOpenMoney()){ + mBinding.rlGroupStatistics.setVisibility(View.VISIBLE); + }else { + mBinding.rlGroupStatistics.setVisibility(View.GONE); + } + } + + @Override + public void onError(Throwable e) { + + } + }); + } + } + +} diff --git a/app/src/main/java/com/chwl/app/team/view/NimTeamMessageActivity.java b/app/src/main/java/com/chwl/app/team/view/NimTeamMessageActivity.java new file mode 100644 index 0000000..979e60f --- /dev/null +++ b/app/src/main/java/com/chwl/app/team/view/NimTeamMessageActivity.java @@ -0,0 +1,414 @@ +package com.chwl.app.team.view; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import com.netease.nim.uikit.api.NimUIKit; +import com.netease.nim.uikit.api.model.SimpleCallback; +import com.netease.nim.uikit.api.model.contact.ContactChangedObserver; +import com.netease.nim.uikit.api.model.session.SessionCustomization; +import com.netease.nim.uikit.api.model.team.TeamDataChangedObserver; +import com.netease.nim.uikit.api.model.team.TeamMemberDataChangedObserver; +import com.netease.nim.uikit.api.wrapper.NimToolBarOptions; +import com.netease.nim.uikit.business.ait.event.AitContactActionEvent; +import com.netease.nim.uikit.business.session.actions.BaseAction; +import com.netease.nim.uikit.business.session.actions.ImageAction; +import com.netease.nim.uikit.business.session.constant.Extras; +import com.netease.nim.uikit.business.session.fragment.MessageFragment; +import com.netease.nim.uikit.business.session.module.list.MessageListPanelEx; +import com.netease.nim.uikit.common.activity.ToolBarOptions; +import com.netease.nim.uikit.impl.NimUIKitImpl; +import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum; +import com.netease.nimlib.sdk.team.constant.TeamTypeEnum; +import com.netease.nimlib.sdk.team.model.Team; +import com.netease.nimlib.sdk.team.model.TeamMember; +import com.trello.rxlifecycle3.android.ActivityEvent; +import com.chwl.app.R; +import com.chwl.app.common.widget.DragLayout; +import com.chwl.app.team.viewmodel.TeamVM; +import com.chwl.app.ui.im.actions.FamilyGameAction; +import com.chwl.app.ui.im.actions.LuckyMoneyAction; +import com.chwl.app.ui.im.avtivity.BaseMessageActivity; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.family.bean.FamilyInfo; +import com.chwl.core.family.model.FamilyModel; +import com.chwl.core.initial.InitialModel; +import com.chwl.core.initial.bean.InitInfo; +import com.chwl.core.level.UserLevelVo; +import com.chwl.core.team.bean.TeamEvent; +import com.chwl.core.team.model.TeamModel; +import com.chwl.core.user.UserModel; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.library.rxbus.RxBus; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import io.reactivex.SingleObserver; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.schedulers.Schedulers; + +/** + * Created by MadisonRong on 24/05/2018. + */ + +public class NimTeamMessageActivity extends BaseMessageActivity { + + private static final String TAG = "NimTeamMessageActivity"; + + // model + private Team team; + + private View invalidTeamTipView; + + private TextView invalidTeamTipText; + + private ImageView managementView; + + private NimTeamMessageFragment fragment; + + private TeamVM teamViewModel; + + private DragLayout teamAvatarLayout; + private ImageView teamAvatar; + + public static void start(Context context, String tid) { + Intent intent = new Intent(); + intent.putExtra(Extras.EXTRA_ACCOUNT, tid); + intent.putExtra(Extras.EXTRA_CUSTOMIZATION, NimUIKitImpl.commonTeamSessionCustomization); + intent.setClass(context, NimTeamMessageActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); + + context.startActivity(intent); + } + + protected void findViews() { + invalidTeamTipView = findViewById(R.id.invalid_team_tip); + invalidTeamTipText = findViewById(R.id.invalid_team_text); + managementView = findViewById(R.id.iv_team_member_list); + teamAvatarLayout = (DragLayout) findViewById(R.id.avatar_image_layout); + teamAvatar = (ImageView) findViewById(R.id.avatar_image); + teamAvatarLayout.setOnClickListener(v -> { + }); + if (FamilyModel.Instance().getMyFamily() != null) { + ImageLoadUtils.loadAvatar(getApplicationContext(), FamilyModel.Instance().getMyFamily().getFamilyIcon(), + teamAvatar); + } + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + findViews(); + + teamViewModel = new TeamVM(); + + openTeamManagementPage(); + + registerTeamUpdateObserver(true); + + RxBus.get().toFlowable(TeamEvent.class) + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(teamEvent -> { + switch (teamEvent.getOperation()) { + case TeamEvent.OP_DELETE_TEAM: + case TeamEvent.OP_QUIT_TEAM: + requestTeamInfo(); + break; + + case TeamEvent.OP_UPDATE_MSG: + MessageListPanelEx messageListPanelEx = fragment.getMessageListPanelEx(); + int itemIndex = messageListPanelEx.getItemIndex(teamEvent.getMsgUuid()); + messageListPanelEx.refreshViewHolderByIndex(itemIndex); + break; + } + }); + EventBus.getDefault().register(this); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + registerTeamUpdateObserver(false); + EventBus.getDefault().unregister(this); + } + + @Override + protected void onStart() { + super.onStart(); + requestFamilyInfo(); + } + + @Override + protected void onResume() { + super.onResume(); + requestTeamInfo(); + } + + /** + * 获取家族信息,决定输入面板的红包,家族游戏是否出现 + */ + private void requestFamilyInfo() { + if (FamilyModel.Instance().getMyFamily() == null) { + return; + } + FamilyModel.Instance().loadFamilySimpleInfo( + FamilyModel.Instance().getMyFamily().getFamilyId() + ) + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onSuccess(FamilyInfo familyInfo) { + if (familyInfo.isOpenMoney()) { + SessionCustomization sessionCustomization = new SessionCustomization(); + ArrayList actions = new ArrayList<>(); + actions.add(new ImageAction()); + actions.add(new LuckyMoneyAction()); + if (familyInfo.isOpenGame()) { + actions.add(new FamilyGameAction()); + } + sessionCustomization.actions = actions; + sessionCustomization.withSticker = true; + fragment.reloadInputPanel(sessionCustomization); + } else { + SessionCustomization sessionCustomization = new SessionCustomization(); + ArrayList actions = new ArrayList<>(); + actions.add(new ImageAction()); + sessionCustomization.actions = actions; + sessionCustomization.withSticker = true; + fragment.reloadInputPanel(sessionCustomization); + } + } + + @Override + public void onError(Throwable e) { +// Toast.makeText(NimTeamMessageActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show(); + SingleToastUtil.showToastShort(e.getMessage()); + } + }); + } + + /** + * 强行完成@人页面的跳转 + * + * @see com.netease.nim.uikit.business.ait.AitManager 下的 afterTextChanged 方法里改掉原来的跳转逻辑, + * 通过 rxbus 的方式在这里打开我们的成员列表页面 + */ + @Subscribe(threadMode = ThreadMode.MAIN) + public void openAitTeamMemberPage(AitContactActionEvent event) { + String content = event.getContent(); + if (content != null && !Objects.equals(content, "") && content.endsWith("@")) { + TeamMemberListActivity.start(this, sessionId, + TeamModel.get().getTeamInfoCache(sessionId).getId(), TeamMemberListActivity.OP_TEAM_MEMBER_NORMAL); + } + } + + public void openTeamManagementPage() { + managementView.setOnClickListener(v -> { + NimTeamManagementActivity.start(this, team.getId()); + }); + } + + /** + * 请求群基本信息 + */ + private void requestTeamInfo() { + // 请求群基本信息 + Team t = NimUIKit.getTeamProvider().getTeamById(sessionId); + if (t != null) { + updateTeamInfo(t); + } else { + NimUIKit.getTeamProvider().fetchTeamById(sessionId, new SimpleCallback() { + @Override + public void onResult(boolean success, Team result, int code) { + if (success && result != null) { + updateTeamInfo(result); + } else { + onRequestTeamInfoFailed(); + } + } + }); + } + + teamViewModel.getTeamInfo(sessionId) + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .subscribe((teamInfo, throwable) -> { + if (teamInfo != null) { + TeamModel.get().setCurrentTeamInfo(teamInfo); + TeamModel.get().setTeamInfoCache(sessionId, teamInfo); + } + }); + } + + private void onRequestTeamInfoFailed() { +// Toast.makeText(NimTeamMessageActivity.this, ResUtil.getString(R.string.team_view_nimteammessageactivity_01), Toast.LENGTH_SHORT).show(); + SingleToastUtil.showToastShort(ResUtil.getString(R.string.team_view_nimteammessageactivity_02)); + finish(); + } + + /** + * 更新群信息 + * + * @param d + */ + private void updateTeamInfo(final Team d) { + if (d == null) { + return; + } + + team = d; + fragment.setTeam(team); + + setTitle(team == null ? sessionId : team.getName() + "(" + team.getMemberCount() + ResUtil.getString(R.string.team_view_nimteammessageactivity_03)); + + invalidTeamTipText.setText(team.getType() == TeamTypeEnum.Normal ? R.string.normal_team_invalid_tip : R.string.team_invalid_tip); + invalidTeamTipView.setVisibility(team.isMyTeam() ? View.GONE : View.VISIBLE); + + managementView.setVisibility(team.isMyTeam() ? View.VISIBLE : View.GONE); + teamAvatarLayout.setVisibility(team.isMyTeam() ? View.VISIBLE : View.GONE); + } + + @Override + public void setTitle(CharSequence title) { + super.setTitle(title); + getToolBar().setTitle(title); + } + + /** + * 注册群信息更新监听 + * + * @param register + */ + private void registerTeamUpdateObserver(boolean register) { + NimUIKit.getTeamChangedObservable().registerTeamDataChangedObserver(teamDataChangedObserver, register); + NimUIKit.getTeamChangedObservable().registerTeamMemberDataChangedObserver(teamMemberDataChangedObserver, register); + NimUIKit.getContactChangedObservable().registerObserver(friendDataChangedObserver, register); + } + + /** + * 群资料变动通知和移除群的通知(包括自己退群和群被解散) + */ + TeamDataChangedObserver teamDataChangedObserver = new TeamDataChangedObserver() { + @Override + public void onUpdateTeams(List teams) { + if (team == null) { + return; + } + for (Team t : teams) { + if (t.getId().equals(team.getId())) { + updateTeamInfo(t); + break; + } + } + } + + @Override + public void onRemoveTeam(Team team) { + if (team == null) { + return; + } + if (team.getId().equals(NimTeamMessageActivity.this.team.getId())) { + updateTeamInfo(team); + } + } + }; + + /** + * 群成员资料变动通知和移除群成员通知 + */ + TeamMemberDataChangedObserver teamMemberDataChangedObserver = new TeamMemberDataChangedObserver() { + + @Override + public void onUpdateTeamMember(List members) { + fragment.refreshMessageList(); + } + + @Override + public void onRemoveTeamMember(List member) { + Log.e(TAG, "onRemoveTeamMember() called with: member = [" + member + "]"); + } + }; + + ContactChangedObserver friendDataChangedObserver = new ContactChangedObserver() { + @Override + public void onAddedOrUpdatedFriends(List accounts) { + fragment.refreshMessageList(); + } + + @Override + public void onDeletedFriends(List accounts) { + fragment.refreshMessageList(); + } + + @Override + public void onAddUserToBlackList(List account) { + fragment.refreshMessageList(); + } + + @Override + public void onRemoveUserFromBlackList(List account) { + fragment.refreshMessageList(); + } + }; + + @Override + protected MessageFragment fragment() { + // 添加fragment + Bundle arguments = getIntent().getExtras(); + if (arguments != null) { + arguments.putSerializable(Extras.EXTRA_TYPE, SessionTypeEnum.Team); + } + fragment = new NimTeamMessageFragment(); + fragment.setArguments(arguments); + fragment.setContainerId(R.id.message_fragment_container); + + // 等级限制 + UserInfo userInfo = UserModel.get().getCacheLoginUserInfo(); + if (userInfo != null) { + UserLevelVo userLevelVo = userInfo.getUserLevelVo(); + if (userLevelVo != null) { + fragment.setCurrentLevel(userLevelVo.experLevelSeq); + } + } + InitInfo initInfo = InitialModel.get().getCacheInitInfo(); + if (initInfo != null) { + fragment.setLimitLevel(initInfo.getPrivateChatLevelNo()); + } + return fragment; + } + + @Override + protected int getContentViewId() { + return R.layout.activity_team_message; + } + + @Override + protected void initToolBar() { + ToolBarOptions options = new NimToolBarOptions(); + options.titleString = ResUtil.getString(R.string.team_view_nimteammessageactivity_04); + setToolBar(R.id.toolbar, options); + } + +} diff --git a/app/src/main/java/com/chwl/app/team/view/NimTeamMessageFragment.java b/app/src/main/java/com/chwl/app/team/view/NimTeamMessageFragment.java new file mode 100644 index 0000000..44f1ddd --- /dev/null +++ b/app/src/main/java/com/chwl/app/team/view/NimTeamMessageFragment.java @@ -0,0 +1,145 @@ +package com.chwl.app.team.view; + +import android.Manifest; +import android.annotation.SuppressLint; +import android.content.Context; +import android.os.Bundle; + +import com.netease.nim.uikit.business.session.fragment.MessageFragment; +import com.netease.nim.uikit.business.session.module.input.InputPanel; +import com.netease.nim.uikit.business.session.module.input.NimAudioChatEvent; +import com.netease.nim.uikit.business.session.module.input.NimImageActionEvent; +import com.netease.nim.uikit.business.session.module.list.MessageListPanelEx; +import com.netease.nimlib.sdk.NIMClient; +import com.netease.nimlib.sdk.msg.model.IMMessage; +import com.netease.nimlib.sdk.team.TeamService; +import com.netease.nimlib.sdk.team.model.Team; +import com.netease.nimlib.sdk.team.model.TeamMember; +import com.tbruyelle.rxpermissions2.RxPermissions; +import com.chwl.app.R; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.manager.IMMessageManager; +import com.chwl.library.utils.SingleToastUtil; + +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import io.reactivex.Observable; + +/** + * Created by MadisonRong on 10/07/2018. + */ + +public class NimTeamMessageFragment extends MessageFragment { + private Team team; + + private RxPermissions rxPermissions; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + rxPermissions = new RxPermissions(this); + } + + @Override + public boolean isAllowSendMessage(IMMessage message) { + if (team == null || !team.isMyTeam()) { +// Toast.makeText(getActivity(), R.string.team_send_message_not_allow, Toast.LENGTH_SHORT).show(); + SingleToastUtil.showToastShort(R.string.team_send_message_not_allow); + return false; + } + + return true; + } + + @Override + public void onResume() { + super.onResume(); + TeamMember teamMember = NIMClient.getService(TeamService.class) + .queryTeamMemberBlock(sessionId, String.valueOf(AuthModel.get().getCurrentUid())); + if (teamMember != null && teamMember.isMute()) { + inputPanel.disableButtons(); + } + } + + public void setTeam(Team team) { + this.team = team; + } + + public MessageListPanelEx getMessageListPanelEx() { + return messageListPanel; + } + + public InputPanel getInputPanel() { + return inputPanel; + } + + @Override + public List filterLoadedMessage(List messageList) { + if (messageList != null) { + messageList = IMMessageManager.filterMessage(messageList); + } + return messageList; + } + + // @Override + public void appendAPNSConfig(IMMessage message) { + + //iphone 手机通知标题配置 + Map apsField = new HashMap<>(); + Map alert = new HashMap<>(); + if (team != null) { + alert.put("title", team.getName()); + } + alert.put("body", message.getContent()); + apsField.put("alert", alert); + + if (message.getPushPayload() == null) { + Map payload = new HashMap<>(); + payload.put("apsField", apsField); + message.setPushPayload(payload); + } else { + message.getPushPayload().put("apsField", apsField); + } + } + + @SuppressLint("CheckResult") + public Observable checkPermission(String... mPerms) { + return rxPermissions.request(mPerms); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + @SuppressLint("CheckResult") + public void onNimAudioChatEvent(NimAudioChatEvent event) { + checkPermission(Manifest.permission.RECORD_AUDIO) + .subscribe(result -> { + if (result) { + event.getSuccess().accept(result); + } else { + SingleToastUtil.showToast(getString(R.string.ask_again)); + } + }); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + @SuppressLint("CheckResult") + public void onNimImageActionEvent(NimImageActionEvent event) { +// checkPermission(Manifest.permission.CAMERA) +// .subscribe(result -> { +// if (result) { +// event.getSuccess().accept(result); +// } else { +// SingleToastUtil.showToast(getString(R.string.ask_again)); +// } +// }); + } +} diff --git a/app/src/main/java/com/chwl/app/team/view/TeamListFragment.java b/app/src/main/java/com/chwl/app/team/view/TeamListFragment.java new file mode 100644 index 0000000..a3a16bb --- /dev/null +++ b/app/src/main/java/com/chwl/app/team/view/TeamListFragment.java @@ -0,0 +1,79 @@ +package com.chwl.app.team.view; + +import android.app.Activity; +import android.os.Bundle; + +import androidx.recyclerview.widget.LinearLayoutManager; + +import com.chwl.app.R; +import com.chwl.app.base.BaseBindingFragment; +import com.chwl.app.databinding.FragmentTeamListBinding; +import com.chwl.app.friend.action.AbstractSelectFriendAction; +import com.chwl.app.friend.view.SelectFriendActivity; +import com.chwl.app.team.adapter.TeamListAdapter; +import com.chwl.app.team.viewmodel.TeamVM; +import com.chwl.core.team.bean.TeamInfo; +import com.chwl.library.annatation.ActLayoutRes; +import com.chwl.library.utils.ListUtils; + +/** + * Created by MadisonRong on 11/06/2018. + */ +@ActLayoutRes(R.layout.fragment_team_list) +public class TeamListFragment extends BaseBindingFragment { + + private TeamListAdapter adapter; + private TeamVM teamViewModel; + private int type; + private SelectFriendActivity friendActivity; + + public static TeamListFragment newInstanceForSelect(int type){ + TeamListFragment fragment = new TeamListFragment(); + Bundle bundle = new Bundle(); + bundle.putInt(AbstractSelectFriendAction.KEY_TYPE, type); + fragment.setArguments(bundle); + return fragment; + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + + if (activity instanceof SelectFriendActivity){ + friendActivity = (SelectFriendActivity) activity; + } + } + + @Override + public void initiate() { + + if (getArguments() != null) { + type = getArguments().getInt(AbstractSelectFriendAction.KEY_TYPE, AbstractSelectFriendAction.TYPE_NORMAL); + } + + teamViewModel = new TeamVM(); + adapter = new TeamListAdapter(getContext()); + mBinding.recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); + mBinding.recyclerView.setAdapter(adapter); + adapter.setType(type); + adapter.setOnItemChildClickListener((adapter1, view, position) -> { + TeamInfo item = adapter.getItem(position); + if (friendActivity != null && item != null) { + friendActivity.shareToTeam(item.getTid(), item.getIcon(), item.getName()); + } + }); + } + + @Override + public void onResume() { + super.onResume(); + teamViewModel.queryJoin() + .subscribe((teamInfos, throwable) -> { + if (!ListUtils.isListEmpty(teamInfos)) { + adapter.setNewData(teamInfos); + adapter.notifyDataSetChanged(); + } + }); + } + +} diff --git a/app/src/main/java/com/chwl/app/team/view/TeamMemberListActivity.java b/app/src/main/java/com/chwl/app/team/view/TeamMemberListActivity.java new file mode 100644 index 0000000..37f5dbe --- /dev/null +++ b/app/src/main/java/com/chwl/app/team/view/TeamMemberListActivity.java @@ -0,0 +1,376 @@ +package com.chwl.app.team.view; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.view.View; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.SimpleItemAnimator; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chwl.app.R; +import com.chwl.app.base.BaseBindingActivity; +import com.chwl.app.base.TitleBar; +import com.chwl.app.databinding.ActivityTeamMemberListBinding; +import com.chwl.app.team.adapter.TeamMemberListAdapter; +import com.chwl.app.team.bean.NimTeamMember; +import com.chwl.app.team.event.TeamMemberUpdateEvent; +import com.chwl.app.team.viewmodel.TeamVM; +import com.chwl.core.family.bean.FamilyMemberInfo; +import com.chwl.core.team.bean.TeamInfo; +import com.chwl.core.team.bean.TeamMemberInfo; +import com.chwl.core.team.model.TeamModel; +import com.chwl.library.annatation.ActLayoutRes; +import com.chwl.library.rxbus.RxBusHelper; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; +import com.netease.nim.uikit.common.util.sys.NetworkUtil; +import com.netease.nimlib.sdk.NIMClient; +import com.netease.nimlib.sdk.team.TeamService; +import com.netease.nimlib.sdk.team.model.Team; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by MadisonRong on 30/05/2018. + */ +@ActLayoutRes(R.layout.activity_team_member_list) +public class TeamMemberListActivity extends BaseBindingActivity + implements TeamMemberListAdapter.OnOperationButtonClickedListener, TeamMemberListAdapter.OnItemClickListener { + + private static final String TAG = "TeamMemberListActivity"; + + public static final String EXTRA_ID = "EXTRA_ID"; + public static final String EXTRA_TEAM_ID = "EXTRA_TEAM_ID"; + public static final int FIRST_PAGE = 1; + + public static final int REQUEST_CODE = 0x10; + public static final String RESULT_TYPE = "type"; + public static final String RESULT_DATA = "data"; + public static final int TYPE_SELECT_AIT_MEMBER = 2; + + public static final String KEY_OPERATION_TYPE = "KEY_OPERATION_TYPE"; + + public static final int OP_TEAM_MEMBER_NORMAL = 0; + public static final int OP_TEAM_MEMBER_REMOVE = 1; + public static final int OP_TEAM_MEMBER_MANAGEMENT = 2; + public static final int OP_TEAM_MEMBER_MUTE = 3; + + private String tid; + private String chatId; + private int type; + private int page = FIRST_PAGE; + private boolean isLoading = false; + private TeamMemberListAdapter teamMemberListAdapter; + private TeamVM teamViewModel; + private TeamInfo teamInfo; + + private TitleBar.Action addMemberAction = new TitleBar.Action() { + @Override + public String getText() { + return null; + } + + @Override + public int getDrawable() { + return R.drawable.ic_family_add; + } + + @Override + public int getTextColor() { + return 0; + } + + @Override + public int getTextDrawableLeft() { + return 0; + } + + @Override + public void performAction(View view) { + AddMemberActivity.start(TeamMemberListActivity.this, tid); + } + }; + + private TitleBar.Action searchAction = new TitleBar.Action() { + @Override + public String getText() { + return null; + } + + @Override + public int getDrawable() { + return R.drawable.ic_family_search; + } + + @Override + public int getTextColor() { + return 0; + } + + @Override + public int getTextDrawableLeft() { + return 0; + } + + @Override + public void performAction(View view) { + TeamMemberSearchListActivity.start(TeamMemberListActivity.this, teamInfo.getTid(), type); + } + }; + + + public static void start(Context context, String tid, String chatId, int type) { + Intent intent = new Intent(context, TeamMemberListActivity.class); + intent.putExtra(KEY_OPERATION_TYPE, type); + intent.putExtra(EXTRA_ID, chatId); + intent.putExtra(EXTRA_TEAM_ID, tid); + ((Activity) context).startActivityForResult(intent, REQUEST_CODE); + } + + @Override + protected void init() { + initTitleBar(getString(R.string.title_team_member_list)); + teamViewModel = new TeamVM(); + + type = getIntent().getIntExtra(KEY_OPERATION_TYPE, OP_TEAM_MEMBER_NORMAL); + chatId = getIntent().getStringExtra(EXTRA_ID); + tid = getIntent().getStringExtra(EXTRA_TEAM_ID); + mBinding.titleBar.addAction(searchAction); + if (type == OP_TEAM_MEMBER_REMOVE && ( + TeamModel.get().getTeamInfoCache(tid).getRole() == TeamMemberInfo.ROLE_TEAM_OWNER || + TeamModel.get().getTeamInfoCache(tid).getRole() == TeamMemberInfo.ROLE_TEAM_MANAGER)) { + mBinding.titleBar.addAction(addMemberAction); + } + + + teamMemberListAdapter = new TeamMemberListAdapter(this, type); + mBinding.rvMember.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)); + + teamMemberListAdapter.setOnLoadMoreListener(() -> { + if (!NetworkUtil.isNetAvailable(TeamMemberListActivity.this)) { + teamMemberListAdapter.loadMoreComplete(); + return; + } + loadData(page); + }, mBinding.rvMember); + + mBinding.rvMember.setAdapter(teamMemberListAdapter); + teamMemberListAdapter.setOnOperationButtonClickedListener(this); + teamMemberListAdapter.setOnItemClickListener(this); + mBinding.rvMember.getItemAnimator().setChangeDuration(0); + ((SimpleItemAnimator) mBinding.rvMember.getItemAnimator()).setSupportsChangeAnimations(false); + + updateTeamMemberCount(String.valueOf(TeamModel.get().getTeamInfoCache(tid).getMemberCount())); + + teamInfo = TeamModel.get().getTeamInfoCache(tid); + + showLoading(); + mBinding.setClick(this); + + mBinding.srlMemberList.setOnRefreshListener(() -> { + if (!NetworkUtil.isNetAvailable(TeamMemberListActivity.this)) { + mBinding.srlMemberList.setRefreshing(false); + return; + } + firstLoad(); + }); + + firstLoad(); + + addRxEvent(); + } + + private void addRxEvent() { + /** + * 家族成员更新 + */ + RxBusHelper.doOnMainThread(TeamMemberUpdateEvent.class, mCompositeDisposable, teamMemberUpdate -> firstLoad()); + } + + private void firstLoad() { + loadData(FIRST_PAGE); + } + + private void loadData(int targetPage) { + if (isLoading) { + return; + } + this.page = targetPage; + isLoading = true; + teamViewModel.getTeamMemberList(chatId, String.valueOf(page)) + .compose(bindToLifecycle()) + .subscribe((respTeamMemberInfo, throwable) -> { + isLoading = false; + mBinding.srlMemberList.setRefreshing(false); + if (throwable != null) { + toast(throwable.getMessage()); + return; + } + List teamMemberInfos = respTeamMemberInfo.getMemberList(); + if (!ListUtils.isListEmpty(teamMemberInfos)) { + hideStatus(); + if (page == FIRST_PAGE) { + teamMemberListAdapter.setNewData(teamMemberInfos); + } else { + teamMemberListAdapter.addData(teamMemberInfos); + teamMemberListAdapter.loadMoreComplete(); + } + page++; + } else { + finishLoadingData(); + } + updateTeamMemberCount(String.valueOf(respTeamMemberInfo.getCount())); + }); + } + + private void updateTeamMemberCount(String memberCount) { + mBinding.tvMemberCount.setText(getString(R.string.family_member_label2, memberCount)); + } + + private void finishLoadingData() { + if (page == FIRST_PAGE) { + showNoData(); + mBinding.srlMemberList.setRefreshing(false); + } else { + teamMemberListAdapter.loadMoreEnd(true); + } + } + + @Override + protected void onResume() { + super.onResume(); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (resultCode == RESULT_OK) { + switch (requestCode) { + case AddMemberActivity.REQUEST_CODE_SELECT_MEMBER: + ArrayList listExtra = (ArrayList) data.getSerializableExtra(AddMemberActivity.EXTRA_SELECTED_MEMBER); + if (listExtra != null) { + List selectMemberUids = new ArrayList<>(); + for (FamilyMemberInfo familyMemberInfo : listExtra) { + selectMemberUids.add(String.valueOf(familyMemberInfo.getUid())); + } + String[] newMembers = new String[selectMemberUids.size()]; + newMembers = selectMemberUids.toArray(newMembers); + // 添加成员,并且刷新列表 + teamViewModel.addMemberToTeam(chatId, newMembers) + .subscribe((s, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + } else { + firstLoad(); + } + }); + } + break; + } + } + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.ll_search: + TeamMemberSearchListActivity.start(this, teamInfo.getTid(), type); + break; + } + } + + @Override + public void onOperationButtonClicked(int position, TeamMemberInfo teamMemberInfo, int type) { + switch (type) { + default: + case TeamMemberListActivity.OP_TEAM_MEMBER_NORMAL: + break; + + case TeamMemberListActivity.OP_TEAM_MEMBER_REMOVE: + getDialogManager().showOkCancelWithTitleDialog(new String[]{ResUtil.getString(R.string.team_view_teammemberlistactivity_01), teamMemberInfo.getNick(), ResUtil.getString(R.string.team_view_teammemberlistactivity_02)}, + () -> teamViewModel.kickOutTeamMember(chatId, String.valueOf(teamMemberInfo.getUid())) + .compose(bindToLifecycle()) + .subscribe((s, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + toast(throwable.getMessage()); + } else { + teamMemberListAdapter.remove(position); + Team team = NIMClient.getService(TeamService.class).queryTeamBlock(tid); + updateTeamMemberCount(String.valueOf(team.getMemberCount())); + } + })); + break; + + case TeamMemberListActivity.OP_TEAM_MEMBER_MANAGEMENT: + boolean wannaSetManager = !(teamMemberInfo.getRole() == TeamMemberInfo.ROLE_TEAM_MANAGER); + String[] message = wannaSetManager ? new String[]{ResUtil.getString(R.string.team_view_teammemberlistactivity_03), teamMemberInfo.getNick(), ResUtil.getString(R.string.team_view_teammemberlistactivity_04)} + : new String[]{ResUtil.getString(R.string.team_view_teammemberlistactivity_05), teamMemberInfo.getNick(), ResUtil.getString(R.string.team_view_teammemberlistactivity_06)}; + getDialogManager().showOkCancelWithTitleDialog(message, () -> + teamViewModel.setTeamManager(chatId, String.valueOf(teamMemberInfo.getUid()), wannaSetManager) + .compose(bindToLifecycle()) + .subscribe((s, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + toast(throwable.getMessage()); + } else { + teamMemberInfo.setRole(wannaSetManager ? TeamMemberInfo.ROLE_TEAM_MANAGER : TeamMemberInfo.ROLE_TEAM_MEMBER); + teamInfo.setManagerCount(wannaSetManager ? teamInfo.getManagerCount() + 1 : teamInfo.getManagerCount() - 1); + teamMemberListAdapter.notifyItemChanged(position); + } + })); + break; + + case TeamMemberListActivity.OP_TEAM_MEMBER_MUTE: + boolean wannaMute = !teamMemberInfo.isDisable(); + if (wannaMute) { + getDialogManager().showOkCancelWithTitleDialog( + new String[]{ResUtil.getString(R.string.team_view_teammemberlistactivity_07), teamMemberInfo.getNick(), ResUtil.getString(R.string.team_view_teammemberlistactivity_08)}, + () -> + muteTeamMember(teamMemberInfo, true, position)); + } else { + muteTeamMember(teamMemberInfo, false, position); + } + break; + } + } + + private void muteTeamMember(TeamMemberInfo teamMemberInfo, boolean wannaMute, int position) { + teamViewModel.muteTeamMember(chatId, String.valueOf(teamMemberInfo.getUid()), wannaMute) + .compose(bindToLifecycle()) + .subscribe((s, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + toast(ResUtil.getString(R.string.team_view_teammemberlistactivity_09)); + } else { + teamMemberInfo.setDisable(wannaMute); + teamInfo.setDisabledCount(wannaMute ? + teamInfo.getDisabledCount() + 1 : + teamInfo.getDisabledCount() - 1); + teamMemberListAdapter.notifyItemChanged(position); + } + }); + } + + @Override + public void onItemClick(BaseQuickAdapter adapter, View view, int position) { + switch (type) { + case TeamMemberListActivity.OP_TEAM_MEMBER_NORMAL: + Intent intent = new Intent(); + TeamMemberInfo teamMemberInfo = (TeamMemberInfo) adapter.getItem(position); + if (teamMemberInfo != null) { + NimTeamMember teamMember = new NimTeamMember(); + teamMember.setTid(tid); + teamMember.setAccount(String.valueOf(teamMemberInfo.getUid())); + teamMember.setTeamNick(teamMemberInfo.getTeamNick()); + intent.putExtra(RESULT_DATA, teamMember); + intent.putExtra(RESULT_TYPE, TYPE_SELECT_AIT_MEMBER); + } + setResult(RESULT_OK, intent); + finish(); + break; + } + } +} diff --git a/app/src/main/java/com/chwl/app/team/view/TeamMemberSearchListActivity.java b/app/src/main/java/com/chwl/app/team/view/TeamMemberSearchListActivity.java new file mode 100644 index 0000000..df01e35 --- /dev/null +++ b/app/src/main/java/com/chwl/app/team/view/TeamMemberSearchListActivity.java @@ -0,0 +1,290 @@ +package com.chwl.app.team.view; + +import static com.chwl.app.team.view.TeamMemberListActivity.EXTRA_ID; +import static com.chwl.app.team.view.TeamMemberListActivity.KEY_OPERATION_TYPE; +import static com.chwl.app.team.view.TeamMemberListActivity.OP_TEAM_MEMBER_NORMAL; +import static com.chwl.app.team.view.TeamMemberListActivity.REQUEST_CODE; +import static com.chwl.app.team.view.TeamMemberListActivity.RESULT_DATA; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.inputmethod.EditorInfo; + +import androidx.recyclerview.widget.LinearLayoutManager; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chwl.app.R; +import com.chwl.app.base.BaseBindingActivity; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.app.databinding.ActivityTeamMemberSearchListBinding; +import com.chwl.app.team.adapter.TeamMemberListAdapter; +import com.chwl.app.team.bean.NimTeamMember; +import com.chwl.app.team.event.TeamMemberUpdateEvent; +import com.chwl.app.team.viewmodel.TeamVM; +import com.chwl.core.team.bean.TeamInfo; +import com.chwl.core.team.bean.TeamMemberInfo; +import com.chwl.core.team.model.TeamModel; +import com.chwl.library.annatation.ActLayoutRes; +import com.chwl.library.rxbus.RxBusHelper; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; + +import java.util.Iterator; + +/** + * Created by MadisonRong on 31/05/2018. + */ +@ActLayoutRes(R.layout.activity_team_member_search_list) +public class TeamMemberSearchListActivity extends BaseBindingActivity + implements TeamMemberListAdapter.OnOperationButtonClickedListener, TeamMemberListAdapter.OnItemClickListener { + + private String tid; + private int type; + private TeamMemberListAdapter teamMemberListAdapter; + private TeamVM teamViewModel; + private TeamInfo teamInfo; + + public static void start(Context context, String tid, int type) { + Intent intent = new Intent(context, TeamMemberSearchListActivity.class); + intent.putExtra(KEY_OPERATION_TYPE, type); + intent.putExtra(EXTRA_ID, tid); + ((Activity) context).startActivityForResult(intent, REQUEST_CODE); + } + + @Override + protected void init() { + teamViewModel = new TeamVM(); + + type = getIntent().getIntExtra(KEY_OPERATION_TYPE, OP_TEAM_MEMBER_NORMAL); + tid = getIntent().getStringExtra(EXTRA_ID); + + teamInfo = TeamModel.get().getTeamInfoCache(tid); + + teamMemberListAdapter = new TeamMemberListAdapter(this, type); + mBinding.recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)); + mBinding.recyclerView.setAdapter(teamMemberListAdapter); + teamMemberListAdapter.setOnOperationButtonClickedListener(this); + teamMemberListAdapter.setOnItemClickListener(this); + View headerView = LayoutInflater.from(this).inflate(R.layout.layout_search_header, null, false); + teamMemberListAdapter.addHeaderView(headerView); + + mBinding.searchEdit.addTextChangedListener(textWatcher); + mBinding.searchEdit.setImeOptions(EditorInfo.IME_ACTION_SEARCH); + mBinding.searchEdit.setOnEditorActionListener((v, actionId, event) -> { + if (actionId == EditorInfo.IME_ACTION_SEARCH || (event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) { + String str = v.getText().toString(); + if (!searchMemberList(str)) return false; + hideIME(); + return true; + } + return false; + + }); + + mBinding.ivClearText.setVisibility(View.GONE); + + mBinding.setClick(this); + + } + + private TextWatcher textWatcher = new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + if (TextUtils.isEmpty(s.toString())) { + mBinding.ivClearText.setVisibility(View.GONE); + } else { + mBinding.ivClearText.setVisibility(View.VISIBLE); + } + } + }; + + @Override + public void onClick(View v) { + int id = v.getId(); + if (id == mBinding.ivBack.getId()) { + hideIME(); + finish(); + } else if (id == mBinding.tvSearch.getId()) { + String str = mBinding.searchEdit.getText().toString(); + if (searchMemberList(str)) return; + hideIME(); + + } else if (id == mBinding.ivClearText.getId()) { + mBinding.searchEdit.setText(""); + } + + } + + private boolean searchMemberList(String str) { + if (TextUtils.isEmpty(str)) { +// Toast.makeText(this, ResUtil.getString(R.string.team_view_teammembersearchlistactivity_01), Toast.LENGTH_SHORT).show(); + SingleToastUtil.showToastShort(ResUtil.getString(R.string.team_view_teammembersearchlistactivity_02)); + return true; + } + showLoading(); + + teamViewModel.queryErbanNo(teamInfo.getId(), str, 1) + .compose(bindToLifecycle()) + .subscribe((teamMemberInfos, throwable) -> { + hideStatus(); + if (throwable != null) { + throwable.printStackTrace(); +// toast(throwable.getMessage()); + showPageError(0); + } else { + if (!ListUtils.isListEmpty(teamMemberInfos)) { + teamMemberListAdapter.setNewData(teamMemberInfos); + } else { + showNoData(); + } + } + }); + + return false; + } + + @Override + public void onOperationButtonClicked(int position, TeamMemberInfo teamMemberInfo, int type) { + switch (type) { + default: + case OP_TEAM_MEMBER_NORMAL: + break; + + case TeamMemberListActivity.OP_TEAM_MEMBER_REMOVE: + getDialogManager().showTipsDialog(getString(R.string.dialog_tips_remove_team_member, teamMemberInfo.getNick()), + new DialogManager.OkCancelDialogListener() { + @Override + public void onCancel() { + + } + + @Override + public void onOk() { + teamViewModel.kickOutTeamMember(teamInfo.getId(), String.valueOf(teamMemberInfo.getUid())) + .compose(bindToLifecycle()) + .subscribe((s, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + toast(throwable.getMessage()); + } else { + toast(ResUtil.getString(R.string.team_view_teammembersearchlistactivity_03)); + RxBusHelper.post(new TeamMemberUpdateEvent()); + Iterator iterator = teamMemberListAdapter.getData().iterator(); + while (iterator.hasNext()){ + TeamMemberInfo item = iterator.next(); + if (item.getId().equals(teamMemberInfo.getId())){ + iterator.remove(); + break; + } + } + teamMemberListAdapter.notifyDataSetChanged(); + + } + }); + } + }); + break; + + case TeamMemberListActivity.OP_TEAM_MEMBER_MANAGEMENT: + boolean wannaSetManager = !(teamMemberInfo.getRole() == TeamMemberInfo.ROLE_TEAM_MANAGER); + String message = wannaSetManager ? getString(R.string.dialog_tips_set_manager, teamMemberInfo.getNick()) + : getString(R.string.dialog_tips_cancel_set_manager, teamMemberInfo.getNick()); + getDialogManager().showTipsDialog(message, new DialogManager.OkCancelDialogListener() { + @Override + public void onCancel() { + + } + + @Override + public void onOk() { + teamViewModel.setTeamManager(teamInfo.getId(), String.valueOf(teamMemberInfo.getUid()), wannaSetManager) + .compose(bindToLifecycle()) + .subscribe((s, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + toast(throwable.getMessage()); + } else { + teamMemberInfo.setRole(wannaSetManager ? TeamMemberInfo.ROLE_TEAM_MANAGER : TeamMemberInfo.ROLE_TEAM_MEMBER); + teamInfo.setManagerCount(wannaSetManager ? teamInfo.getManagerCount() + 1 : teamInfo.getManagerCount() - 1); + teamMemberListAdapter.notifyItemChanged(position); + } + }); + } + }); + break; + + case TeamMemberListActivity.OP_TEAM_MEMBER_MUTE: + boolean wannaMute = !teamMemberInfo.isDisable(); + if (wannaMute) { + getDialogManager().showTipsDialog( + getString(R.string.dialog_tips_mute_team_member, teamMemberInfo.getNick()), + new DialogManager.OkCancelDialogListener() { + @Override + public void onCancel() { + + } + + @Override + public void onOk() { + muteTeamMember(teamMemberInfo, true, position); + } + }); + } else { + muteTeamMember(teamMemberInfo, false, position); + } + } + } + + private void muteTeamMember(TeamMemberInfo teamMemberInfo, boolean wannaMute, int position) { + teamViewModel.muteTeamMember(teamInfo.getId(), String.valueOf(teamMemberInfo.getUid()), wannaMute) + .compose(bindToLifecycle()) + .subscribe((s, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + toast(ResUtil.getString(R.string.error_tips)); + } else { + teamMemberInfo.setDisable(wannaMute); + teamInfo.setDisabledCount(wannaMute ? + teamInfo.getDisabledCount() + 1 : + teamInfo.getDisabledCount() - 1); + teamMemberListAdapter.notifyItemChanged(position); + } + }); + } + + @Override + public void onItemClick(BaseQuickAdapter adapter, View view, int position) { + switch (type) { + case OP_TEAM_MEMBER_NORMAL: + Intent intent = new Intent(); + TeamMemberInfo teamMemberInfo = (TeamMemberInfo) adapter.getItem(position); + if (teamMemberInfo != null) { + NimTeamMember teamMember = new NimTeamMember(); + teamMember.setTid(tid); + teamMember.setAccount(teamMemberInfo.getAccount()); + teamMember.setTeamNick(teamMemberInfo.getTeamNick()); + intent.putExtra(RESULT_DATA, teamMember); + } + setResult(RESULT_OK, intent); + finish(); + break; + } + } +} diff --git a/app/src/main/java/com/chwl/app/team/view/TeamWeeklyBillActivity.java b/app/src/main/java/com/chwl/app/team/view/TeamWeeklyBillActivity.java new file mode 100644 index 0000000..ffcee02 --- /dev/null +++ b/app/src/main/java/com/chwl/app/team/view/TeamWeeklyBillActivity.java @@ -0,0 +1,168 @@ +package com.chwl.app.team.view; + +import android.content.Context; +import android.content.Intent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import androidx.recyclerview.widget.LinearLayoutManager; + +import com.chwl.app.R; +import com.chwl.app.base.BaseBindingActivity; +import com.chwl.app.databinding.ActivityTeamWeeklyBillBinding; +import com.chwl.app.team.adapter.TeamWeeklyBillAdapter; +import com.chwl.app.team.viewmodel.TeamVM; +import com.chwl.core.family.model.FamilyModel; +import com.chwl.core.team.bean.TeamTransactionRecordInfo; +import com.chwl.library.annatation.ActLayoutRes; +import com.chwl.library.utils.FormatUtils; +import com.chwl.library.utils.ListUtils; +import com.netease.nim.uikit.common.util.sys.NetworkUtil; +import com.scwang.smart.refresh.layout.api.RefreshLayout; +import com.scwang.smart.refresh.layout.listener.OnRefreshLoadMoreListener; + +import java.util.List; + +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; + +; +; + +/** + * Created by MadisonRong on 31/05/2018. + */ +@ActLayoutRes(R.layout.activity_team_weekly_bill) +public class TeamWeeklyBillActivity extends BaseBindingActivity + implements OnRefreshLoadMoreListener { + + public static final int PAGE_FIRST = 1; + + private String chatId; + private TeamVM teamViewModel; + private TeamWeeklyBillAdapter teamWeeklyBillAdapter; + private View headerView; + private View emptyView; + private int page = PAGE_FIRST; + + public static void start(Context context, String chatId) { + Intent intent = new Intent(context, TeamWeeklyBillActivity.class); + intent.putExtra(TeamMemberListActivity.EXTRA_ID, chatId); + context.startActivity(intent); + } + + @Override + protected void init() { + initTitleBar(getString(R.string.title_team_statistics)); + chatId = getIntent().getStringExtra(TeamMemberListActivity.EXTRA_ID); + + mBinding.rvFamilyCurrency.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)); + teamWeeklyBillAdapter = new TeamWeeklyBillAdapter(this); + teamWeeklyBillAdapter.setEnableLoadMore(true); + mBinding.rvFamilyCurrency.setAdapter(teamWeeklyBillAdapter); + mBinding.swipeRefresh.setOnRefreshLoadMoreListener(this); + + teamViewModel = new TeamVM(); + + mBinding.setClick(this); + + emptyView = LayoutInflater.from(this).inflate(R.layout.fragment_no_data, null, false); + RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); + emptyView.setLayoutParams(layoutParams); + + headerView = LayoutInflater.from(this).inflate(R.layout.header_team_currency_bill, null, false); + teamWeeklyBillAdapter.setHeaderView(headerView); + teamWeeklyBillAdapter.setHeaderAndEmpty(true); + headerView.findViewById(R.id.ll_search).setOnClickListener(this); + } + + @Override + protected void onResume() { + super.onResume(); + firstLoad(); + } + + private void firstLoad() { + page = PAGE_FIRST; + loadBill(); + } + + private void loadBill() { + teamViewModel.queryTeamTransactionRecords(chatId, page) + .compose(bindToLifecycle()) + .subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe((transactionRecordInfos, throwable) -> { + updateHeaderView(FormatUtils.formatToShortDown(transactionRecordInfos.getWeekAmount()), + FormatUtils.formatToShortDown(transactionRecordInfos.getTotalAmount())); + List weekRecords = transactionRecordInfos.getWeekRecords(); + if (!ListUtils.isListEmpty(weekRecords)) { + teamWeeklyBillAdapter.setEnableLoadMore(true); + mBinding.swipeRefresh.setEnableLoadMore(true); + if (page == PAGE_FIRST) { + teamWeeklyBillAdapter.setNewData(weekRecords); + mBinding.swipeRefresh.finishRefresh(); + } else { + teamWeeklyBillAdapter.addData(weekRecords); + mBinding.swipeRefresh.finishLoadMore(); + } + page ++; + } + finishLoadingData(); + }); + } + + private void finishLoadingData() { + if (page == PAGE_FIRST) { + mBinding.swipeRefresh.finishRefresh(); + teamWeeklyBillAdapter.setEmptyView(emptyView); + teamWeeklyBillAdapter.setEnableLoadMore(false); + mBinding.swipeRefresh.setEnableLoadMore(false); + } else { + mBinding.swipeRefresh.finishLoadMore(); + } + } + + public void updateHeaderView(String weekAmount, String totalAmount) { + String coinName = FamilyModel.Instance().getMyFamily().getMoneyName(); + ((TextView) headerView.findViewById(R.id.tv_team_currency_weekly_bill)) + .setText(getString(R.string.text_team_currency_weekly_bill, coinName)); + ((TextView) headerView.findViewById(R.id.tv_team_currency_balance)).setText(weekAmount); + ((TextView) headerView.findViewById(R.id.tv_team_currency_income)).setText(totalAmount + coinName); + } + + @Override + public void onLoadMore(RefreshLayout refreshlayout) { + if (!NetworkUtil.isNetAvailable(TeamWeeklyBillActivity.this)) { + mBinding.swipeRefresh.finishLoadMore(); + return; + } + List data = teamWeeklyBillAdapter.getData(); + if (ListUtils.isListEmpty(data)) { + mBinding.swipeRefresh.finishLoadMore(); + return; + } + loadBill(); + } + + @Override + public void onRefresh(RefreshLayout refreshlayout) { + if (!NetworkUtil.isNetAvailable(TeamWeeklyBillActivity.this)) { + mBinding.swipeRefresh.finishRefresh(); + return; + } + firstLoad(); + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.ll_search: + TeamWeeklyBillSearchActivity.start(this, chatId); + break; + } + } +} diff --git a/app/src/main/java/com/chwl/app/team/view/TeamWeeklyBillSearchActivity.java b/app/src/main/java/com/chwl/app/team/view/TeamWeeklyBillSearchActivity.java new file mode 100644 index 0000000..97fe590 --- /dev/null +++ b/app/src/main/java/com/chwl/app/team/view/TeamWeeklyBillSearchActivity.java @@ -0,0 +1,197 @@ +package com.chwl.app.team.view; + +import android.content.Context; +import android.content.Intent; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.LayoutInflater; +import android.view.View; +import android.view.inputmethod.EditorInfo; + +import androidx.recyclerview.widget.LinearLayoutManager; + +import com.chwl.app.R; +import com.chwl.app.base.BaseBindingActivity; +import com.chwl.app.databinding.ActivityTeamWeeklyBillSearchBinding; +import com.chwl.app.team.adapter.TeamWeeklyBillAdapter; +import com.chwl.app.team.viewmodel.TeamVM; +import com.chwl.core.team.bean.TeamTransactionRecordInfo; +import com.chwl.library.annatation.ActLayoutRes; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; +import com.netease.nim.uikit.common.util.sys.NetworkUtil; +import com.scwang.smart.refresh.layout.api.RefreshLayout; +import com.scwang.smart.refresh.layout.listener.OnRefreshLoadMoreListener; + +import java.util.List; + +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; + +; +; + +/** + * Created by MadisonRong on 20/07/2018. + */ +@ActLayoutRes(R.layout.activity_team_weekly_bill_search) +public class TeamWeeklyBillSearchActivity extends BaseBindingActivity + implements OnRefreshLoadMoreListener { + + public static final int PAGE_FIRST = 1; + + private String chatId; + private TeamWeeklyBillAdapter teamWeeklyBillAdapter; + private TeamVM teamViewModel; + private int page = PAGE_FIRST; + + public static void start(Context context, String chatId) { + Intent intent = new Intent(context, TeamWeeklyBillSearchActivity.class); + intent.putExtra(TeamMemberListActivity.EXTRA_ID, chatId); + context.startActivity(intent); + } + + @Override + protected void init() { + chatId = getIntent().getStringExtra(TeamMemberListActivity.EXTRA_ID); + + mBinding.rvFamilyCurrency.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)); + teamWeeklyBillAdapter = new TeamWeeklyBillAdapter(this); + teamWeeklyBillAdapter.setEnableLoadMore(true); + mBinding.rvFamilyCurrency.setAdapter(teamWeeklyBillAdapter); + mBinding.swipeRefresh.setOnRefreshLoadMoreListener(this); + + teamViewModel = new TeamVM(); + + View headerView = LayoutInflater.from(this).inflate(R.layout.layout_search_header, null, false); + teamWeeklyBillAdapter.addHeaderView(headerView); + + mBinding.searchEdit.addTextChangedListener(textWatcher); + mBinding.searchEdit.setImeOptions(EditorInfo.IME_ACTION_SEARCH); +// mBinding.searchEdit.setOnEditorActionListener((v, actionId, event) -> { +// if (actionId == EditorInfo.IME_ACTION_SEARCH || (event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) { +// String str = v.getText().toString(); +// if (!searchMemberList(str)) return false; +// hideIME(); +// return true; +// } +// return false; +// +// }); + + mBinding.ivClearText.setVisibility(View.GONE); + + mBinding.setClick(this); + } + + private TextWatcher textWatcher = new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + if (TextUtils.isEmpty(s.toString())) { + mBinding.ivClearText.setVisibility(View.GONE); + } else { + mBinding.ivClearText.setVisibility(View.VISIBLE); + } + } + }; + + @Override + public void onClick(View v) { + int id = v.getId(); + if (id == mBinding.ivBack.getId()) { + hideIME(); + finish(); + } else if (id == mBinding.tvSearch.getId()) { + String str = mBinding.searchEdit.getText().toString(); + if (searchMemberList(str)) return; + hideIME(); + + } else if (id == mBinding.ivClearText.getId()) { + mBinding.searchEdit.setText(""); + } + + } + + private boolean searchMemberList(String str) { + if (TextUtils.isEmpty(str)) { +// Toast.makeText(this, ResUtil.getString(R.string.team_view_teamweeklybillsearchactivity_01), Toast.LENGTH_SHORT).show(); + SingleToastUtil.showToastShort(ResUtil.getString(R.string.team_view_teamweeklybillsearchactivity_02)); + return true; + } + showLoading(); + + loadBill(); + + return false; + } + + private void firstLoad() { + page = PAGE_FIRST; + loadBill(); + } + + private void loadBill() { + teamViewModel.searchTeamTransactionRecords(chatId, mBinding.searchEdit.getText().toString(), page) + .compose(bindToLifecycle()) + .subscribeOn(Schedulers.computation()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe((transactionRecordInfos, throwable) -> { + List weekRecords = transactionRecordInfos.getWeekRecords(); + if (!ListUtils.isListEmpty(weekRecords)) { + hideStatus(); + if (page == PAGE_FIRST) { + teamWeeklyBillAdapter.setNewData(weekRecords); + mBinding.swipeRefresh.finishRefresh(); + } else { + teamWeeklyBillAdapter.addData(weekRecords); + mBinding.swipeRefresh.finishLoadMore(); + } + page++; + } + finishLoadingData(); + }); + } + + private void finishLoadingData() { + if (page == PAGE_FIRST) { + showNoData(); + mBinding.swipeRefresh.finishRefresh(); + } else { + mBinding.swipeRefresh.finishLoadMore(); + } + } + + @Override + public void onLoadMore(RefreshLayout refreshlayout) { + if (!NetworkUtil.isNetAvailable(TeamWeeklyBillSearchActivity.this)) { + mBinding.swipeRefresh.finishLoadMore(); + return; + } + List data = teamWeeklyBillAdapter.getData(); + if (ListUtils.isListEmpty(data)) { + mBinding.swipeRefresh.finishLoadMore(); + return; + } + loadBill(); + } + + @Override + public void onRefresh(RefreshLayout refreshlayout) { + if (!NetworkUtil.isNetAvailable(TeamWeeklyBillSearchActivity.this)) { + mBinding.swipeRefresh.finishRefresh(); + return; + } + firstLoad(); + } +} diff --git a/app/src/main/java/com/chwl/app/team/view/UpdateTeamNameActivity.java b/app/src/main/java/com/chwl/app/team/view/UpdateTeamNameActivity.java new file mode 100644 index 0000000..980a31e --- /dev/null +++ b/app/src/main/java/com/chwl/app/team/view/UpdateTeamNameActivity.java @@ -0,0 +1,78 @@ +package com.chwl.app.team.view; + +import static com.chwl.app.team.view.NimTeamManagementActivity.EXTRA_TEAM_ID; + +import android.content.Context; +import android.content.Intent; +import android.text.InputFilter; +import android.view.View; +import android.widget.EditText; + +import com.google.android.material.snackbar.Snackbar; +import com.chwl.app.R; +import com.chwl.app.base.BaseBindingActivity; +import com.chwl.app.base.TitleBar; +import com.chwl.app.databinding.ActivityUpdateTeamNameBinding; +import com.chwl.app.team.viewmodel.TeamVM; +import com.chwl.core.team.bean.TeamInfo; +import com.chwl.core.team.model.TeamModel; +import com.chwl.library.annatation.ActLayoutRes; +import com.chwl.library.utils.ResUtil; + +/** + * Created by MadisonRong on 28/06/2018. + */ +@ActLayoutRes(R.layout.activity_update_team_name) +public class UpdateTeamNameActivity extends BaseBindingActivity { + + private EditText teamName; + private TeamVM teamViewModel; + private String tid; + private TeamInfo teamInfo; + + public static void start(Context context, String tid) { + Intent intent = new Intent(context, UpdateTeamNameActivity.class); + intent.putExtra(EXTRA_TEAM_ID, tid); + context.startActivity(intent); + } + + @Override + protected void init() { + tid = getIntent().getStringExtra(EXTRA_TEAM_ID); + teamInfo = TeamModel.get().getTeamInfoCache(tid); + teamViewModel = new TeamVM(); + teamName = mBinding.etContentTeamName; + teamName.setText(teamInfo.getName()); + teamName.setFilters(new InputFilter[]{new InputFilter.LengthFilter(15)}); + initTitleBar(ResUtil.getString(R.string.team_view_updateteamnameactivity_01)); + } + + @Override + public void initTitleBar(String title) { + super.initTitleBar(title); + TitleBar titleBar = (TitleBar) findViewById(R.id.title_bar); + titleBar.setActionTextColor(R.color.text_color_primary); + titleBar.addAction(new TitleBar.TextAction(ResUtil.getString(R.string.team_view_updateteamnameactivity_02)) { + @Override + public void performAction(View view) { + String content = teamName.getText().toString(); + //修改个人介绍 + if (!content.trim().isEmpty()) { + teamViewModel.updateTeamName(teamInfo.getId(), content) + .compose(bindToLifecycle()) + .subscribe((teamInfo, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + toast(ResUtil.getString(R.string.team_view_updateteamnameactivity_03)); + } else { + TeamModel.get().setTeamInfoCache(teamInfo.getTid(), teamInfo); + finish(); + } + }); + } else { + Snackbar.make(mBinding.layoutCoordinator, ResUtil.getString(R.string.team_view_updateteamnameactivity_04), Snackbar.LENGTH_SHORT).show(); + } + } + }); + } +} diff --git a/app/src/main/java/com/chwl/app/team/viewmodel/FamilyMemberVM.java b/app/src/main/java/com/chwl/app/team/viewmodel/FamilyMemberVM.java new file mode 100644 index 0000000..26a68db --- /dev/null +++ b/app/src/main/java/com/chwl/app/team/viewmodel/FamilyMemberVM.java @@ -0,0 +1,27 @@ +package com.chwl.app.team.viewmodel; + +import com.chwl.app.base.BaseVM; +import com.chwl.core.family.bean.response.memberList.RespFamilymember; +import com.chwl.core.family.model.FamilyModel; + +import io.reactivex.Single; + +/** + * Created by MadisonRong on 29/05/2018. + */ + +public class FamilyMemberVM extends BaseVM { + + + /** + * 获取不在群组内的成员列表 + * @param tid 云信群组 ID + * @param key 查询关键字 + * @param page 页码 + * @return + */ + public Single getNotInTeamFamilyMembers(String tid, String key, int page) { + return FamilyModel.Instance().getNotInTeamMember( + tid, key, page, 10); + } +} diff --git a/app/src/main/java/com/chwl/app/team/viewmodel/TeamVM.java b/app/src/main/java/com/chwl/app/team/viewmodel/TeamVM.java new file mode 100644 index 0000000..59caabc --- /dev/null +++ b/app/src/main/java/com/chwl/app/team/viewmodel/TeamVM.java @@ -0,0 +1,265 @@ +package com.chwl.app.team.viewmodel; + +import com.chwl.app.base.BaseVM; +import com.chwl.core.bean.response.ServiceResult; +import com.chwl.core.luckymoney.bean.LuckyMoneyInfo; +import com.chwl.core.luckymoney.bean.LuckyMoneyRecordsInfo; +import com.chwl.core.team.bean.RespTeamMemberInfo; +import com.chwl.core.team.bean.TeamInfo; +import com.chwl.core.team.bean.TeamMemberInfo; +import com.chwl.core.team.bean.TeamTransactionInfo; +import com.chwl.core.team.model.TeamModel; + +import java.util.List; + +import io.reactivex.Single; + +/** + * Created by MadisonRong on 29/05/2018. + */ + +public class TeamVM extends BaseVM { + + private static final String TAG = "TeamViewModel"; + + + /** + * 分页获取群组成员列表 + * + * @param chatId 群聊 ID + * @param page 页码 + * @return + */ + public Single getTeamMemberList(String chatId, String page) { + return TeamModel.get().getTeamMemberList(chatId, page); + } + + /** + * 创建群组 + * + * @param familyId 家族 ID + * @param uid 创建者的用户 UID + * @param icon 群头像(七牛的 url) + * @param name 群组名称 + * @param isVerify 是否开启身份验证 + * @param members 群组成员 + * @return + */ + public Single createTeam(String familyId, String uid, String icon, String name, boolean isVerify, + String[] members) { + return TeamModel.get().createTeam(familyId,uid,icon,name,isVerify,members); + } + + /** + * 群主(族长)删除本群组 + * + * @param chatId 群组 ID + * @param uid 群主 UID + * @return + */ + public Single deleteTeam(String chatId, String uid) { + return TeamModel.get().deleteTeam(chatId,uid); + } + + /** + * 管理员或者普通成员退出群组 + * + * @param chatId 群组 ID + * @return + */ + public Single quiteTeam(String chatId) { + return TeamModel.get().quiteTeam(chatId); + } + + /** + * 清空群组的聊天记录(本地的) + * + * @param tid 云信群组 ID + */ + public void clearChattingHistory(String tid) { + TeamModel.get().clearChattingHistory(tid); + } + + /** + * 通过号搜索群聊成员 + * + * @param chatId 群组 ID + * @param page 页码 + * @return + */ + public Single> queryErbanNo(String chatId, String erbanNo, int page) { + return TeamModel.get().queryErbanNo(chatId, erbanNo, page); + } + + /** + * 添加成员到群组里 + * + * @param chatId 群组 ID + * @param targetUids 目标用户(被操作者) UID 数组 + * @return + */ + public Single addMemberToTeam(String chatId, String[] targetUids) { + return TeamModel.get().addMemberToTeam(chatId, targetUids); + } + + /** + * 设置群组消息提示方式(是否开启消息免打扰) + * + * @param chatId 群组 ID + * @param uid 用户 UID + * @param wannaMute 是否要开启消息免打扰 + * @return + */ + public Single muteNotification(String chatId, String uid, Boolean wannaMute) { + return TeamModel.get().muteNotification(chatId, uid, wannaMute); + } + + /** + * 查询用户已加入的群组列表 + * + * @return + */ + public Single> queryJoin() { + return TeamModel.get().queryJoin(); + } + + /** + * 更新群资料(更新群头像) + * + * @param chatId 群组 ID + * @param icon 群头像 URL + * @return + */ + public Single updateTeamIcon(String chatId, String icon) { + return TeamModel.get().updateTeamIcon(chatId, icon); + } + + /** + * 更新群资料(更新群名称) + * + * @param chatId 群组 ID + * @param name 群名称 + * @return + */ + public Single updateTeamName(String chatId, String name) { + return TeamModel.get().updateTeamName(chatId, name); + } + + /** + * 更新群资料(更新入群验证方式) + * + * @param chatId 群组 ID + * @param isVerify 群组是否加入身份验证 + * @return + */ + public Single updateTeamJoinAuthMethod(String chatId, Boolean isVerify) { + return TeamModel.get().updateTeamJoinAuthMethod(chatId, isVerify); + } + + /** + * 获取群资料 + * + * @param sessionId 云信群组 ID + * @return + */ + public Single getTeamInfo(String sessionId) { + return TeamModel.get().getTeamInfo(sessionId); + } + + /** + * 禁言/解禁 群组成员 + * + * @param chatId 群组 ID + * @param targetUid 目标用户(被操作者) UID + * @param wannaMute 是否禁言 + * @return + */ + public Single muteTeamMember(String chatId, String targetUid, Boolean wannaMute) { + return TeamModel.get().muteTeamMember(chatId, targetUid, wannaMute); + } + + /** + * 设置/取消设置 群组管理员 + * + * @param chatId 群组 ID + * @param targetUid 目标用户(被操作者) UID + * @param wannaSetManager 是否设置管理员;true 为设置,false 为取消设置 + * @return + */ + public Single setTeamManager(String chatId, String targetUid, boolean wannaSetManager) { + return TeamModel.get().setTeamManager(chatId, targetUid, wannaSetManager); + } + + /** + * 踢出群组成员 + * + * @param chatId 群组 ID + * @param targetUid 目标用户(被操作者) UID + * @return + */ + public Single kickOutTeamMember(String chatId, String targetUid) { + return TeamModel.get().kickOutTeamMember(chatId, targetUid); + } + + /** + * 统计群组人数 + * + * @param chatId 群组 ID + * @return + */ + public Single getTeamMemberCount(String chatId) { + return TeamModel.get().getTeamMemberCount(chatId); + } + + /** + * 查询群统计(群组内一周的交易记录) + * @param chatId 群组 ID + * @param page 页码 + * @return + */ + public Single queryTeamTransactionRecords(String chatId, int page) { + return TeamModel.get().queryTeamTransactionRecords(chatId, page); + } + + /** + * 搜索群统计(群组内一周的交易记录) + * @param chatId 群组 ID + * @param page 页码 + * @return + */ + public Single searchTeamTransactionRecords(String chatId, String erbanNo, int page) { + return TeamModel.get().searchTeamTransactionRecords(chatId, erbanNo, page); + } + + /** + * 群组内发红包 + * + * @param tid 云信群组 ID + * @param amount 红包金额 + * @param count 红包可领取个数 + * @return + */ + public Single sendLuckyMoney(String tid, double amount, int count, String message) { + return TeamModel.get().sendLuckyMoney(tid, amount, count, message); + } + + /** + * 群组内收红包 + * + * @param luckyMoneyId 红包 ID + * @return + */ + public Single> receiveLuckyMoney(String luckyMoneyId) { + return TeamModel.get().receiveLuckyMoney(luckyMoneyId); + } + + /** + * 群组内查看红包的领取情况 + * + * @param luckyMoneyId 红包 ID + * @return + */ + public Single receiveLuckyMoneyRecords(String luckyMoneyId) { + return TeamModel.get().receiveLuckyMoneyRecords(luckyMoneyId); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/adapter/GiftAdapter.kt b/app/src/main/java/com/chwl/app/ui/adapter/GiftAdapter.kt new file mode 100644 index 0000000..fd8f849 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/adapter/GiftAdapter.kt @@ -0,0 +1,21 @@ +package com.chwl.app.ui.adapter + +import android.view.View +import com.chwl.app.bindadapter.BaseBindingAdapter +import com.chwl.app.bindadapter.BaseBindingViewHolder +import com.chwl.app.databinding.ListItemDialogGiftBinding +import com.chwl.app.ui.gift.dialog.GiftInfoVm +import com.chwl.library.common.util.setVis + +class GiftAdapter : BaseBindingAdapter() { + + override fun convert( + helper: BaseBindingViewHolder, + item: GiftInfoVm + ) { + helper?.binding?.viewRoomGiftSelect?.setVis(false) + helper?.binding?.giftImage?.visibility = View.INVISIBLE + helper?.binding?.item = item +// helper?.binding?.iconLayout?.setVis(true) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/adapter/StarWeekAdapter.java b/app/src/main/java/com/chwl/app/ui/adapter/StarWeekAdapter.java new file mode 100644 index 0000000..e65b5c4 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/adapter/StarWeekAdapter.java @@ -0,0 +1,52 @@ +package com.chwl.app.ui.adapter; + +import androidx.appcompat.widget.AppCompatImageView; +import androidx.appcompat.widget.AppCompatTextView; +import androidx.constraintlayout.widget.ConstraintLayout; + +import com.chwl.app.R; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.gift.bean.SimpleUserInfo; +import com.chwl.core.room.anotherroompk.ShowUserInfoDialogEvent; +import com.chwl.core.utils.CoreTextUtils; +import com.chwl.library.common.application.BaseApp; +import com.chwl.library.utils.ResUtil; +import com.zhpan.bannerview.BaseBannerAdapter; +import com.zhpan.bannerview.BaseViewHolder; + +import org.greenrobot.eventbus.EventBus; + +public class StarWeekAdapter extends BaseBannerAdapter { + + @Override + public int getLayoutId(int viewType) { + return R.layout.star_week_banner; + } + + @Override + protected void bindData(BaseViewHolder helper, SimpleUserInfo item, int position, int pageSize) { + ConstraintLayout bg = helper.findViewById(R.id.ll_container); + AppCompatImageView ivAvatar = helper.findViewById(R.id.iv_avatar); + AppCompatTextView tvNickCharm = helper.findViewById(R.id.tv_name); + if (position == 0) { + bg.setBackgroundResource(R.drawable.bg_star_week_1); + } else { + bg.setBackgroundResource(R.drawable.bg_star_week_2); + } + if (CoreTextUtils.isEmptyText(item.getAvatar())) { + ivAvatar.setImageResource(R.drawable.default_avatar); + ivAvatar.setOnClickListener(v -> { + if (item.getUid() == 0L) return; + EventBus.getDefault().post(new ShowUserInfoDialogEvent(String.valueOf(item.getUid()))); + }); + } else { + ImageLoadUtils.loadImage(BaseApp.getContext(), item.getAvatar(), ivAvatar); + } + if (CoreTextUtils.isEmptyText(item.getNick())){ + tvNickCharm.setText(ResUtil.getString(R.string.ui_widget_giftdialog_013)); + } else { + tvNickCharm.setText(item.getNick()); + } + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/anim/AnimFactory.java b/app/src/main/java/com/chwl/app/ui/anim/AnimFactory.java new file mode 100644 index 0000000..8ea40cf --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/anim/AnimFactory.java @@ -0,0 +1,206 @@ +package com.chwl.app.ui.anim; + +import android.content.Context; +import android.graphics.Color; +import android.graphics.drawable.AnimationDrawable; +import android.graphics.drawable.ColorDrawable; +import android.util.Log; + +import com.chwl.app.R; +import com.chwl.core.room.face.DynamicFaceModel; +import com.chwl.core.room.face.FaceInfo; +import com.chwl.core.room.face.FaceReceiveInfo; +import com.chwl.library.threadmgr.ThreadPoolManager; +import com.chwl.library.utils.ResUtil; +import com.netease.nim.uikit.common.util.log.LogUtil; + +import java.util.ArrayList; +import java.util.List; + +import io.reactivex.Single; +import io.reactivex.SingleOnSubscribe; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; + +/** + * @author xiaoyu + * @date 2017/11/30 + */ + +public class AnimFactory { + private static final String TAG = "AnimFactory"; + + private AnimFactory() { + } + + public static Single getFaceAnimation(Context context, int width, int height) { + return Single.create((SingleOnSubscribe) e -> { + long time = System.currentTimeMillis(); + AnimationDrawable drawable = new AnimationDrawable(); + FaceInfo faceInfo = DynamicFaceModel.get().findFaceInfoById(24); + // 如果找不到对应的表情,直接返回null + if (faceInfo == null) { + e.onError(new Throwable("no face")); + return; + } + int startIndex = faceInfo.getAnimationIndexStart(); + int endIndex = faceInfo.getAnimationIndexEnd(); + int duration = (int) ((faceInfo.getAnimationDuration() + 0.F) / (endIndex - startIndex)); + int repeatCount = faceInfo.getRepeatCount(); + while (repeatCount > 0) { + for (int i = startIndex; i <= endIndex; i++) { + // 增加每一帧到drawable中 + OneFaceDrawable face = new OneFaceDrawable(context, faceInfo.getFacePath(i), width, height); + drawable.addFrame(face, duration); + } + repeatCount--; + } + // 如果是普通表情,则直接返回 + if (faceInfo.getResultCount() <= 0) { + drawable.addFrame(new ColorDrawable(Color.TRANSPARENT), 10); + e.onSuccess(drawable); + return; + } + // 如果有结果,增加结果帧 + List resultIndexes = new ArrayList<>(); + resultIndexes.add(14); + resultIndexes.add(15); + resultIndexes.add(16); + resultIndexes.add(17); + resultIndexes.add(18); + duration = faceInfo.getResultDuration(); + // 找出所有结果图片的路径 + List images = new ArrayList<>(); + for (int i = 0; i < resultIndexes.size(); i++) { + LogUtil.e(TAG, faceInfo.getFacePath(resultIndexes.get(i))); + images.add(faceInfo.getFacePath(resultIndexes.get(i))); + } + // 根据显示类型,产生对应的类型的结果图片 + int displayType = faceInfo.getDisplayType(); + if (displayType == FaceInfo.DISPLAY_TYPE_ONE_PIC || images.size() == 1) { + OneFaceDrawable face = new OneFaceDrawable(context, images.get(0), width, height); + drawable.addFrame(face, duration); + } else if (displayType == FaceInfo.DISPLAY_TYPE_FLOW) { + FlowFaceDrawable flowFaceDrawable = new FlowFaceDrawable(context, images, width, height); + flowFaceDrawable.setBounds(0, 0, width, height); + drawable.addFrame(flowFaceDrawable, duration); + } else if (displayType == FaceInfo.DISPLAY_TYPE_OVERLAY) { + OverlayFaceDrawable overlayFaceDrawable = new OverlayFaceDrawable(context, images, width, height); + overlayFaceDrawable.setBounds(0, 0, width, height); + drawable.addFrame(overlayFaceDrawable, duration); + } else { + // 未知类型,不显示动画 + e.onError(new Throwable(ResUtil.getString(R.string.ui_anim_animfactory_01))); + return; + } + + //隐藏drawable + ColorDrawable colorDrawable = new ColorDrawable(Color.TRANSPARENT); + colorDrawable.setBounds(0, 0, width, height); + drawable.addFrame(new ColorDrawable(Color.TRANSPARENT), 10); + Log.e(TAG, "time consumed: " + (System.currentTimeMillis() - time)); + e.onSuccess(drawable); + }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()); + } + + /** + * @param needAnim 需要转的动画 + * @param needResult 随机表情是否需要结果 + * @param needGone 动画结束是否需要隐藏 + * @return + */ + public static Single getFaceAnimation(FaceReceiveInfo faceReceiveInfo, Context context, int width, int height,boolean needAnim,boolean needResult,boolean needGone) { + return Single.create((SingleOnSubscribe) e -> { + AnimationDrawable drawable = new AnimationDrawable(); + FaceInfo faceInfo = DynamicFaceModel.get().findFaceInfoById(faceReceiveInfo.getFaceId()); + // 如果找不到对应的表情,直接返回null + if (faceInfo == null) { + e.onError(new Throwable("no face")); + return; + } + int startIndex = faceInfo.getAnimationIndexStart(); + int endIndex = faceInfo.getAnimationIndexEnd(); + int duration = (int) ((faceInfo.getAnimationDuration() + 0.F) / (endIndex - startIndex)); + int repeatCount = faceInfo.getRepeatCount(); + if (needAnim){ + while (repeatCount > 0) { + for (int i = startIndex; i <= endIndex; i++) { + // 增加每一帧到drawable中 + OneFaceDrawable face = new OneFaceDrawable(context, faceInfo.getFacePath(i), width, height); + drawable.addFrame(face, duration); + } + repeatCount--; + } + } + // 如果是普通表情,则直接返回 + if (faceInfo.getResultCount() <= 0) { + drawable.addFrame(new ColorDrawable(Color.TRANSPARENT), 10); + e.onSuccess(drawable); + return; + } + // 如果有结果,增加结果帧 + List resultIndexes = faceReceiveInfo.getResultIndexes(); + duration = faceInfo.getResultDuration(); + if (needResult){ + // 找出所有结果图片的路径 + List images = new ArrayList<>(); + for (int i = 0; i < resultIndexes.size(); i++) { + images.add(faceInfo.getFacePath(resultIndexes.get(i))); + } + // 根据显示类型,产生对应的类型的结果图片 + int displayType = faceInfo.getDisplayType(); + if (displayType == FaceInfo.DISPLAY_TYPE_ONE_PIC || images.size() == 1) { + OneFaceDrawable face = new OneFaceDrawable(context, images.get(0), width, height); + drawable.addFrame(face, duration); + } else if (displayType == FaceInfo.DISPLAY_TYPE_FLOW) { + FlowFaceDrawable flowFaceDrawable = new FlowFaceDrawable(context, images, width, height); + flowFaceDrawable.setBounds(0, 0, width, height); + drawable.addFrame(flowFaceDrawable, duration); + } else if (displayType == FaceInfo.DISPLAY_TYPE_OVERLAY) { + OverlayFaceDrawable overlayFaceDrawable = new OverlayFaceDrawable(context, images, width, height); + overlayFaceDrawable.setBounds(0, 0, width, height); + drawable.addFrame(overlayFaceDrawable, duration); + }else if(displayType == FaceInfo.DISPLAY_TYPE_ABREAST){ + OverlayFaceDrawable overlayFaceDrawable = new OverlayFaceDrawable(context, images, width, height,1F); + overlayFaceDrawable.setBounds(0, 0, width, height); + drawable.addFrame(overlayFaceDrawable, duration); + } else { + // 未知类型,不显示动画 + e.onError(new Throwable(ResUtil.getString(R.string.ui_anim_animfactory_02))); + return; + } + } + if (needGone){ + //隐藏drawable + ColorDrawable colorDrawable = new ColorDrawable(Color.TRANSPARENT); + colorDrawable.setBounds(0, 0, width, height); + drawable.addFrame(new ColorDrawable(Color.TRANSPARENT), 10); + } + e.onSuccess(drawable); + }) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()); + } + + public static Single getSpeakingAnimation(Context context, int maxWidth, int maxHeight, int color, int startRadius) { + return Single.create((SingleOnSubscribe) e -> { + AnimationDrawable drawable = new AnimationDrawable(); + drawable.setOneShot(true); + float frames = 30F; + float halfFrames = frames / 2; + float fixedStep = ((maxWidth - startRadius) / frames); + // 刚开始的透明度(白色刚开始的透明度是200),其他是255 + int startTranslucent = (Color.argb(255, 255, 255, 255) == color) ? 200 : 255; + for (int i = 0; i < frames; i++) { + WavingDrawable wavingDrawable = new WavingDrawable(maxWidth, maxHeight, color, + (int) (startRadius + i * fixedStep)); + wavingDrawable.setAlpha((i <= halfFrames) ? startTranslucent : (int) ((1 - ((i - halfFrames) / (frames - halfFrames))) * startTranslucent)); + drawable.addFrame(wavingDrawable, 50); + } + drawable.addFrame(new ColorDrawable(Color.TRANSPARENT), 5); + e.onSuccess(drawable); + }) + .subscribeOn(Schedulers.from(ThreadPoolManager.instance().getSpeakExecutor())) + .observeOn(AndroidSchedulers.mainThread()); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/anim/FlowFaceDrawable.java b/app/src/main/java/com/chwl/app/ui/anim/FlowFaceDrawable.java new file mode 100644 index 0000000..9f1e0b9 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/anim/FlowFaceDrawable.java @@ -0,0 +1,208 @@ +package com.chwl.app.ui.anim; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.bumptech.glide.request.FutureTarget; +import com.netease.nim.uikit.support.glide.GlideApp; +import com.chwl.library.common.util.Utils; + +import java.util.ArrayList; +import java.util.List; + +/** + * 用来显示最后一张图片 + * 实现了连贯排列的效果 + * + * @author xiaoyu + * @date 2017/12/1 + */ + +public class FlowFaceDrawable extends Drawable { + + private static final String TAG = "drawable"; + + private class Pair { + private Bitmap bitmap; + private Rect rect; + + Pair(Bitmap bitmap, Rect rect) { + this.bitmap = bitmap; + this.rect = rect; + } + } + + private List images; + private List data; + private Paint mPaint; + private int mWidth; + private int mHeight; + private int mSpaceX; + private int mSpaceY; + private Context mContext; + + FlowFaceDrawable(Context context, List images, int width, int height) { + this.images = images; + this.mWidth = width; + this.mHeight = height; + this.mContext = context; + if (images.size() > 0) { + init(); + } + } + + private static final int RAW_MAX_COUNT = 3; + private static final int COLUMN_MAX_COUNT = 3; + + private void init() { + // 确定每一张图片的位置 + data = new ArrayList<>(); + int size = images.size(); + // 行数 + int rows = size < RAW_MAX_COUNT ? 1 : size < 6 ? 2 : 3; + // 列数 + int columns = size > COLUMN_MAX_COUNT ? COLUMN_MAX_COUNT : size == 1 ? 1 : 2; + int max = Math.max(rows, columns); + float ratio = 1; + + BitmapFactory.Options options = new BitmapFactory.Options(); + for (int i = 0; i < size; i++) { + options.inJustDecodeBounds = true; + BitmapFactory.decodeFile(images.get(i), options); + ratio = (max == rows) ? (options.outWidth / (mWidth + 0.F)) * max : (options.outHeight / (mHeight + 0.F)) * max; + int width = (int) (options.outWidth / ratio); + int maxWidth = Utils.dip2px(mContext, 28); + if (width > maxWidth) { + ratio = ratio * (width / (maxWidth + 0.F)); + } + + FutureTarget submit = GlideApp.with(mContext) + .asBitmap() + .dontAnimate() + .dontTransform() + .override(width > maxWidth ? maxWidth : width, (int) (options.outHeight / ratio)) + .load(images.get(i)) + .submit(); + + Bitmap bitmap = null;//Bitmap.createScaledBitmap(originalBitmap, width > maxWidth ? maxWidth : width, (int) (originalBitmap.getHeight() / ratio), true); + try { + bitmap = submit.get(); + } catch (Exception e) { + e.printStackTrace(); + } + Pair pair = new Pair(bitmap, calcRect(bitmap, i)); + data.add(pair); + } + // 留白 + mSpaceX = (mWidth - columns * data.get(0).bitmap.getWidth()) / 2; + mSpaceY = (mHeight - rows * data.get(0).bitmap.getHeight()) / 2; + // 笔 + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); +// LogUtil.e(TAG, "rows: " + rows + " columns: " + columns + ", max: " + max + ", mWidth: " + mWidth + ", mHeight: " + mHeight + +// ", mSpaceX: " + mSpaceX + ", mSpaceY: " + mSpaceY + ", bitmap.getWidth(): " + +// data.get(0).bitmap.getWidth() + ", bitmap.getHeight(): " + data.get(0).bitmap.getHeight() + +// "originalBitmap.getWidth(): " + originalBitmap.getWidth() + ", originalBitmap.getHeight(): " + originalBitmap.getHeight()); + } + + private Rect calcRect(Bitmap bitmap, int pos) { + int size = images.size(); + Rect rect = new Rect(); + switch (size) { + case 1: + rect.left = 0; + rect.top = 0; + rect.right = bitmap.getWidth(); + rect.bottom = bitmap.getHeight(); + break; + case 2: + rect.left = pos * bitmap.getWidth(); + rect.top = 0; + rect.right = rect.left + bitmap.getWidth(); + rect.bottom = bitmap.getHeight(); + break; + case 3: + if (pos == 0) { + rect.left = bitmap.getWidth() / 2; + rect.top = 0; + rect.right = rect.left + bitmap.getWidth(); + rect.bottom = bitmap.getHeight(); + } else { + rect.left = (pos - 1) * bitmap.getWidth(); + rect.top = bitmap.getHeight(); + rect.right = rect.left + bitmap.getWidth(); + rect.bottom = rect.top + bitmap.getHeight(); + } + break; + case 4: + if (pos < 2) { + rect.left = pos * bitmap.getWidth(); + rect.top = 0; + rect.right = rect.left + bitmap.getWidth(); + rect.bottom = bitmap.getHeight(); + } else { + rect.left = (pos - 2) * bitmap.getWidth(); + rect.top = bitmap.getHeight(); + rect.right = rect.left + bitmap.getWidth(); + rect.bottom = rect.top + bitmap.getHeight(); + } + break; + case 5: + if (pos < 2) { + rect.left = bitmap.getWidth() / 2 + (pos * bitmap.getWidth()); + rect.top = 0; + rect.right = rect.left + bitmap.getWidth(); + rect.bottom = bitmap.getHeight(); + } else { + rect.left = (pos - 2) * bitmap.getWidth(); + rect.top = bitmap.getHeight(); + rect.right = rect.left + bitmap.getWidth(); + rect.bottom = rect.top + bitmap.getHeight(); + } + break; + default: + } + return rect; + } + + @Override + public void draw(@NonNull Canvas canvas) { + for (int i = 0; i < data.size(); i++) { + canvas.drawBitmap(data.get(i).bitmap, mSpaceX + data.get(i).rect.left, mSpaceY + data.get(i).rect.top, mPaint); + } + } + + @Override + public void setAlpha(int alpha) { + mPaint.setAlpha(alpha); + } + + @Override + public int getIntrinsicHeight() { + return mHeight; + } + + @Override + public int getIntrinsicWidth() { + return mWidth; + } + + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) { + mPaint.setColorFilter(colorFilter); + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/anim/FrameAnimation.java b/app/src/main/java/com/chwl/app/ui/anim/FrameAnimation.java new file mode 100644 index 0000000..861949b --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/anim/FrameAnimation.java @@ -0,0 +1,333 @@ +package com.chwl.app.ui.anim; + +import android.graphics.drawable.Drawable; +import android.widget.ImageView; + +import java.util.List; + +/** + * Created by Ansen on 2015/5/14 23:30. + * + * @E-mail: ansen360@126.com + * @Blog: http://blog.csdn.net/qq_25804863 + * @Github: https://github.com/ansen360 + * @PROJECT_NAME: FrameAnimation + * @PACKAGE_NAME: com.ansen.frameanimation.sample + * @Description: TODO + */ +public class FrameAnimation { + + private boolean mIsRepeat; + + private AnimationListener mAnimationListener; + + private ImageView mImageView; + + private List mFrameRess; + + /** + * 每帧动画的播放间隔数组 + */ + private int[] mDurations; + + /** + * 每帧动画的播放间隔 + */ + private int mDuration; + + /** + * 下一遍动画播放的延迟时间 + */ + private int mDelay; + + private int mLastFrame; + + private boolean mNext; + + private boolean mPause; + + private int mCurrentSelect; + + private int mCurrentFrame; + + private static final int SELECTED_A = 1; + + private static final int SELECTED_B = 2; + + private static final int SELECTED_C = 3; + + private static final int SELECTED_D = 4; + + + /** + * @param iv 播放动画的控件 + * @param frameRes 播放的图片数组 + * @param duration 每帧动画的播放间隔(毫秒) + * @param isRepeat 是否循环播放 + */ + public FrameAnimation(ImageView iv, List frameRes, int duration, boolean isRepeat) { + this.mImageView = iv; + this.mFrameRess = frameRes; + this.mDuration = duration; + this.mLastFrame = frameRes.size() - 1; + this.mIsRepeat = isRepeat; + play(0); + } + + /** + * @param iv 播放动画的控件 + * @param frameRess 播放的图片数组 + * @param durations 每帧动画的播放间隔(毫秒) + * @param isRepeat 是否循环播放 + */ + public FrameAnimation(ImageView iv, List frameRess, int[] durations, boolean isRepeat) { + this.mImageView = iv; + this.mFrameRess = frameRess; + this.mDurations = durations; + this.mLastFrame = frameRess.size() - 1; + this.mIsRepeat = isRepeat; + playByDurations(0); + } + + /** + * 循环播放动画 + * + * @param iv 播放动画的控件 + * @param frameRess 播放的图片数组 + * @param duration 每帧动画的播放间隔(毫秒) + * @param delay 循环播放的时间间隔 + */ + public FrameAnimation(ImageView iv, List frameRess, int duration, int delay) { + this.mImageView = iv; + this.mFrameRess = frameRess; + this.mDuration = duration; + this.mDelay = delay; + this.mLastFrame = frameRess.size() - 1; + playAndDelay(0); + } + + /** + * 循环播放动画 + * + * @param iv 播放动画的控件 + * @param frameRess 播放的图片数组 + * @param durations 每帧动画的播放间隔(毫秒) + * @param delay 循环播放的时间间隔 + */ + public FrameAnimation(ImageView iv, List frameRess, int[] durations, int delay) { + this.mImageView = iv; + this.mFrameRess = frameRess; + this.mDurations = durations; + this.mDelay = delay; + this.mLastFrame = frameRess.size() - 1; + playByDurationsAndDelay(0); + } + + private void playByDurationsAndDelay(final int i) { + mImageView.postDelayed(new Runnable() { + + @Override + public void run() { + if (mPause) { // 暂停和播放需求 + mCurrentSelect = SELECTED_A; + mCurrentFrame = i; + return; + } + if (0 == i) { + if (mAnimationListener != null) { + mAnimationListener.onAnimationStart(); + } + } + mImageView.setBackground(mFrameRess.get(i)); + if (i == mLastFrame) { + if (mAnimationListener != null) { + mAnimationListener.onAnimationRepeat(); + } + mNext = true; + playByDurationsAndDelay(0); + } else { + playByDurationsAndDelay(i + 1); + } + } + }, mNext && mDelay > 0 ? mDelay : mDurations[i]); + + } + + private void playAndDelay(final int i) { + mImageView.postDelayed(new Runnable() { + + @Override + public void run() { + if (mPause) { + if (mPause) { + mCurrentSelect = SELECTED_B; + mCurrentFrame = i; + return; + } + return; + } + mNext = false; + if (0 == i) { + if (mAnimationListener != null) { + mAnimationListener.onAnimationStart(); + } + } + mImageView.setBackground(mFrameRess.get(i)); + if (i == mLastFrame) { + if (mAnimationListener != null) { + mAnimationListener.onAnimationRepeat(); + } + mNext = true; + playAndDelay(0); + } else { + playAndDelay(i + 1); + } + } + }, mNext && mDelay > 0 ? mDelay : mDuration); + + } + + private void playByDurations(final int i) { + mImageView.postDelayed(new Runnable() { + + @Override + public void run() { + if (mPause) { + if (mPause) { + mCurrentSelect = SELECTED_C; + mCurrentFrame = i; + return; + } + return; + } + if (0 == i) { + if (mAnimationListener != null) { + mAnimationListener.onAnimationStart(); + } + } + mImageView.setBackground(mFrameRess.get(i)); + if (i == mLastFrame) { + if (mIsRepeat) { + if (mAnimationListener != null) { + mAnimationListener.onAnimationRepeat(); + } + playByDurations(0); + } else { + if (mAnimationListener != null) { + mAnimationListener.onAnimationEnd(); + } + } + } else { + + playByDurations(i + 1); + } + } + }, mDurations[i]); + + } + + private void play(final int i) { + mImageView.postDelayed(new Runnable() { + + @Override + public void run() { + if (mPause) { + if (mPause) { + mCurrentSelect = SELECTED_D; + mCurrentFrame = i; + return; + } + return; + } + if (0 == i) { + if (mAnimationListener != null) { + mAnimationListener.onAnimationStart(); + } + } + mImageView.setBackground(mFrameRess.get(i)); + if (i == mLastFrame) { + + if (mIsRepeat) { + if (mAnimationListener != null) { + mAnimationListener.onAnimationRepeat(); + } + play(0); + } else { + if (mAnimationListener != null) { + mAnimationListener.onAnimationEnd(); + } + } + + } else { + + play(i + 1); + } + } + }, mDuration); + } + + public static interface AnimationListener { + + /** + *

Notifies the start of the animation.

+ */ + void onAnimationStart(); + + /** + *

Notifies the end of the animation. This callback is not invoked + * for animations with repeat count set to INFINITE.

+ */ + void onAnimationEnd(); + + /** + *

Notifies the repetition of the animation.

+ */ + void onAnimationRepeat(); + } + + /** + *

Binds an animation listener to this animation. The animation listener + * is notified of animation events such as the end of the animation or the + * repetition of the animation.

+ * + * @param listener the animation listener to be notified + */ + public void setAnimationListener(AnimationListener listener) { + this.mAnimationListener = listener; + } + + public void release() { + pauseAnimation(); + } + + public void pauseAnimation() { + this.mPause = true; + } + + public boolean isPause() { + return this.mPause; + } + + public void restartAnimation() { + if (mPause) { + mPause = false; + switch (mCurrentSelect) { + case SELECTED_A: + playByDurationsAndDelay(mCurrentFrame); + break; + case SELECTED_B: + playAndDelay(mCurrentFrame); + break; + case SELECTED_C: + playByDurations(mCurrentFrame); + break; + case SELECTED_D: + play(mCurrentFrame); + break; + default: + break; + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/anim/OneFaceDrawable.java b/app/src/main/java/com/chwl/app/ui/anim/OneFaceDrawable.java new file mode 100644 index 0000000..74bd18f --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/anim/OneFaceDrawable.java @@ -0,0 +1,131 @@ +package com.chwl.app.ui.anim; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.text.TextUtils; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.bumptech.glide.request.FutureTarget; +import com.netease.nim.uikit.support.glide.GlideApp; + +/** + * 用来显示一张图片 + * + * @author xiaoyu + * @date 2017/12/1 + */ + +public class OneFaceDrawable extends Drawable { + + private static final String TAG = "OneFaceDrawable"; + private float ratio; + + private class Pair { + private Bitmap bitmap; + private Rect rect; + + Pair(Bitmap bitmap, Rect rect) { + this.bitmap = bitmap; + this.rect = rect; + } + } + + private String image; + private Pair pair; + private Paint mPaint; + private int mWidth; + private int mHeight; + private int mSpaceX; + private int mSpaceY; + private Context mContext; + + OneFaceDrawable(Context context, String image, int width, int height) { + this.image = image; + this.mWidth = width; + this.mHeight = height; + this.mContext = context; + if (!TextUtils.isEmpty(image)) { + init(); + } + } + + private void init() { + // 确定一张图片的位置 + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeFile(image, options); + + float ratioX = (mWidth + 0.F) / options.outWidth;//originalBitmap.getWidth(); + float ratioY = (mHeight + 0.F) / options.outHeight;//originalBitmap.getHeight(); + ratio = ratioX > ratioY ? ratioY : ratioX; + FutureTarget submit = GlideApp.with(mContext) + .asBitmap() + .dontTransform() + .dontAnimate() + .override((int) (options.outWidth * ratio), (int) (options.outHeight * ratio)) + .load(image) + .submit(); + Bitmap bitmap = null;//Bitmap.createScaledBitmap(originalBitmap, (int) (originalBitmap.getWidth() * ratio), (int) (originalBitmap.getHeight() * ratio), true); + try { + bitmap = submit.get(); + } catch (Exception e) { + e.printStackTrace(); + } + if (bitmap == null) return; + pair = new Pair(bitmap, calcRect(bitmap)); + // 留白 + mSpaceX = (mWidth - bitmap.getWidth()) / 2; + mSpaceY = (mHeight - bitmap.getHeight()) / 2; + // 笔 + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + } + + private Rect calcRect(Bitmap bitmap) { + Rect rect = new Rect(); + rect.left = 0; + rect.top = 0; + rect.right = rect.left + bitmap.getWidth(); + rect.bottom = bitmap.getHeight(); + return rect; + } + + @Override + public void draw(@NonNull Canvas canvas) { + if (pair == null || pair.bitmap == null) return; + canvas.drawBitmap(pair.bitmap, mSpaceX + pair.rect.left, mSpaceY + pair.rect.top, mPaint); + } + + @Override + public void setAlpha(int alpha) { + mPaint.setAlpha(alpha); + } + + @Override + public int getIntrinsicHeight() { + return mHeight; + } + + @Override + public int getIntrinsicWidth() { + return mWidth; + } + + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) { + mPaint.setColorFilter(colorFilter); + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/anim/OverlayFaceDrawable.java b/app/src/main/java/com/chwl/app/ui/anim/OverlayFaceDrawable.java new file mode 100644 index 0000000..abfbe36 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/anim/OverlayFaceDrawable.java @@ -0,0 +1,190 @@ +package com.chwl.app.ui.anim; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.bumptech.glide.request.FutureTarget; +import com.chwl.library.common.util.Utils; +import com.netease.nim.uikit.support.glide.GlideApp; + +import java.util.ArrayList; +import java.util.List; + +/** + * 用来显示最后一张图片 + * 实现了连贯排列的效果 + * + * @author xiaoyu + * @date 2017/12/1 + */ +public class OverlayFaceDrawable extends Drawable { + + private static final String TAG = "drawable"; + private static final float RATIO_MAX = 0.5F; //默认重叠的图片宽度百分比 + private float ratio = RATIO_MAX; + + // 定义一个内部类Pair,用于存储Bitmap和其对应的Rect位置信息 + private class Pair { + private Bitmap bitmap; + private Rect rect; + + Pair(Bitmap bitmap, Rect rect) { + this.bitmap = bitmap; + this.rect = rect; + } + } + + // 存储图片路径的列表 + private List images; + // 存储每张图片的Bitmap及其位置信息 + private List data; + // 画笔对象,用于绘制Bitmap + private Paint mPaint; + // 控件的宽度和高度 + private int mWidth; + private int mHeight; + // 图片之间的水平和垂直间距 + private int mSpaceX; + private int mSpaceY; + // 上下文对象 + private Context mContext; + + /** + * 构造方法,初始化OverlayFaceDrawable + * + * @param context 上下文对象 + * @param images 图片路径列表 + * @param width 控件宽度 + * @param height 控件高度 + */ + OverlayFaceDrawable(Context context, List images, int width, int height) { + this.images = images; + this.mWidth = width; + this.mHeight = height; + this.mContext = context; + if (images.size() > 1) { + init(); // 如果图片数量大于1,则调用init方法进行初始化 + } + } + OverlayFaceDrawable(Context context, List images, int width, int height,float ratio) { + this.images = images; + this.mWidth = width; + this.mHeight = height; + this.mContext = context; + this.ratio = ratio; + if (images.size() > 1) { + init(); // 如果图片数量大于1,则调用init方法进行初始化 + } + } + + /** + * 初始化方法,计算每张图片的位置和大小 + */ + private void init() { + // 确定每一张图片的位置 + data = new ArrayList<>(); + int size = images.size(); + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeFile(images.get(0), options); + // 高度最大不超过35dp + int maxHeight = Utils.dip2px(mContext, 35); + int targetHeight = maxHeight > options.outHeight ? options.outHeight : maxHeight; + float scale = targetHeight / (options.outHeight + 0.F); + int targetWidth = (int) (scale * options.outWidth); +// ratio = RATIO_MAX; + // 算出overlay为0.5F的时候宽度相当于几张图片的大小 + int count = (int) (size / 2.F + 0.5F); + if (count * targetWidth > mWidth) { + // 如果overlay为0.5F的时候显示的总宽度大于mWidth,则需要计算出他可以显示的overlay的比例 + int canShownWidth = (mWidth - targetWidth) / (size - 1); + ratio = (canShownWidth + 0.F) / targetWidth; + } + for (int i = 0; i < size; i++) { + // 使用Glide加载图片 + FutureTarget submit = GlideApp.with(mContext) + .asBitmap() + .dontAnimate() + .dontTransform() + .override(targetWidth, targetHeight) + .load(images.get(i)) + .submit(); + Bitmap bitmap = null; + try { + bitmap = submit.get(); + } catch (Exception e) { + e.printStackTrace(); + } + Pair pair = new Pair(bitmap, calcRect(bitmap, i)); // 计算每张图片的位置 + data.add(pair); + } + // 留白 + mSpaceX = (int) ((mWidth - (targetWidth * ((size - 1) * ratio + 1))) / 2); + mSpaceY = (mHeight - targetHeight) / 2; + // 笔 + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + } + + /** + * 计算每张图片的位置 + * + * @param bitmap 图片的Bitmap对象 + * @param pos 图片的位置索引 + * @return 图片的位置Rect + */ + private Rect calcRect(Bitmap bitmap, int pos) { + Rect rect = new Rect(); + rect.left = (int) (pos * ratio * bitmap.getWidth()); + rect.top = 0; + rect.right = rect.left + bitmap.getWidth(); + rect.bottom = bitmap.getHeight(); + return rect; + } + + /** + * 绘制方法,将每张图片绘制到Canvas上 + * + * @param canvas 画布对象 + */ + @Override + public void draw(@NonNull Canvas canvas) { + for (int i = 0; i < data.size(); i++) { + canvas.drawBitmap(data.get(i).bitmap, mSpaceX + data.get(i).rect.left, mSpaceY + data.get(i).rect.top, mPaint); + } + } + + @Override + public void setAlpha(int alpha) { + mPaint.setAlpha(alpha); + } + + @Override + public int getIntrinsicHeight() { + return mHeight; + } + + @Override + public int getIntrinsicWidth() { + return mWidth; + } + + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) { + mPaint.setColorFilter(colorFilter); + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/anim/WavingDrawable.java b/app/src/main/java/com/chwl/app/ui/anim/WavingDrawable.java new file mode 100644 index 0000000..a168f94 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/anim/WavingDrawable.java @@ -0,0 +1,92 @@ +package com.chwl.app.ui.anim; + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.RadialGradient; +import android.graphics.Shader; +import android.graphics.drawable.Drawable; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.netease.nim.uikit.common.util.sys.ScreenUtil; + +/** + * @author xiaoyu + * @date 2018/1/15 + */ + +public class WavingDrawable extends Drawable { + + private final Paint mPaint; + private RadialGradient mRadialGradient; + private int maxWidth; + private int maxHeight; + private int strokeWidth; + private int color; + private int startRadius; + + public WavingDrawable(int maxWidth, int maxHeight, int color, int startRadius) { + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + strokeWidth = ScreenUtil.dip2px(2.4F); + mPaint.setStrokeWidth(strokeWidth); + this.maxWidth = maxWidth; + this.maxHeight = maxHeight; + this.color = color; + this.startRadius = startRadius / 2; + } + + @Override + public void draw(@NonNull Canvas canvas) { + if (mRadialGradient == null) { + int x = maxWidth / 2; + int y = maxHeight / 2; + // 内环 + strokeWidth = ScreenUtil.dip2px(1.8F); + int startRealColor = Color.argb(200, (color & 0x00FF0000) >> 16, (color & 0x0000FF00) >> 8, color & 0x000000FF); + int endRealColor = Color.argb(255, (color & 0x00FF0000) >> 16, (color & 0x0000FF00) >> 8, color & 0x000000FF); + mPaint.setStyle(Paint.Style.FILL); + mRadialGradient = new RadialGradient(x, y, startRadius, startRealColor, endRealColor, Shader.TileMode.CLAMP); + mPaint.setShader(mRadialGradient); + canvas.drawCircle(x, y, startRadius, mPaint); + } + } + + @Override + public int getIntrinsicWidth() { + return maxWidth; + } + + @Override + public int getIntrinsicHeight() { + return maxHeight; + } + + @Override + public int getMinimumHeight() { + return ScreenUtil.dip2px(55F); + } + + @Override + public int getMinimumWidth() { + return ScreenUtil.dip2px(55F); + } + + @Override + public void setAlpha(int alpha) { + mPaint.setAlpha(alpha); + } + + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) { + mPaint.setColorFilter(colorFilter); + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSPARENT; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/bean/BaseResponse.java b/app/src/main/java/com/chwl/app/ui/bean/BaseResponse.java new file mode 100644 index 0000000..ef21b7e --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/bean/BaseResponse.java @@ -0,0 +1,34 @@ +package com.chwl.app.ui.bean; + + +/** + * Created by hyman on 2016/8/2. + */ +public class BaseResponse { + private int code; + private String msg; + + public BaseResponse() { + } + + public BaseResponse(int code, String msg) { + this.code = code; + this.msg = msg; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/bean/CountryBean.java b/app/src/main/java/com/chwl/app/ui/bean/CountryBean.java new file mode 100644 index 0000000..3c5610c --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/bean/CountryBean.java @@ -0,0 +1,12 @@ +package com.chwl.app.ui.bean; + + +import lombok.Data; + +@Data +public class CountryBean { + public String name; + public String icon; + public int id; + public boolean checked; +} diff --git a/app/src/main/java/com/chwl/app/ui/bean/FirstRechargeInfo.java b/app/src/main/java/com/chwl/app/ui/bean/FirstRechargeInfo.java new file mode 100644 index 0000000..3506a26 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/bean/FirstRechargeInfo.java @@ -0,0 +1,13 @@ +package com.chwl.app.ui.bean; + +import java.util.List; + +import lombok.Data; + +@Data +public class FirstRechargeInfo { + + public String chargeBanner; + public boolean chargeStatus; + public List levelCharge; +} diff --git a/app/src/main/java/com/chwl/app/ui/bean/Footer.java b/app/src/main/java/com/chwl/app/ui/bean/Footer.java new file mode 100644 index 0000000..3750f73 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/bean/Footer.java @@ -0,0 +1,8 @@ +package com.chwl.app.ui.bean; + +/** + * Created by zhouxiangfeng on 2017/4/30. + */ + +public class Footer { +} diff --git a/app/src/main/java/com/chwl/app/ui/bean/FooterLoadMoreBean.java b/app/src/main/java/com/chwl/app/ui/bean/FooterLoadMoreBean.java new file mode 100644 index 0000000..1976f8c --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/bean/FooterLoadMoreBean.java @@ -0,0 +1,16 @@ +package com.chwl.app.ui.bean; + + + +/** + * Created by wanli on 2016/10/27. + */ + +public class FooterLoadMoreBean { + public int LayId; + public String desc; + + public FooterLoadMoreBean() { + + } +} diff --git a/app/src/main/java/com/chwl/app/ui/bean/GiveGoldAgentBean.java b/app/src/main/java/com/chwl/app/ui/bean/GiveGoldAgentBean.java new file mode 100644 index 0000000..ee3a514 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/bean/GiveGoldAgentBean.java @@ -0,0 +1,20 @@ +package com.chwl.app.ui.bean; + +import lombok.Data; + +@Data +public class GiveGoldAgentBean { + public long uid; + public long id; + public long manageUid; + public int starLevel = -1; + public int hasCharge; + public long erbanNo; + public String nick; + public String avatar; + public int isOnline; + public int seq; + public int starLevelSeq; + public double totalGiveGoldUsd; + public long totalGiveGold; +} diff --git a/app/src/main/java/com/chwl/app/ui/bean/GiveGoldBiliBean.java b/app/src/main/java/com/chwl/app/ui/bean/GiveGoldBiliBean.java new file mode 100644 index 0000000..bd33580 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/bean/GiveGoldBiliBean.java @@ -0,0 +1,25 @@ +package com.chwl.app.ui.bean; + +import com.chwl.core.utils.myutil.MyTimeUtils; + +import lombok.Data; + +@Data +public class GiveGoldBiliBean { + + public boolean isHead; + + public long targetErbanNo; + public String targetNick; + public String targetAvatar; + public double diamondNum; + public double guildUsdNum; + public String createTimeStr; + public long createTime; + + public String getTimeStr() { + return MyTimeUtils.millis2String(createTime,"yyyy-MM-dd"); + } + +} + diff --git a/app/src/main/java/com/chwl/app/ui/bean/GiveGoldBiliEntity.java b/app/src/main/java/com/chwl/app/ui/bean/GiveGoldBiliEntity.java new file mode 100644 index 0000000..f0009cd --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/bean/GiveGoldBiliEntity.java @@ -0,0 +1,23 @@ +package com.chwl.app.ui.bean; + +import java.util.List; + +import lombok.Data; + +@Data +public class GiveGoldBiliEntity { + public String cycleDateStr; + public List diamondGiveHistoryVoList; + + public double totalGiveGoldUsd; + public long totalGiveGold; + + public @interface Cycle{ + public int thisCycle = 1; + public int lastCycle = 2; + } + public @interface TabType{ + public int gold = 1; + public int goldUs = 2; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/bean/LevelChargeBean.java b/app/src/main/java/com/chwl/app/ui/bean/LevelChargeBean.java new file mode 100644 index 0000000..386d707 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/bean/LevelChargeBean.java @@ -0,0 +1,13 @@ +package com.chwl.app.ui.bean; + +import lombok.Data; + +@Data +public class LevelChargeBean{ + public int awardNum; + public int exp; //对应金币数值 + public String pic; + public String rewardName; + public String rewardType; + public String unit; +} diff --git a/app/src/main/java/com/chwl/app/ui/bean/RechargeUserInfo.java b/app/src/main/java/com/chwl/app/ui/bean/RechargeUserInfo.java new file mode 100644 index 0000000..3dfaac2 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/bean/RechargeUserInfo.java @@ -0,0 +1,24 @@ +package com.chwl.app.ui.bean; + + +import lombok.Data; + +@Data +public class RechargeUserInfo { + public long id; + public long uid; + public long type; + public int starLevel; + public long erbanNo; + public String nick; + public String avatar; + public int isOnline; + + + public double totalGiveGoldUsd; + public long totalGiveGold; + + public int subNum; + + +} diff --git a/app/src/main/java/com/chwl/app/ui/bean/ShareInfo.java b/app/src/main/java/com/chwl/app/ui/bean/ShareInfo.java new file mode 100644 index 0000000..2cdde9b --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/bean/ShareInfo.java @@ -0,0 +1,16 @@ +package com.chwl.app.ui.bean; + +import lombok.Data; + +@Data +public class ShareInfo { + + //{"shareId":10002,"uid":3208,"targetUid":3208,"shareType":1} + public long shareId; + public long uid; + public long targetUid; + public String targetId; + public int shareType; + + +} diff --git a/app/src/main/java/com/chwl/app/ui/bean/header.java b/app/src/main/java/com/chwl/app/ui/bean/header.java new file mode 100644 index 0000000..2133033 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/bean/header.java @@ -0,0 +1,8 @@ +package com.chwl.app.ui.bean; + +/** + * Created by zhouxiangfeng on 2017/4/30. + */ + +public class header { +} diff --git a/app/src/main/java/com/chwl/app/ui/debug/DebugActivity.kt b/app/src/main/java/com/chwl/app/ui/debug/DebugActivity.kt new file mode 100644 index 0000000..2f9a3f9 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/debug/DebugActivity.kt @@ -0,0 +1,50 @@ +package com.chwl.app.ui.debug + +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.databinding.DebugActivityBinding +import com.netease.nim.uikit.StatusBarUtil + +class DebugActivity : BaseViewBindingActivity() { + override fun init() { + initWhiteTitleBar("调试") + initSVGAList() + } + + private fun initSVGAList() { + val adapter = DebugAdapter() + binding.recyclerView.adapter = adapter +// binding.recyclerView.setItemViewCacheSize(-1) + val svgaList = listOf( + "https://image.pekolive.com/花和玫瑰.svga", + "https://image.pekolive.com/firecrown.svga", + "https://image.pekolive.com/ningtangchengbaoqietu.svga", + "https://image.pekolive.com/xunmengfengche.svga", + "https://image.pekolive.com/tonghuaqiyuan1334.svga", + "https://image.pekolive.com/mengquyinhe.svga", + "https://image.pekolive.com/duqinghuashu.svga", + "https://image.pekolive.com/juzhijingling.svga", + "https://image.pekolive.com/3121_aixintouwei.svga", + "https://image.pekolive.com/4051_langmanyewan.svga" + ) + val list = ArrayList() + list.addAll(svgaList) + list.addAll(svgaList) + adapter.setNewData(list) + binding.btnRefreshAll.setOnClickListener { + adapter.notifyDataSetChanged() + } + binding.btnRefresh.setOnClickListener { + adapter.notifyItemChanged(5, true) + } + } + + override fun needSteepStateBar(): Boolean { + return true + } + + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/debug/DebugAdapter.kt b/app/src/main/java/com/chwl/app/ui/debug/DebugAdapter.kt new file mode 100644 index 0000000..2754e8e --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/debug/DebugAdapter.kt @@ -0,0 +1,47 @@ +package com.chwl.app.ui.debug + +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.library.widget.SVGAView +import com.example.lib_utils.log.ILog + +class DebugAdapter : BaseQuickAdapter(R.layout.debug_item_svga), ILog { + + private val svgaCache = SVGAView.newCache(10) + override fun convertPayloads( + helper: BaseViewHolder, + item: String?, + payloads: MutableList + ) { + super.convertPayloads(helper, item, payloads) + logD("convertPayloads holder:${helper.absoluteAdapterPosition} #${helper.hashCode()} SVGAView") + val svgaView = helper.getView(R.id.svga_view) + svgaView.loadUrl(item) + } + + override fun convert(helper: BaseViewHolder, item: String?) { + logD("convert holder:${helper.absoluteAdapterPosition} #${helper.hashCode()} SVGAView") + helper.setText(R.id.tv_name, helper.absoluteAdapterPosition.toString()) + val item = getItem(helper.bindingAdapterPosition) + val svgaView = helper.getView(R.id.svga_view) + svgaView.bindCache(svgaCache) + svgaView.setLogTag(helper.absoluteAdapterPosition.toString()) + svgaView.loadUrl(item) + } + + override fun onViewAttachedToWindow(holder: BaseViewHolder) { + super.onViewAttachedToWindow(holder) + logD("onViewAttachedToWindow holder:${holder.absoluteAdapterPosition} #${holder.hashCode()} SVGAView") +// val item = getItem(holder.bindingAdapterPosition) +// val svgaView = holder.getView(R.id.svga_view) +// svgaView.bindCache(SVGAView.newCache(10)) +// svgaView.setLogTag(holder.absoluteAdapterPosition.toString()) +// svgaView.loadUrl(item) + } + + override fun onViewDetachedFromWindow(holder: BaseViewHolder) { + super.onViewDetachedFromWindow(holder) + logD("onViewDetachedFromWindow holder:${holder.absoluteAdapterPosition} #${holder.hashCode()} SVGAView") + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/feedback/CustomerServiceDialog.kt b/app/src/main/java/com/chwl/app/ui/feedback/CustomerServiceDialog.kt new file mode 100644 index 0000000..ead3e9e --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/feedback/CustomerServiceDialog.kt @@ -0,0 +1,61 @@ +package com.chwl.app.ui.feedback + +import android.content.ClipData +import android.content.ClipboardManager +import android.content.Context +import android.view.WindowManager +import com.chwl.app.R +import com.chwl.app.base.BaseBindingDialog +import com.chwl.app.databinding.FeedbackCustomerServiceDialogBinding +import com.chwl.app.ui.widget.recyclerview.decoration.SpacingDecoration +import com.chwl.library.annatation.ActLayoutRes +import com.chwl.library.utils.SingleToastUtil + +@ActLayoutRes(R.layout.feedback_customer_service_dialog) +class CustomerServiceDialog(context: Context, val map: Map) : + BaseBindingDialog(context, R.style.dialog) { + private val adapter = CustomerServiceItemAdapter() + + override fun onStart() { + width = WindowManager.LayoutParams.MATCH_PARENT + super.onStart() + } + + override fun init() { + binding.layoutRoot.setOnClickListener { + dismiss() + } + binding.tvNext.setOnClickListener { + dismiss() + } + binding.recyclerView.addItemDecoration( + SpacingDecoration( + 0, + context.resources.getDimensionPixelOffset(R.dimen.dp_10), + false + ) + ) + binding.recyclerView.adapter = adapter + val list = map.map { + it + } + adapter.setNewData(list) + adapter.setOnItemChildClickListener { adapter, view, position -> + val text = this.adapter.getItem(position)?.value + if (text != null) { + copyText(text) + } + } + } + + private fun copyText(text: String) { + try { + val cm = + context?.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager + cm.setPrimaryClip(ClipData.newPlainText("text", text)) + SingleToastUtil.showToast(R.string.have_copy) + } catch (e: Exception) { + SingleToastUtil.showToast(e.toString()) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/feedback/CustomerServiceItemAdapter.kt b/app/src/main/java/com/chwl/app/ui/feedback/CustomerServiceItemAdapter.kt new file mode 100644 index 0000000..e15e489 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/feedback/CustomerServiceItemAdapter.kt @@ -0,0 +1,34 @@ +package com.chwl.app.ui.feedback + +import android.annotation.SuppressLint +import android.view.Gravity +import android.view.ViewGroup +import android.widget.TextView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.example.lib_utils.AppUtils +import com.example.lib_utils.UiUtils + +class CustomerServiceItemAdapter : + BaseQuickAdapter, BaseViewHolder>(R.layout.feedback_customer_service_item) { + + private var isRTL = UiUtils.isRtl(AppUtils.getApp()) + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder { + return super.onCreateViewHolder(parent, viewType).apply { + this.addOnClickListener(R.id.layout_copy) + val textView = getView(R.id.tv_content) + if (isRTL) { + textView.gravity = Gravity.RIGHT + } + } + } + + @SuppressLint("SetTextI18n") + override fun convert(helper: BaseViewHolder, item: Map.Entry) { + val textView = helper.getView(R.id.tv_content) + textView.text = "${item.key}: ${item.value ?: ""}" + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/feedback/FeedbackActivity.kt b/app/src/main/java/com/chwl/app/ui/feedback/FeedbackActivity.kt new file mode 100644 index 0000000..953fb73 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/feedback/FeedbackActivity.kt @@ -0,0 +1,295 @@ +package com.chwl.app.ui.feedback + +import android.annotation.SuppressLint +import android.content.Intent +import android.os.Bundle +import android.widget.ImageView.ScaleType +import androidx.activity.viewModels +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.base.PhotoPickActivity +import com.chwl.app.databinding.FeedbackActivityBinding +import com.chwl.app.ui.utils.load +import com.chwl.core.file.FileModel +import com.chwl.core.home.bean.FeedbackTypeBean +import com.chwl.core.utils.myutil.MyUriUtils +import com.chwl.library.common.util.PhotoCompressUtil +import com.chwl.library.common.util.PhotosCompressCallback +import com.chwl.library.utils.ResUtil +import com.example.lib_utils.SolveEditTextScrollClash +import com.example.lib_utils.ktx.getColorById +import com.example.lib_utils.ktx.setOnInputChangedListener +import com.example.lib_utils.ktx.singleClick +import com.example.lib_utils.spannable.SpannableTextBuilder +import com.google.android.flexbox.FlexDirection +import com.google.android.flexbox.FlexWrap +import com.google.android.flexbox.FlexboxLayoutManager +import com.google.android.flexbox.JustifyContent +import com.hjq.toast.ToastUtils +import com.netease.nim.uikit.StatusBarUtil +import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.launch + +class FeedbackActivity : BaseViewBindingActivity() { + + private val PERMISSION_CODE_STORAGE = 12 + private val REQUEST_CODE_OPEN_PHOTO_PROVIDER = 111 // 从相册中选择 + + private val viewModel: FeedbackViewModel by viewModels() + private val adapter = FeedbackTypeAdapter() + private var compressJob: Job? = null + private var wantShowCustomerService = false + private var imagePath: String? = null + private var imageUrl: String? = null + + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + } + + override fun init() { + initWhiteTitleBar(ResUtil.getString(R.string.feedback_title)) + initView() + initEvent() + initObserve() + refreshSubmitState() + } + + private fun initView() { + val flexBoxLayoutManager = FlexboxLayoutManager(context) + flexBoxLayoutManager.flexDirection = FlexDirection.ROW + flexBoxLayoutManager.flexWrap = FlexWrap.WRAP + flexBoxLayoutManager.justifyContent = JustifyContent.FLEX_START + binding.recyclerViewType.layoutManager = flexBoxLayoutManager + binding.recyclerViewType.adapter = adapter + binding.etContent.setOnTouchListener(SolveEditTextScrollClash(binding.etContent)) + } + + private fun initEvent() { + adapter.setOnItemClickListener { adapter, view, position -> + this.adapter.selectItem(this.adapter.getItem(position)) + refreshSubmitState() + } + binding.tvSubmit.singleClick { + dialogManager.showProgressDialog(this) + submit() + } + binding.ivImage.singleClick { + checkStoragePermission() + } + binding.ivCustomerService.singleClick { + showCustomerServiceDialog() + } + binding.etContent.setOnInputChangedListener { + updateContentInputTips(this) + refreshSubmitState() + true + } + binding.etContact.setOnInputChangedListener { + refreshSubmitState() + true + } + } + + private fun initObserve() { + viewModel.loadingLiveData.observe(this) { + if (it) dialogManager.showProgressDialog(this) + else dialogManager.dismissDialog() + } + viewModel.configLiveData.observe(this) { + if (it?.isSuccess == true) { + loadTypeList(it.data?.typeEnumList) + if (wantShowCustomerService) { + showCustomerServiceDialog(it.data?.customContactMap) + } + } else if (it?.message != null) { + toast(it.message ?: "") + } + wantShowCustomerService = false + } + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.RESUMED) { + viewModel.submitStateFlow.collectLatest { + dialogManager.dismissDialog() + if (it.isSuccess) { + toast(R.string.home_model_homemodel_01) + finish() + } else if (it.message != null) { + toast(it.message) + } + } + } + } + } + + private fun updateContentInputTips(length: Int) { + if (length > 0) { + SpannableTextBuilder(binding.tvContentCount) + .appendText( + text = length.toString(), + textColor = getColorById(R.color.color_3FDDAC) + ) + .appendText(text = "/300") + .apply() + } else { + binding.tvContentCount.text = "${length}/300" + } + } + + private fun showCustomerServiceDialog() { + val config = viewModel.configLiveData.value?.data + if (config == null) { + wantShowCustomerService = true + viewModel.getConfig() + return + } + showCustomerServiceDialog(config.customContactMap) + } + + private fun showCustomerServiceDialog(info: Map?) { + if (info.isNullOrEmpty()) { + return + } + CustomerServiceDialog(this, info).show() + } + + private fun loadTypeList(type: List?) { + adapter.setNewData(type) + } + + private fun onAddImage(path: String?) { + if (path.isNullOrEmpty()) { + imagePath = null + imageUrl = null + binding.ivImage.scaleType = ScaleType.CENTER_INSIDE + binding.ivImage.setImageResource(R.drawable.feedback_ic_add) + } else { + imagePath = path + imageUrl = null + binding.ivImage.load(path) + binding.ivImage.scaleType = ScaleType.CENTER_CROP + } + refreshSubmitState() + } + + private fun refreshSubmitState() { + binding.tvSubmit.isEnabled = canSubmit() + } + + private fun canSubmit(): Boolean { + if (binding.etContent.text.isNullOrEmpty()) { + return false + } + if (binding.etContact.text.isNullOrEmpty()) { + return false + } + if (adapter.getSelectItem() == null) { + return false + } + return true + } + + private fun submit() { + val content = binding.etContent.text.trim().toString() + val contact = binding.etContact.text.trim().toString() + val type = adapter.getSelectItem()?.type ?: "" + val imagePath = imagePath + if (imagePath != null && imageUrl == null) { + uploadImage(imagePath, { + imageUrl = it + submit() + }, { + if (it != null) { + toast(ResUtil.getString(R.string.ui_user_userinfomodifyactivity_08) + ":${it.message}") + } + dialogManager.dismissDialog() + }) + } else { + viewModel.submitFeedback( + type = type, + content = content, + image = imageUrl ?: "", + contact = contact + ) + } + } + + + private fun checkStoragePermission() { + PhotoPickActivity.start(this, PhotoPickActivity.IMG) + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (resultCode == RESULT_OK) { + if (requestCode == PhotoPickActivity.PICK_ACT_RESULT) { + if (data == null) { + return + } + val uri = data.data + uri?.let { + val file = MyUriUtils.copyFile(this, uri) + if (file != null) { + compressPhotos(mutableListOf(file.path)) + } else { + ToastUtils.show(R.string.exception_try_again) + } + } + } + } + } + + private fun compressPhotos(paths: MutableList) { + compressJob?.cancel(null) + compressJob = PhotoCompressUtil.compress( + this, paths, + PhotoCompressUtil.getCompressCachePath(), + object : PhotosCompressCallback { + override fun onSuccess(compressedImgList: ArrayList) { + val firstItem = compressedImgList.firstOrNull() ?: return + onAddImage(firstItem) + } + + override fun onFail(e: Throwable) { + ToastUtils.show(getString(R.string.picker_image_error)) + } + } + ) + } + + @SuppressLint("CheckResult") + private fun uploadImage(path: String, success: (String) -> Unit, failed: (Throwable?) -> Unit) { + FileModel.get() + .uploadFile(path) + .compose(bindToLifecycle()) + .subscribe { url: String?, throwable: Throwable? -> + if (url != null) { + success.invoke(url) + } else { + failed.invoke(throwable) + } + } + } + + override fun needSteepStateBar(): Boolean { + return true + } + + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } + + + override fun onResume() { + super.onResume() + if (viewModel.configLiveData.value?.data == null) { + viewModel.getConfig() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/feedback/FeedbackTypeAdapter.kt b/app/src/main/java/com/chwl/app/ui/feedback/FeedbackTypeAdapter.kt new file mode 100644 index 0000000..a6672bc --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/feedback/FeedbackTypeAdapter.kt @@ -0,0 +1,42 @@ +package com.chwl.app.ui.feedback + +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.core.home.bean.FeedbackTypeBean + +class FeedbackTypeAdapter : BaseQuickAdapter(R.layout.feedback_item_type) { + + private var selectItem: FeedbackTypeBean? = null + + override fun convertPayloads( + helper: BaseViewHolder, + item: FeedbackTypeBean?, + payloads: MutableList + ) { + super.convertPayloads(helper, item, payloads) + convertState(helper, item) + } + + override fun convert(helper: BaseViewHolder, item: FeedbackTypeBean?) { + helper.setText(R.id.tv_name, item?.desc ?: "") + convertState(helper, item) + } + + private fun convertState(helper: BaseViewHolder, item: FeedbackTypeBean?) { + if (selectItem == item) { + helper.setBackgroundRes(R.id.tv_name, R.drawable.shape_85f6d3_15dp) + } else { + helper.setBackgroundRes(R.id.tv_name, R.drawable.shape_f3f5fa_15dp) + } + } + + fun selectItem(item: FeedbackTypeBean?) { + this.selectItem = item + notifyItemRangeChanged(0, itemCount, true) + } + + fun getSelectItem(): FeedbackTypeBean? { + return selectItem + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/feedback/FeedbackViewModel.kt b/app/src/main/java/com/chwl/app/ui/feedback/FeedbackViewModel.kt new file mode 100644 index 0000000..638023a --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/feedback/FeedbackViewModel.kt @@ -0,0 +1,36 @@ +package com.chwl.app.ui.feedback + +import androidx.lifecycle.MutableLiveData +import com.chwl.app.base.BaseViewModel +import com.chwl.core.bean.response.BeanResult +import com.chwl.core.home.bean.FeedbackConfigBean +import com.chwl.core.home.model.HomeModel +import kotlinx.coroutines.flow.MutableSharedFlow + +class FeedbackViewModel : BaseViewModel() { + val configLiveData = MutableLiveData?>() + + val submitStateFlow = MutableSharedFlow>() + + fun getConfig() { + safeLaunch( + needLoading = true, + onError = { + configLiveData.postValue(BeanResult.failed(it)) + }) { + val value = HomeModel.getFeedbackConfig() + configLiveData.postValue(BeanResult.success(value)) + } + } + + fun submitFeedback(type: String, content: String, image: String, contact: String) { + safeLaunch( + needLoading = true, + onError = { + submitStateFlow.emit(BeanResult.failed(it)) + }) { + val value = HomeModel.commitFeedback(contact, content, image, type) + submitStateFlow.emit(BeanResult.success(value)) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/game_team/invite/GameTeamInviteDialog.kt b/app/src/main/java/com/chwl/app/ui/game_team/invite/GameTeamInviteDialog.kt new file mode 100644 index 0000000..3445c06 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/game_team/invite/GameTeamInviteDialog.kt @@ -0,0 +1,202 @@ +package com.chwl.app.ui.game_team.invite + +import android.annotation.SuppressLint +import android.os.Bundle +import android.view.Gravity +import android.view.WindowManager +import androidx.fragment.app.viewModels +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import com.chwl.app.R +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.common.widget.dialog.DialogManager +import com.chwl.app.databinding.GameTeamInviteDialogBinding +import com.chwl.app.ui.pay.ChargeActivity +import com.chwl.app.ui.utils.load +import com.chwl.core.game_team.UserGameTeamInfo +import com.chwl.core.pay.PayModel +import com.chwl.core.pay.bean.WalletInfo +import com.chwl.core.utils.net.BalanceNotEnoughExeption +import com.chwl.library.utils.ResUtil +import com.chwl.library.utils.SingleToastUtil +import com.example.lib_utils.ktx.singleClick +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.launch +import java.math.BigDecimal +import java.math.RoundingMode + + +class GameTeamInviteDialog : BaseDialogFragment() { + + private val viewModel: GameTeamInviteViewModel by viewModels() + + override var width = WindowManager.LayoutParams.MATCH_PARENT + override var gravity = Gravity.CENTER + + private var gameId: Long = 0 + private var gameUid: Long = 0 + private var gameBackground: String? = null + private var gamePrice: Long = 0 + private var gameInning: Long = 1 + private var dialogManager: DialogManager? = null + + var successListener: (() -> Unit)? = null + + companion object { + fun newInstance(info: UserGameTeamInfo): GameTeamInviteDialog { + return newInstance(info.uid ?: 0, info.gameId ?: 0, info.pic, info.price ?: 0, 1) + } + + fun newInstance( + targetUid: Long, + gameId: Long, + gameBackground: String?, + gamePrice: Long, + gameInning: Long, + ): GameTeamInviteDialog { + return GameTeamInviteDialog().apply { + arguments = Bundle().apply { + putLong("targetUid", targetUid) + putLong("gameId", gameId) + putSerializable("gameBackground", gameBackground) + putLong("gamePrice", gamePrice) + putLong("gameInning", gameInning) + } + } + } + } + + override fun init() { + gameUid = arguments?.getLong("targetUid") ?: 0 + gameId = arguments?.getLong("gameId") ?: 0 + gameBackground = arguments?.getString("gameBackground") + gamePrice = arguments?.getLong("gamePrice") ?: 0 + gameInning = arguments?.getLong("gameInning") ?: 1 + dialogManager = DialogManager(requireContext()) + initView() + initEvent() + initObserve() + } + + override fun onResume() { + super.onResume() + updateBalance() + } + + private fun initView() { + binding.ivGameImage.load(gameBackground) + updateInning(0) + requestBalance() + } + + private fun initEvent() { + binding.ivClose.setOnClickListener { + safeDismiss() + } + + binding.tvPay.singleClick { + pay() + } + + binding.layoutRecharge.setOnClickListener { + ChargeActivity.start(context) + } + + binding.ivCountAdd.setOnClickListener { + updateInning(1) + } + + binding.ivCountSubtract.setOnClickListener { + updateInning(-1) + } + } + + private fun initObserve() { + viewLifecycleOwner.lifecycleScope.launch { + viewLifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { + viewModel.payResultFlow.collectLatest { + dialogManager?.dismissDialog() + if (it.isSuccess) { + successListener?.invoke() + SingleToastUtil.showToast(R.string.game_team_19) + safeDismiss() + } else if (it.code == BalanceNotEnoughExeption.code) { + showBalanceNotEnoughDialog() + } else { + it.message?.let { msg -> + SingleToastUtil.showToast(msg) + } + } + } + } + } + } + + private fun showBalanceNotEnoughDialog() { + dialogManager?.showOkCancelDialog( + ResUtil.getString(R.string.widget_dialog_dialoguihelper_04), + ResUtil.getString(R.string.treasure_to_charge) + ) { + ChargeActivity.start(context) + } + } + + private fun pay() { + dialogManager?.showProgressDialog(requireContext()) + viewModel.pay(gameId, gameUid, gameInning) + } + + private fun updateInning(add: Int) { + var newInning = gameInning + add + if (newInning <= 0) { + newInning = 1 + } + gameInning = newInning + if (gameInning <= 1L) { + binding.ivCountSubtract.setImageResource(R.drawable.game_team_invite_ic_subtract_disabled) + binding.ivCountSubtract.isEnabled = false + } else { + binding.ivCountSubtract.setImageResource(R.drawable.game_team_invite_ic_subtract) + binding.ivCountSubtract.isEnabled = true + } + binding.tvCount.text = gameInning.toString() + updateMoney() + } + + private fun updateMoney() { + val total = gamePrice * gameInning + binding.tvMoney.text = total.toString() + } + + @SuppressLint("SetTextI18n") + private fun updateBalance() { + if (_binding == null) { + return + } + val balanceTitle = getString(R.string.gift_wallet_overage) + val balanceValue = PayModel.get().currentWalletInfo?.diamondNum ?: 0.0 + var balanceBigDecimal = BigDecimal.valueOf(balanceValue) + balanceBigDecimal = balanceBigDecimal.setScale(0, RoundingMode.DOWN) + binding.tvBalance.text = "$balanceTitle${balanceBigDecimal.toPlainString()}" + } + + @SuppressLint("CheckResult") + private fun requestBalance() { + PayModel.get().myRemoteWalletInfo.compose(bindToLifecycle()) + .subscribe { info: WalletInfo -> + updateBalance() + } + } + + override fun onDestroyView() { + super.onDestroyView() + dialogManager?.dismissDialog() + dialogManager = null + } + + override fun onDestroy() { + super.onDestroy() + successListener = null + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/game_team/invite/GameTeamInviteViewModel.kt b/app/src/main/java/com/chwl/app/ui/game_team/invite/GameTeamInviteViewModel.kt new file mode 100644 index 0000000..166d3b8 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/game_team/invite/GameTeamInviteViewModel.kt @@ -0,0 +1,22 @@ +package com.chwl.app.ui.game_team.invite + +import com.chwl.app.base.BaseViewModel +import com.chwl.core.auth.AuthModel +import com.chwl.core.bean.response.BeanResult +import com.chwl.core.room.game.GameModel +import kotlinx.coroutines.flow.MutableSharedFlow + +class GameTeamInviteViewModel : BaseViewModel() { + + var payResultFlow = MutableSharedFlow>() + + fun pay(gameId: Long, gameUid: Long, inning: Long) { + safeLaunch(onError = { + payResultFlow.emit(BeanResult.failed(it)) + }) { + val result = + GameModel.startGameTeam(gameId, gameUid, inning, AuthModel.get().currentUid) + payResultFlow.emit(BeanResult.success(result)) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/game_team/record/GameTeamRecordActivity.kt b/app/src/main/java/com/chwl/app/ui/game_team/record/GameTeamRecordActivity.kt new file mode 100644 index 0000000..07322ef --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/game_team/record/GameTeamRecordActivity.kt @@ -0,0 +1,63 @@ +package com.chwl.app.ui.game_team.record + +import android.content.Context +import android.content.Intent +import android.widget.TextView +import androidx.fragment.app.Fragment +import com.chwl.app.R +import com.chwl.app.avroom.adapter.CommonVPAdapter +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.databinding.GameTeamRecordActivityBinding +import com.chwl.app.ui.widget.magicindicator.ViewPagerHelper +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.CommonNavigator +import com.chwl.library.utils.ResUtil +import com.netease.nim.uikit.StatusBarUtil + +class GameTeamRecordActivity : BaseViewBindingActivity() { + + companion object { + fun start(context: Context) { + context.startActivity(Intent(context, GameTeamRecordActivity::class.java)) + } + } + + override fun init() { + initWhiteTitleBar(ResUtil.getString(R.string.game_team_09)) + initTab() + } + + private fun initTab() { + val fragmentList = ArrayList() + fragmentList.add(GameTeamRecordFragment.newInstance(GameTeamRecordFragment.TYPE_INITIATOR)) + fragmentList.add(GameTeamRecordFragment.newInstance(GameTeamRecordFragment.TYPE_RECEIVER)) + val titleList = ArrayList() + titleList.add(getString(R.string.game_team_10)) + titleList.add(getString(R.string.game_team_11)) + val commonNavigator = CommonNavigator(context) + commonNavigator.setTitleWrapContent(false) + val magicIndicatorAdapter = GameTeamRecordIndicatorAdapter(context, titleList) + magicIndicatorAdapter.setOnItemSelectListener { position: Int, view: TextView? -> + binding.viewPager.currentItem = position + } + commonNavigator.adapter = magicIndicatorAdapter + binding.magicIndicator.navigator = commonNavigator + binding.viewPager.offscreenPageLimit = 2 + binding.viewPager.adapter = CommonVPAdapter( + supportFragmentManager, + lifecycle, + fragmentList + ) + binding.viewPager.isUserInputEnabled = false + ViewPagerHelper.bind(binding.magicIndicator, binding.viewPager) + } + + override fun needSteepStateBar(): Boolean { + return true + } + + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/game_team/record/GameTeamRecordAdapter.kt b/app/src/main/java/com/chwl/app/ui/game_team/record/GameTeamRecordAdapter.kt new file mode 100644 index 0000000..96665fc --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/game_team/record/GameTeamRecordAdapter.kt @@ -0,0 +1,38 @@ +package com.chwl.app.ui.game_team.record + +import android.view.View +import android.widget.ImageView +import androidx.core.view.isVisible +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.ui.utils.load +import com.chwl.app.ui.utils.loadAvatar +import com.chwl.core.game_team.GameTeamRecordBean + +class GameTeamRecordAdapter : + BaseQuickAdapter(R.layout.game_team_record_item) { + + var isInitiator = false + + override fun convert(helper: BaseViewHolder, item: GameTeamRecordBean?) { + helper.addOnClickListener(R.id.tv_repurchase, R.id.tv_chat, R.id.iv_order_id_copy) + val userAvatarView = helper.getView(R.id.iv_user_avatar) + val repurchaseView = helper.getView(R.id.tv_repurchase) + if (isInitiator) { + repurchaseView.isVisible = true + helper.setText(R.id.tv_user_name, item?.toNick ?: "") + helper.setText(R.id.tv_user_id, item?.toErBanNo?.toString() ?: "") + userAvatarView.load(item?.toAvatar) + } else { + repurchaseView.isVisible = false + helper.setText(R.id.tv_user_name, item?.fromNick ?: "") + helper.setText(R.id.tv_user_id, item?.fromErBanNo?.toString() ?: "") + userAvatarView.load(item?.fromAvatar) + } + helper.setText(R.id.tv_game_name, item?.gameName ?: "") + helper.setText(R.id.tv_order_money, item?.amount?.toString()) + helper.setText(R.id.tv_order_time, item?.orderTime) + helper.setText(R.id.tv_order_id, item?.orderNo) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/game_team/record/GameTeamRecordFragment.kt b/app/src/main/java/com/chwl/app/ui/game_team/record/GameTeamRecordFragment.kt new file mode 100644 index 0000000..a61f93e --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/game_team/record/GameTeamRecordFragment.kt @@ -0,0 +1,154 @@ +package com.chwl.app.ui.game_team.record + +import android.os.Bundle +import androidx.fragment.app.viewModels +import androidx.recyclerview.widget.LinearLayoutManager +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingFragment +import com.chwl.app.common.EmptyViewHelper +import com.chwl.app.databinding.GameTemaRecordFragmentBinding +import com.chwl.app.ui.game_team.invite.GameTeamInviteDialog +import com.chwl.app.ui.im.avtivity.NimP2PMessageActivity +import com.chwl.app.ui.utils.RVDelegate +import com.chwl.app.utils.ClipboardUtils +import com.chwl.core.game_team.GameTeamRecordBean +import com.chwl.library.utils.SingleToastUtil + +class GameTeamRecordFragment : BaseViewBindingFragment() { + + companion object { + const val TYPE_INITIATOR = 0 + const val TYPE_RECEIVER = 1 + fun newInstance(type: Int): GameTeamRecordFragment { + return GameTeamRecordFragment().apply { + arguments = Bundle().apply { + putInt("type", type) + } + } + } + } + + private val viewModel: GameTeamRecordViewModel by viewModels() + private val adapter = GameTeamRecordAdapter() + + private var type: Int = TYPE_INITIATOR + + private var rvDelegate: RVDelegate? = null + + private var pageNum = 1 + + private val pageSize = 20 + + override fun init() { + type = arguments?.getInt("type", TYPE_INITIATOR) ?: TYPE_INITIATOR + initView() + initEvent() + initObserve() + binding.swipeRefresh.isRefreshing = true + loadData(true) + } + + private fun initView() { + adapter.isInitiator = type == TYPE_INITIATOR + binding.recyclerView.adapter = adapter + rvDelegate = RVDelegate.Builder() + .setPageSize(pageSize) + .setAdapter(adapter) + .setRecyclerView(binding.recyclerView) + .setEmptyView( + EmptyViewHelper.createEmptyTextViewHeight( + context, + getString(R.string.data_empty) + ) + ) + .setLayoutManager(LinearLayoutManager(mContext)) + .build() + } + + private fun initEvent() { + adapter.setOnItemChildClickListener { adapter, view, position -> + val item = (adapter.getItem(position) as? GameTeamRecordBean) + ?: return@setOnItemChildClickListener + + when (view.id) { + R.id.tv_repurchase -> { + jumpRepurchase(item) + } + + R.id.tv_chat -> { + jumpChat(item) + } + + R.id.iv_order_id_copy -> { + ClipboardUtils.copyText(item.orderNo ?: "") + toast(getString(R.string.have_copy)) + } + } + } + binding.swipeRefresh.setOnRefreshListener { + loadData(true) + } + adapter.setOnLoadMoreListener({ + loadData(false) + }, binding.recyclerView) + } + + private fun initObserve() { + viewModel.listLiveData.observe(this) { + binding.swipeRefresh.isRefreshing = false + rvDelegate?.loadData(it) + if (!it.isSuccess && it.message != null) { + toast(it.message) + } + } + } + + private fun jumpRepurchase(item: GameTeamRecordBean) { + val uid = getTargetUidByItem(item) + val gameId = item.gameId + val gameBackground = item.gamePic + val gamePrice = item.price ?: 0 + val gameInning = item.inning ?: 1 + if (uid == null || gameId == null) { + toast(R.string.data_parsing_exception) + return + } + GameTeamInviteDialog.newInstance( + targetUid = uid, + gameId = gameId, + gameBackground = gameBackground, + gamePrice = gamePrice, + gameInning = gameInning + ).apply { + this.successListener = { + loadData(true) + } + }.safeShow(requireActivity().supportFragmentManager, requireActivity()) + } + + private fun jumpChat(item: GameTeamRecordBean) { + val targetUid = getTargetUidByItem(item)?.toString() + if (targetUid.isNullOrEmpty()) { + return + } + NimP2PMessageActivity.start(requireContext(), targetUid) + } + + private fun getTargetUidByItem(item: GameTeamRecordBean): Long? { + val targetUid = if (type == TYPE_INITIATOR) { + item.toUid + } else { + item.fromUid + } + return targetUid + } + + private fun loadData(isRefresh: Boolean) { + if (isRefresh) { + pageNum = 1 + } else { + pageNum++ + } + viewModel.getRecordList(type, pageNum, pageSize) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/game_team/record/GameTeamRecordIndicatorAdapter.java b/app/src/main/java/com/chwl/app/ui/game_team/record/GameTeamRecordIndicatorAdapter.java new file mode 100644 index 0000000..39d782f --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/game_team/record/GameTeamRecordIndicatorAdapter.java @@ -0,0 +1,103 @@ +package com.chwl.app.ui.game_team.record; + +import android.content.Context; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.TextView; + +import androidx.core.content.ContextCompat; + +import com.chwl.app.R; +import com.chwl.app.ui.widget.XRecyclerView.ScaleTransitionPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.CommonNavigatorAdapter; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.indicators.LinePagerIndicator; + +import java.util.List; + +public class GameTeamRecordIndicatorAdapter extends CommonNavigatorAdapter { + private final Context mContext; + private final List mTitleList; + + private int textSize = 14; + private float minScale = 1f; + private boolean showIndicator = true; + private OnItemSelectListener mOnItemSelectListener; + + public GameTeamRecordIndicatorAdapter(Context context, List charSequences) { + this.mContext = context; + this.mTitleList = charSequences; + } + + @Override + public int getCount() { + return mTitleList == null ? 0 : mTitleList.size(); + } + + @Override + public IPagerTitleView getTitleView(Context context, final int i) { + ScaleTransitionPagerTitleView scaleTransitionPagerTitleView = new ScaleTransitionPagerTitleView(context, true); + scaleTransitionPagerTitleView.setNormalColor(ContextCompat.getColor(context, R.color.color_66000000)); + scaleTransitionPagerTitleView.setSelectedColor(ContextCompat.getColor(context, R.color.color_000000)); + scaleTransitionPagerTitleView.setMinScale(minScale); + scaleTransitionPagerTitleView.setTextSize(textSize); + int padding = UIUtil.dip2px(context, 13); + scaleTransitionPagerTitleView.setPadding(padding, 0, padding, 0); + scaleTransitionPagerTitleView.setText(mTitleList.get(i)); + scaleTransitionPagerTitleView.setOnClickListener(view -> { + if (mOnItemSelectListener != null) { + mOnItemSelectListener.onItemSelect(i, scaleTransitionPagerTitleView); + } + + }); + return scaleTransitionPagerTitleView; + } + + @Override + public IPagerIndicator getIndicator(Context context) { + LinePagerIndicator indicator = new LinePagerIndicator(context); + indicator.setMode(LinePagerIndicator.MODE_EXACTLY); + indicator.setLineHeight(context.getResources().getDimensionPixelOffset(R.dimen.dp_3)); + indicator.setRoundRadius(context.getResources().getDimensionPixelOffset(R.dimen.dp_2)); + indicator.setLineWidth(context.getResources().getDimensionPixelOffset(R.dimen.dp_13)); + indicator.setColors(context.getResources().getColor(R.color.color_0FCA81)); + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); +// lp.bottomMargin = mBottomMargin; + indicator.setLayoutParams(lp); + return indicator; + } + + public int getTextSize() { + return textSize; + } + + public void setTextSize(int textSize) { + this.textSize = textSize; + } + + public float getMinScale() { + return minScale; + } + + public void setMinScale(float minScale) { + this.minScale = minScale; + } + + public boolean isShowIndicator() { + return showIndicator; + } + + public void setShowIndicator(boolean showIndicator) { + this.showIndicator = showIndicator; + } + + public void setOnItemSelectListener(OnItemSelectListener onItemSelectListener) { + mOnItemSelectListener = onItemSelectListener; + } + + public interface OnItemSelectListener { + void onItemSelect(int position, TextView view); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/game_team/record/GameTeamRecordViewModel.kt b/app/src/main/java/com/chwl/app/ui/game_team/record/GameTeamRecordViewModel.kt new file mode 100644 index 0000000..277c73a --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/game_team/record/GameTeamRecordViewModel.kt @@ -0,0 +1,23 @@ +package com.chwl.app.ui.game_team.record + +import androidx.lifecycle.MutableLiveData +import com.chwl.app.base.BaseViewModel +import com.chwl.core.auth.AuthModel +import com.chwl.core.bean.response.ListResult +import com.chwl.core.game_team.GameTeamRecordBean +import com.chwl.core.room.game.GameModel + +class GameTeamRecordViewModel : BaseViewModel() { + + val listLiveData = MutableLiveData>() + + fun getRecordList(type: Int, pageNum: Int, pageSize: Int) { + safeLaunch(onError = { + listLiveData.postValue(ListResult.failed(pageNum, it)) + }) { + val list = + GameModel.getGameTeamRecordList(type, pageNum, pageSize, AuthModel.get().currentUid) + listLiveData.postValue(ListResult.success(list, pageNum)) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/gift/adapter/FaceGVAdapter.java b/app/src/main/java/com/chwl/app/ui/gift/adapter/FaceGVAdapter.java new file mode 100644 index 0000000..7e57955 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/gift/adapter/FaceGVAdapter.java @@ -0,0 +1,143 @@ +package com.chwl.app.ui.gift.adapter; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.recyclerview.widget.RecyclerView; + +import com.chwl.app.R; +import com.chwl.app.ui.gift.util.RecyclerViewUtil; +import com.chwl.app.ui.gift.widget.GiftDataInfo; +import com.chwl.app.ui.utils.ImageLoadUtils; + +import java.io.IOException; +import java.util.List; + +public class FaceGVAdapter extends RecyclerView.Adapter { + private List list; + private RecyclerView mRecyclerView; + private Context mContext; + private boolean isNetData; + + private ViewHodler mHolder; + private int clickTemp = -1; + private RecyclerViewUtil recyclerViewUtil; + + //标识选择的Item + public void setSeclection(int position) { + clickTemp = position; + } + + public int getSecletion() { + return clickTemp; + } + + public FaceGVAdapter(RecyclerView recyclerView, List list, Context mContext, boolean isNetData) { + super(); + this.mRecyclerView = recyclerView; + this.list = list; + this.mContext = mContext; + this.isNetData = isNetData; + recyclerViewClickListenter(list, mContext); + } + + private void recyclerViewClickListenter(final List list, Context mContext) { + recyclerViewUtil = new RecyclerViewUtil(mContext, mRecyclerView); + recyclerViewUtil.setOnItemClickListener(new RecyclerViewUtil.OnItemClickListener() { + + private LinearLayout llroot; + + @Override + public void onItemClick(int position, View view) { + if (mOnItemClickListener != null) { + final GiftDataInfo giftDataInfo = list.get(position); + mOnItemClickListener.onItemClick(view, giftDataInfo, position); + if (llroot == null) { + llroot = (LinearLayout) view.findViewById(R.id.ll_gift_root); + } + llroot.setBackgroundResource(R.drawable.shape_gift_chose); + clickTemp = position; + notifyDataSetChanged(); + } + } + }); + } + + public void clear() { + this.mContext = null; + } + + @Override + public ViewHodler onCreateViewHolder(ViewGroup parent, int viewType) { + View view = LayoutInflater.from(mContext).inflate(R.layout.face_image, parent, false); + return new ViewHodler(view); + } + + @Override + public void onBindViewHolder(final ViewHodler holder, final int position) { + final GiftDataInfo giftDataInfo = list.get(position); + if (isNetData) { + ImageLoadUtils.loadImage(mContext, giftDataInfo.getGiftPic(), holder.giftImg); + } else { + try { + Bitmap mBitmap = BitmapFactory.decodeStream(mContext.getAssets().open(giftDataInfo.getGiftName())); + holder.giftImg.setImageBitmap(mBitmap); + } catch (IOException e) { + e.printStackTrace(); + } + } + + holder.giftName.setText(giftDataInfo.getGiftName()); + holder.giftPrice.setText(giftDataInfo.getGiftPrice()); + if (clickTemp == position) { + holder.llroot.setBackgroundResource(R.drawable.shape_gift_chose); + mHolder = holder; + } else { + holder.llroot.setBackgroundResource(R.drawable.shape_gift_tran); + } + } + + @Override + public int getItemCount() { + return list.size(); + } + + public void clearSelection() { + if (mHolder != null) { + mHolder.llroot.setBackgroundResource(R.drawable.shape_gift_tran); + mHolder = null; + } + } + + class ViewHodler extends RecyclerView.ViewHolder { + LinearLayout llroot; + ImageView giftImg; + TextView giftName; + TextView giftPrice; + + public ViewHodler(View view) { + super(view); + llroot = (LinearLayout) view.findViewById(R.id.ll_gift_root); + giftImg = (ImageView) view.findViewById(R.id.face_img); + giftName = (TextView) view.findViewById(R.id.face_name); + giftPrice = (TextView) view.findViewById(R.id.face_price); + } + } + + public interface OnItemClickListener { + void onItemClick(View view, GiftDataInfo giftDataInfo, int position); + } + + public OnItemClickListener mOnItemClickListener; + + public void setOnItemClickListener(OnItemClickListener listener) { + mOnItemClickListener = listener; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/gift/adapter/FaceVPAdapter.java b/app/src/main/java/com/chwl/app/ui/gift/adapter/FaceVPAdapter.java new file mode 100644 index 0000000..f99ebbb --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/gift/adapter/FaceVPAdapter.java @@ -0,0 +1,40 @@ +package com.chwl.app.ui.gift.adapter; + +import android.view.View; +import android.view.ViewGroup; + +import androidx.viewpager.widget.PagerAdapter; + +import java.util.List; + +public class FaceVPAdapter extends PagerAdapter { + + // 界面列表 + private List views; + + public FaceVPAdapter(List views) { + this.views = views; + } + + @Override + public int getCount() { + return views != null ? views.size() : 0; + } + + + @Override + public boolean isViewFromObject(View view, Object object) { + return view == object; + } + + @Override + public Object instantiateItem(ViewGroup container, int position) { + container.addView(views.get(position), 0); + return views.get(position); + } + + @Override + public void destroyItem(ViewGroup container, int position, Object object) { + container.removeView(views.get(position)); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/gift/callback/OnGiftDialogBtnClickListenerWrapper.java b/app/src/main/java/com/chwl/app/ui/gift/callback/OnGiftDialogBtnClickListenerWrapper.java new file mode 100644 index 0000000..052a4fc --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/gift/callback/OnGiftDialogBtnClickListenerWrapper.java @@ -0,0 +1,16 @@ +package com.chwl.app.ui.gift.callback; + +import com.chwl.app.ui.widget.GiftDialog; +import com.chwl.core.gift.bean.GiftInfo; +import com.chwl.core.room.queue.bean.MicMemberInfo; + +import java.util.ArrayList; +import java.util.List; + +public class OnGiftDialogBtnClickListenerWrapper implements GiftDialog.OnGiftDialogBtnClickListener { + @Override + public void onSendGiftBtnClick(GiftInfo giftInfo, ArrayList micMemberInfos, int number, String msg, boolean isKnap, boolean isWholeMic, List> drawFixedArray, GiftDialog.SenGiftCallback callback) { + + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/gift/dialog/GiftGridView.java b/app/src/main/java/com/chwl/app/ui/gift/dialog/GiftGridView.java new file mode 100644 index 0000000..20364ce --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/gift/dialog/GiftGridView.java @@ -0,0 +1,165 @@ +package com.chwl.app.ui.gift.dialog; + +import android.content.Context; +import android.util.AttributeSet; +import android.util.SparseArray; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.viewpager.widget.PagerAdapter; +import androidx.viewpager.widget.ViewPager; + +import com.chwl.app.BR; +import com.chwl.core.gift.bean.GiftInfo; +import com.chwl.core.magic.bean.MagicInfo; +import com.chwl.library.bindinglist.IItem; +import com.chwl.library.bindinglist.MultiTypeAdapter; +import com.chwl.library.utils.ListUtils; + +import java.util.ArrayList; +import java.util.List; + +/** + * 在这里统一处理礼物分页展示的逻辑 + * 同时支持礼物和魔法不同的bean,减少代码冗余 + * Created by lvzebiao on 2018/11/20. + */ + +public class GiftGridView extends ViewPager { + + private List> pagerList; + /** + * 一页数据的数量 + */ + private int PAGE_SIZE = 8; + + private OnItemClickListener listener; + + private IItem LastSelectedItem; + + public GiftGridView(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + public List> getPagerList() { + return pagerList; + } + + public void setPageSize(int pageSize) { + this.PAGE_SIZE = pageSize; + } + + public void setOnItemClickListener(OnItemClickListener listener) { + this.listener = listener; + } + + public void setGiftData(Context context, List data, boolean isKnap) { + pagerList = beanTransformVm(context, data, isKnap, PAGE_SIZE); + initView(context); + } + + public void setMagicData(Context context, List data) { + pagerList = beanTransformVm(context, data, false, PAGE_SIZE); + initView(context); + } + + private void initView(final Context context) { + LastSelectedItem = null; + if (ListUtils.isListEmpty(pagerList)) { + return; + } + SparseArray cacheItemView = new SparseArray<>(); + setAdapter(new PagerAdapter() { + @Override + public int getCount() { + return pagerList.size(); + } + + @Override + public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { + return view == object; + } + + @NonNull + @Override + public Object instantiateItem(@NonNull ViewGroup container, int pagePos) { + RecyclerView recyclerView; + MultiTypeAdapter giftAdapter; + if (cacheItemView.get(pagePos) == null) { + recyclerView = new RecyclerView(context); + recyclerView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT)); + recyclerView.setLayoutManager(new GridLayoutManager(context, 4)); + giftAdapter = new MultiTypeAdapter(BR.item, true); + recyclerView.setAdapter(giftAdapter); + cacheItemView.put(pagePos, recyclerView); + } else { + recyclerView = cacheItemView.get(pagePos); + giftAdapter = (MultiTypeAdapter) recyclerView.getAdapter(); + } + giftAdapter.clearAllItem(); + giftAdapter.addData(pagerList.get(pagePos)); + giftAdapter.setOnItemClickListener(item -> { + if (item instanceof GiftInfoVm) { + GiftInfoVm giftInfoVm = (GiftInfoVm) item; + if (LastSelectedItem != null) { + if (LastSelectedItem instanceof GiftInfoVm) { + ((GiftInfoVm) LastSelectedItem).isSelect.set(false); + } + } + giftInfoVm.isSelect.set(true); + LastSelectedItem = item; + } + if (listener != null) { + listener.onClick(item); + } + }); + return recyclerView; + } + + @Override + public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { + RecyclerView recyclerView = cacheItemView.get(position); + MultiTypeAdapter adapter = (MultiTypeAdapter) recyclerView.getAdapter(); + adapter.getAllItems().clear(); + container.removeView(recyclerView); + } + }); + } + + public interface OnItemClickListener { + void onClick(IItem item); + } + + public static List> beanTransformVm(Context context, List data, boolean isKnap, int pageSize) { + List> result = new ArrayList<>(); + if (ListUtils.isListEmpty(data)) { + return result; + } + for (int i = 0; i < data.size(); i++) { + IItem item = null; + List page = null; + if (i % pageSize == 0) { + page = new ArrayList<>(); + result.add(page); + } else { + if (result.size() > 0) { + page = result.get(result.size() - 1); + } + } + item = createGiftItem(context, (GiftInfo) data.get(i), i == 0, isKnap); + if (page != null) { + page.add(item); + } + } + return result; + } + + public static GiftInfoVm createGiftItem(Context context, GiftInfo giftInfo, boolean select, boolean isKnap) { + return new GiftInfoVm(context, giftInfo, select, isKnap); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/gift/dialog/GiftInfoVm.java b/app/src/main/java/com/chwl/app/ui/gift/dialog/GiftInfoVm.java new file mode 100644 index 0000000..c2bae7b --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/gift/dialog/GiftInfoVm.java @@ -0,0 +1,145 @@ +package com.chwl.app.ui.gift.dialog; + +import android.content.Context; +import android.graphics.drawable.Drawable; + +import androidx.databinding.ObservableBoolean; +import androidx.databinding.ObservableField; + +import com.chwl.app.R; +import com.chwl.app.vip.util.VipHelper; +import com.chwl.core.gift.bean.GiftInfo; +import com.chwl.core.gift.bean.GiftType; +import com.chwl.core.gift.bean.SimpleVipInfo; +import com.chwl.library.bindinglist.BaseItem; +import com.chwl.library.utils.TimeUtils; + +/** + * 礼物item + * Created by lvzebiao on 2018/11/19. + */ + +public class GiftInfoVm extends BaseItem { + + public final ObservableBoolean isSelect = new ObservableBoolean(); + + public final ObservableField goldText = new ObservableField<>(); + + public final ObservableBoolean isKnap = new ObservableBoolean(); + + public final ObservableField countText = new ObservableField<>(); + + public final ObservableField countDownText = new ObservableField<>(); + + public Drawable nobleDrawable = null; + + public Drawable radishDrawable = null; + + public Drawable radishDrawableSelected = null; + + /** + * 是否显示新 + */ + public boolean isShowNew = false; + + /** + * 显示限定 + */ + public boolean isShowLimit = false; + + /** + * 显示特定 + */ + public boolean isShowEffect = false; + + /** + * 是否显示专属礼物 + */ + public boolean isExclusive = false; + + public boolean isLocked = false; + + public String vipIcon; + + /** + * 是否显示免费礼物 + */ + public boolean isFreeGift; + + /** + * 是否超级幸运礼物 + */ + public boolean isSuperLuckyGift; + + /** + * 礼物名称 + */ + public String giftName; + + public GiftInfoVm(Context context, GiftInfo data, boolean select, boolean isKnap) { + super(context, data); + this.isSelect.set(select); + if (data.getConsumeType() == GiftInfo.CONSUME_TYPE_GOLD) { + radishDrawable = null; + radishDrawableSelected = null; + goldText.set(String.valueOf(data.getGoldPrice())); + } else if (data.getConsumeType() == GiftInfo.CONSUME_TYPE_FREE_GIFT) { + radishDrawable = null; + radishDrawableSelected = null; + goldText.set(context.getResources().getString(R.string.free_gift)); + } else { + radishDrawable = null; + radishDrawableSelected = null; + goldText.set(String.valueOf(data.getGoldPrice())); + } + this.isKnap.set(isKnap); + updateCount(); + int nobleId = data.getLevel(); + if (nobleId == 0) { + // 普通表情 + nobleDrawable = null; + } else { + int drawableId = nobleId == 1 ? R.drawable.ic_tag_1 : nobleId == 2 ? R.drawable.ic_tag_2 : nobleId == 3 ? + R.drawable.ic_tag_3 : nobleId == 4 ? R.drawable.ic_tag_4 : nobleId == 5 ? R.drawable.ic_tag_5 : nobleId == 6 ? + R.drawable.ic_tag_6 : nobleId == 7 ? R.drawable.ic_tag_7 : 0; + nobleDrawable = context.getResources().getDrawable(drawableId); + } + isShowNew = data.isHasLatest(); + isShowLimit = data.isHasTimeLimit(); + isShowEffect = data.isHasEffect(); + isExclusive = data.isRoomExclude(); + if (data.getConsumeType() == GiftInfo.CONSUME_TYPE_FREE_GIFT) { + isFreeGift = true; + } + isSuperLuckyGift = (data.getGiftType() == GiftType.GIFT_TYPE_SUPER_LUCKY); + SimpleVipInfo vipInfo = data.getGiftVipInfo(); + isLocked = vipInfo != null && VipHelper.getMyVipLevel() < vipInfo.getVipLevel(); + vipIcon = vipInfo == null ? "" : vipInfo.getVipIcon(); + giftName = data.getFirstGiftName(); + } + + @Override + public GiftInfo data() { + return super.data(); + } + + @Override + public int getType() { + return R.layout.list_item_dialog_gift; + } + + public void updateCount() { + this.countText.set("x" + data.getCount()); + } + + public void updateFreeGiftCount() { + long progress = data.getFreeGiftProgress(); + String countDown = TimeUtils.timeConversion(progress); + if (progress == 0) { + this.countDownText.set(""); + } else { + this.countDownText.set(countDown); + } + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/gift/dialog/PageIndicatorView.java b/app/src/main/java/com/chwl/app/ui/gift/dialog/PageIndicatorView.java new file mode 100644 index 0000000..2ef286b --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/gift/dialog/PageIndicatorView.java @@ -0,0 +1,133 @@ +package com.chwl.app.ui.gift.dialog; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.View; +import android.widget.LinearLayout; + +import com.chwl.app.R; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by shichaohui on 2015/7/10 0010. + *

+ * 页码指示器类,获得此类实例后,可通过{@link PageIndicatorView#initIndicator(int)}方法初始化指示器 + *

+ */ +public class PageIndicatorView extends LinearLayout { + + private Context mContext = null; + private int dotSize = 6; // 指示器的大小(dp) + private int height = 6; // 指示器的大小(dp) + private double margins = 5; // 指示器间距(dp) + private List indicatorViews = null; // 存放指示器 + private int selectRes = R.drawable.shape_indicator_present_visible; + private int noSelectRes = R.drawable.shape_indicator_present_invisible; + + public void setSelectRes(int selectRes) { + this.selectRes = selectRes; + } + + public void setNoSelectRes(int noSelectRes) { + this.noSelectRes = noSelectRes; + } + + public PageIndicatorView(Context context) { + this(context, null); + } + + public PageIndicatorView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public PageIndicatorView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context); + } + + private void init(Context context) { + this.mContext = context; + + setGravity(Gravity.CENTER); + setOrientation(HORIZONTAL); + + dotSize = UIUtil.dip2px(context, dotSize); + height = UIUtil.dip2px(context, height); + margins = UIUtil.dip2px(context, (float) margins); + } + + public void setDotSize(int dotSize) { + this.dotSize = dotSize; + } + + public void setHeight(int height) { + this.height = height; + } + + /** + * 初始化指示器,默认选中第一页 + * + * @param count 指示器数量,即页数 + */ + public void initIndicator(int count) { + if (indicatorViews == null) { + indicatorViews = new ArrayList<>(); + } + indicatorViews.clear(); + removeAllViews(); + View view; + LayoutParams params = new LayoutParams(dotSize, height); + int margins = (int) this.margins; + params.setMargins(margins, margins, margins, margins); + for (int i = 0; i < count; i++) { + view = new View(mContext); + view.setBackgroundResource(noSelectRes); + addView(view, params); + indicatorViews.add(view); + } + if (indicatorViews.size() > 0) { + indicatorViews.get(0).setBackgroundResource(selectRes); + } + } + + /** + * 设置选中页 + * + * @param selected 页下标,从0开始 + */ + public void setSelectedPage(int selected) { + for (int i = 0; i < indicatorViews.size(); i++) { + if (i == selected) { + indicatorViews.get(i).setBackgroundResource(selectRes); + } else { + indicatorViews.get(i).setBackgroundResource(noSelectRes); + } + } + } + + /** + * 设置选中页 + * + * @param selected 页下标,从0开始 + */ + public void setDifSelectedPage(int selected) { + for (int i = 0; i < indicatorViews.size(); i++) { + if (i == selected) { + LayoutParams params = new LayoutParams(dotSize, height); + int margins = (int) this.margins; + params.setMargins(margins, margins, margins, margins); + indicatorViews.get(i).setLayoutParams(params); + indicatorViews.get(i).setBackgroundResource(selectRes); + } else { + LayoutParams params = new LayoutParams(height, height); + indicatorViews.get(i).setLayoutParams(params); + indicatorViews.get(i).setBackgroundResource(noSelectRes); + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/gift/gif/AnimatedGifDrawable.java b/app/src/main/java/com/chwl/app/ui/gift/gif/AnimatedGifDrawable.java new file mode 100644 index 0000000..108d3f1 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/gift/gif/AnimatedGifDrawable.java @@ -0,0 +1,64 @@ +package com.chwl.app.ui.gift.gif; + +import android.graphics.Bitmap; +import android.graphics.drawable.AnimationDrawable; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; + +import java.io.InputStream; + +public class AnimatedGifDrawable extends AnimationDrawable { + + private int mCurrentIndex = 0; + private UpdateListener mListener; + + public AnimatedGifDrawable(InputStream source, UpdateListener listener) { + mListener = listener; + GifDecoder decoder = new GifDecoder(); + decoder.read(source); + // Iterate through the gif frames, add each as animation frame + for (int i = 0; i < decoder.getFrameCount(); i++) { + Bitmap bitmap = decoder.getFrame(i); + BitmapDrawable drawable = new BitmapDrawable(bitmap); + // Explicitly set the bounds in order for the frames to display + drawable.setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight()); + addFrame(drawable, decoder.getDelay(i)); + if (i == 0) { + // Also set the bounds for this container drawable + setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight()); + } + } + } + + /** + * Naive method to proceed to next frame. Also notifies listener. + */ + public void nextFrame() { + mCurrentIndex = (mCurrentIndex + 1) % getNumberOfFrames(); + if (mListener != null) + mListener.update(); + } + + /** + * Return display duration for current frame + */ + public int getFrameDuration() { + return getDuration(mCurrentIndex); + } + + /** + * Return drawable for current frame + */ + public Drawable getDrawable() { + return getFrame(mCurrentIndex); + } + + /** + * Interface to notify listener to update/redraw Can't figure out how to + * invalidate the drawable (or span in which it sits) itself to force redraw + */ + public interface UpdateListener { + void update(); + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/gift/gif/AnimatedImageSpan.java b/app/src/main/java/com/chwl/app/ui/gift/gif/AnimatedImageSpan.java new file mode 100644 index 0000000..fe93b18 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/gift/gif/AnimatedImageSpan.java @@ -0,0 +1,78 @@ +package com.chwl.app.ui.gift.gif; + +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.os.Handler; +import android.text.style.DynamicDrawableSpan; + +public class AnimatedImageSpan extends DynamicDrawableSpan { + + private Drawable mDrawable; + + public AnimatedImageSpan(Drawable d) { + super(); + mDrawable = d; + // Use handler for 'ticks' to proceed to next frame + final Handler mHandler = new Handler(); + mHandler.post(new Runnable() { + public void run() { + ((AnimatedGifDrawable)mDrawable).nextFrame(); + // Set next with a delay depending on the duration for this frame + mHandler.postDelayed(this, ((AnimatedGifDrawable)mDrawable).getFrameDuration()); + } + }); + } + + /* + * Return current frame from animated drawable. Also acts as replacement for super.getCachedDrawable(), + * since we can't cache the 'image' of an animated image. + */ + @Override + public Drawable getDrawable() { + return ((AnimatedGifDrawable)mDrawable).getDrawable(); + } + + /* + * Copy-paste of super.getSize(...) but use getDrawable() to get the image/frame to calculate the size, + * in stead of the cached drawable. + */ + @Override + public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) { + Drawable d = getDrawable(); + Rect rect = d.getBounds(); + + if (fm != null) { + fm.ascent = -rect.bottom; + fm.descent = 0; + + fm.top = fm.ascent; + fm.bottom = 0; + } + + return rect.right; + } + + /* + * Copy-paste of super.draw(...) but use getDrawable() to get the image/frame to draw, in stead of + * the cached drawable. + */ + @Override + public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) { + Drawable b = getDrawable(); + canvas.save(); + + int transY = bottom - b.getBounds().bottom; + if (mVerticalAlignment == ALIGN_BASELINE) { + transY -= paint.getFontMetricsInt().descent; + } + + canvas.translate(x, transY); + b.draw(canvas); + canvas.restore(); + + } + +} + diff --git a/app/src/main/java/com/chwl/app/ui/gift/gif/GifDecoder.java b/app/src/main/java/com/chwl/app/ui/gift/gif/GifDecoder.java new file mode 100644 index 0000000..fa08a4d --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/gift/gif/GifDecoder.java @@ -0,0 +1,625 @@ +package com.chwl.app.ui.gift.gif; + +import android.graphics.Bitmap; +import android.graphics.Bitmap.Config; + +import java.io.InputStream; +import java.util.Vector; + +//Handler for read & extract Bitmap from *.gif +public class GifDecoder { + + // to store *.gif data, Bitmap & delay + class GifFrame { + // to access image & delay w/o interface + public Bitmap image; + public int delay; + + public GifFrame(Bitmap im, int del) { + image = im; + delay = del; + } + + } + + // to define some error type + public static final int STATUS_OK = 0; + public static final int STATUS_FORMAT_ERROR = 1; + public static final int STATUS_OPEN_ERROR = 2; + + protected int status; + + protected InputStream in; + + protected int width; // full image width + protected int height; // full image height + protected boolean gctFlag; // global color table used + protected int gctSize; // size of global color table + protected int loopCount = 1; // iterations; 0 = repeat forever + + protected int[] gct; // global color table + protected int[] lct; // local color table + protected int[] act; // active color table + + protected int bgIndex; // background color index + protected int bgColor; // background color + protected int lastBgColor; // previous bg color + protected int pixelAspect; // pixel aspect ratio + + protected boolean lctFlag; // local color table flag + protected boolean interlace; // interlace flag + protected int lctSize; // local color table size + + protected int ix, iy, iw, ih; // current image rectangle + protected int lrx, lry, lrw, lrh; + protected Bitmap image; // current frame + protected Bitmap lastImage; // previous frame + protected int frameindex = 0; + + public int getFrameindex() { + return frameindex; + } + + public void setFrameindex(int frameindex) { + this.frameindex = frameindex; + if (frameindex > frames.size() - 1) { + frameindex = 0; + } + } + + protected byte[] block = new byte[256]; // current data block + protected int blockSize = 0; // block size + + // last graphic control extension info + protected int dispose = 0; + // 0=no action; 1=leave in place; 2=restore to bg; 3=restore to prev + protected int lastDispose = 0; + protected boolean transparency = false; // use transparent color + protected int delay = 0; // delay in milliseconds + protected int transIndex; // transparent color index + + protected static final int MaxStackSize = 4096; + // max decoder pixel stack size + + // LZW decoder working arrays + protected short[] prefix; + protected byte[] suffix; + protected byte[] pixelStack; + protected byte[] pixels; + + protected Vector frames; // frames read from current file + protected int frameCount; + + // to get its Width / Height + public int getWidth() { + return width; + } + + public int getHeigh() { + return height; + } + + /** + * Gets display duration for specified frame. + * + * @param n + * int index of frame + * @return delay in milliseconds + */ + public int getDelay(int n) { + delay = -1; + if ((n >= 0) && (n < frameCount)) { + delay = ((GifFrame) frames.elementAt(n)).delay; + } + return delay; + } + + public int getFrameCount() { + return frameCount; + } + + public Bitmap getImage() { + return getFrame(0); + } + + public int getLoopCount() { + return loopCount; + } + + protected void setPixels() { + int[] dest = new int[width * height]; + // fill in starting image contents based on last image's dispose code + if (lastDispose > 0) { + if (lastDispose == 3) { + // use image before last + int n = frameCount - 2; + if (n > 0) { + lastImage = getFrame(n - 1); + } else { + lastImage = null; + } + } + if (lastImage != null) { + lastImage.getPixels(dest, 0, width, 0, 0, width, height); + // copy pixels + if (lastDispose == 2) { + // fill last image rect area with background color + int c = 0; + if (!transparency) { + c = lastBgColor; + } + for (int i = 0; i < lrh; i++) { + int n1 = (lry + i) * width + lrx; + int n2 = n1 + lrw; + for (int k = n1; k < n2; k++) { + dest[k] = c; + } + } + } + } + } + + // copy each source line to the appropriate place in the destination + int pass = 1; + int inc = 8; + int iline = 0; + for (int i = 0; i < ih; i++) { + int line = i; + if (interlace) { + if (iline >= ih) { + pass++; + switch (pass) { + case 2: + iline = 4; + break; + case 3: + iline = 2; + inc = 4; + break; + case 4: + iline = 1; + inc = 2; + } + } + line = iline; + iline += inc; + } + line += iy; + if (line < height) { + int k = line * width; + int dx = k + ix; // start of line in dest + int dlim = dx + iw; // end of dest line + if ((k + width) < dlim) { + dlim = k + width; // past dest edge + } + int sx = i * iw; // start of line in source + while (dx < dlim) { + // map color and insert in destination + int index = ((int) pixels[sx++]) & 0xff; + int c = act[index]; + if (c != 0) { + dest[dx] = c; + } + dx++; + } + } + } + image = Bitmap.createBitmap(dest, width, height, Config.ARGB_4444); + } + + public Bitmap getFrame(int n) { + Bitmap im = null; + if ((n >= 0) && (n < frameCount)) { + im = ((GifFrame) frames.elementAt(n)).image; + } + return im; + } + + public Bitmap nextBitmap() { + frameindex++; + if (frameindex > frames.size() - 1) { + frameindex = 0; + } + return ((GifFrame) frames.elementAt(frameindex)).image; + } + + public int nextDelay() { + return ((GifFrame) frames.elementAt(frameindex)).delay; + } + + // to read & parse all *.gif stream + public int read(InputStream is) { + init(); + if (is != null) { + in = is; + + readHeader(); + if (!err()) { + readContents(); + if (frameCount < 0) { + status = STATUS_FORMAT_ERROR; + } + } + } else { + status = STATUS_OPEN_ERROR; + } + try { + is.close(); + } catch (Exception e) { + e.printStackTrace(); + } + return status; + } + + protected void decodeImageData() { + int NullCode = -1; + int npix = iw * ih; + int available, clear, code_mask, code_size, end_of_information, in_code, old_code, bits, code, count, i, datum, data_size, first, top, bi, pi; + + if ((pixels == null) || (pixels.length < npix)) { + pixels = new byte[npix]; // allocate new pixel array + } + if (prefix == null) { + prefix = new short[MaxStackSize]; + } + if (suffix == null) { + suffix = new byte[MaxStackSize]; + } + if (pixelStack == null) { + pixelStack = new byte[MaxStackSize + 1]; + } + // Initialize GIF data stream decoder. + data_size = read(); + clear = 1 << data_size; + end_of_information = clear + 1; + available = clear + 2; + old_code = NullCode; + code_size = data_size + 1; + code_mask = (1 << code_size) - 1; + for (code = 0; code < clear; code++) { + prefix[code] = 0; + suffix[code] = (byte) code; + } + + // Decode GIF pixel stream. + datum = bits = count = first = top = pi = bi = 0; + for (i = 0; i < npix;) { + if (top == 0) { + if (bits < code_size) { + // Load bytes until there are enough bits for a code. + if (count == 0) { + // Read a new data block. + count = readBlock(); + if (count <= 0) { + break; + } + bi = 0; + } + datum += (((int) block[bi]) & 0xff) << bits; + bits += 8; + bi++; + count--; + continue; + } + // Get the next code. + code = datum & code_mask; + datum >>= code_size; + bits -= code_size; + + // Interpret the code + if ((code > available) || (code == end_of_information)) { + break; + } + if (code == clear) { + // Reset decoder. + code_size = data_size + 1; + code_mask = (1 << code_size) - 1; + available = clear + 2; + old_code = NullCode; + continue; + } + if (old_code == NullCode) { + pixelStack[top++] = suffix[code]; + old_code = code; + first = code; + continue; + } + in_code = code; + if (code == available) { + pixelStack[top++] = (byte) first; + code = old_code; + } + while (code > clear) { + pixelStack[top++] = suffix[code]; + code = prefix[code]; + } + first = ((int) suffix[code]) & 0xff; + // Add a new string to the string table, + if (available >= MaxStackSize) { + break; + } + pixelStack[top++] = (byte) first; + prefix[available] = (short) old_code; + suffix[available] = (byte) first; + available++; + if (((available & code_mask) == 0) + && (available < MaxStackSize)) { + code_size++; + code_mask += available; + } + old_code = in_code; + } + + // Pop a pixel off the pixel stack. + top--; + pixels[pi++] = pixelStack[top]; + i++; + } + for (i = pi; i < npix; i++) { + pixels[i] = 0; // clear missing pixels + } + } + + protected boolean err() { + return status != STATUS_OK; + } + + // to initia variable + public void init() { + status = STATUS_OK; + frameCount = 0; + frames = new Vector(); + gct = null; + lct = null; + } + + protected int read() { + int curByte = 0; + try { + curByte = in.read(); + } catch (Exception e) { + status = STATUS_FORMAT_ERROR; + } + return curByte; + } + + protected int readBlock() { + blockSize = read(); + int n = 0; + if (blockSize > 0) { + try { + int count = 0; + while (n < blockSize) { + count = in.read(block, n, blockSize - n); + if (count == -1) { + break; + } + n += count; + } + } catch (Exception e) { + e.printStackTrace(); + } + if (n < blockSize) { + status = STATUS_FORMAT_ERROR; + } + } + return n; + } + + // Global Color Table + protected int[] readColorTable(int ncolors) { + int nbytes = 3 * ncolors; + int[] tab = null; + byte[] c = new byte[nbytes]; + int n = 0; + try { + n = in.read(c); + } catch (Exception e) { + e.printStackTrace(); + } + if (n < nbytes) { + status = STATUS_FORMAT_ERROR; + } else { + tab = new int[256]; // max size to avoid bounds checks + int i = 0; + int j = 0; + while (i < ncolors) { + int r = ((int) c[j++]) & 0xff; + int g = ((int) c[j++]) & 0xff; + int b = ((int) c[j++]) & 0xff; + tab[i++] = 0xff000000 | (r << 16) | (g << 8) | b; + } + } + return tab; + } + + // Image Descriptor + protected void readContents() { + // read GIF file content blocks + boolean done = false; + while (!(done || err())) { + int code = read(); + switch (code) { + case 0x2C: // image separator + readImage(); + break; + case 0x21: // extension + code = read(); + switch (code) { + case 0xf9: // graphics control extension + readGraphicControlExt(); + break; + + case 0xff: // application extension + readBlock(); + String app = ""; + for (int i = 0; i < 11; i++) { + app += (char) block[i]; + } + if (app.equals("NETSCAPE2.0")) { + readNetscapeExt(); + } else { + skip(); // don't care + } + break; + default: // uninteresting extension + skip(); + } + break; + + case 0x3b: // terminator + done = true; + break; + + case 0x00: // bad byte, but keep going and see what happens + break; + default: + status = STATUS_FORMAT_ERROR; + } + } + } + + protected void readGraphicControlExt() { + read(); // block size + int packed = read(); // packed fields + dispose = (packed & 0x1c) >> 2; // disposal method + if (dispose == 0) { + dispose = 1; // elect to keep old image if discretionary + } + transparency = (packed & 1) != 0; + delay = readShort() * 10; // delay in milliseconds + transIndex = read(); // transparent color index + read(); // block terminator + } + + // to get Stream - Head + protected void readHeader() { + String id = ""; + for (int i = 0; i < 6; i++) { + id += (char) read(); + } + if (!id.startsWith("GIF")) { + status = STATUS_FORMAT_ERROR; + return; + } + readLSD(); + if (gctFlag && !err()) { + gct = readColorTable(gctSize); + bgColor = gct[bgIndex]; + } + } + + protected void readImage() { + // offset of X + ix = readShort(); // (sub)image position & size + // offset of Y + iy = readShort(); + // width of bitmap + iw = readShort(); + // height of bitmap + ih = readShort(); + + // Local Color Table Flag + int packed = read(); + lctFlag = (packed & 0x80) != 0; // 1 - local color table flag + + // Interlace Flag, to array with interwoven if ENABLE, with order + // otherwise + interlace = (packed & 0x40) != 0; // 2 - interlace flag + // 3 - sort flag + // 4-5 - reserved + lctSize = 2 << (packed & 7); // 6-8 - local color table size + if (lctFlag) { + lct = readColorTable(lctSize); // read table + act = lct; // make local table active + } else { + act = gct; // make global table active + if (bgIndex == transIndex) { + bgColor = 0; + } + } + int save = 0; + if (transparency) { + save = act[transIndex]; + act[transIndex] = 0; // set transparent color if specified + } + if (act == null) { + status = STATUS_FORMAT_ERROR; // no color table defined + } + if (err()) { + return; + } + decodeImageData(); // decode pixel data + skip(); + if (err()) { + return; + } + frameCount++; + // create new image to receive frame data + image = Bitmap.createBitmap(width, height, Config.ARGB_4444); + // createImage(width, height); + setPixels(); // transfer pixel data to image + frames.addElement(new GifFrame(image, delay)); // add image to frame + // list + if (transparency) { + act[transIndex] = save; + } + resetFrame(); + } + + // Logical Screen Descriptor + protected void readLSD() { + // logical screen size + width = readShort(); + height = readShort(); + // packed fields + int packed = read(); + gctFlag = (packed & 0x80) != 0; // 1 : global color table flag + // 2-4 : color resolution + // 5 : gct sort flag + gctSize = 2 << (packed & 7); // 6-8 : gct size + bgIndex = read(); // background color index + pixelAspect = read(); // pixel aspect ratio + } + + protected void readNetscapeExt() { + do { + readBlock(); + if (block[0] == 1) { + // loop count sub-block + int b1 = ((int) block[1]) & 0xff; + int b2 = ((int) block[2]) & 0xff; + loopCount = (b2 << 8) | b1; + } + } while ((blockSize > 0) && !err()); + } + + // read 8 bit data + protected int readShort() { + // read 16-bit value, LSB first + return read() | (read() << 8); + } + + protected void resetFrame() { + lastDispose = dispose; + lrx = ix; + lry = iy; + lrw = iw; + lrh = ih; + lastImage = image; + lastBgColor = bgColor; + dispose = 0; + transparency = false; + delay = 0; + lct = null; + } + + /** + * Skips variable length blocks up to and including next zero length block. + */ + protected void skip() { + do { + readBlock(); + } while ((blockSize > 0) && !err()); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/gift/util/ExpressionUtil.java b/app/src/main/java/com/chwl/app/ui/gift/util/ExpressionUtil.java new file mode 100644 index 0000000..a88975b --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/gift/util/ExpressionUtil.java @@ -0,0 +1,261 @@ +package com.chwl.app.ui.gift.util; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.style.ImageSpan; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.chwl.app.R; +import com.chwl.app.ui.gift.adapter.FaceGVAdapter; +import com.chwl.app.ui.gift.gif.AnimatedGifDrawable; +import com.chwl.app.ui.gift.gif.AnimatedImageSpan; +import com.chwl.app.ui.gift.widget.GiftDataInfo; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class ExpressionUtil { + public static String ASSETS_ROOT = "p/"; + public static String ASSETS_GIF_ROOT = "g/"; + private boolean isNetData = false;//是否来自网络数据 + + public ExpressionUtil(){ + + } + + public ExpressionUtil(boolean isNetData){ + this.isNetData = isNetData; + } + + /** + * 从静态图找到对应的动态图,为了方便此处我动态图和静态图名称保持一致 + * + * @param mContext + * @param gifTextView + * @param content + * @return + */ + public SpannableStringBuilder prase(Context mContext, final TextView gifTextView, String content) { + SpannableStringBuilder sb = new SpannableStringBuilder(content); + String regex = "\\[[^\\]]+\\]"; + Pattern p = Pattern.compile(regex); + Matcher m = p.matcher(content); + while (m.find()) { + String tempText = m.group(); + try { + String num = tempText.substring(("[" + ASSETS_ROOT).length(), tempText.length() - ".png]".length()); + String gif = ASSETS_GIF_ROOT + num + ".gif"; + /** + * 如果open这里不抛异常说明存在gif,则显示对应的gif + * 否则说明gif找不到,则显示png\\[[^\\]]+\\] + * */ + InputStream is = mContext.getAssets().open(gif); + sb.setSpan( + new AnimatedImageSpan( + new AnimatedGifDrawable(is, new AnimatedGifDrawable.UpdateListener() { + @Override + public void update() { + gifTextView.postInvalidate(); + } + })), + m.start(), + m.end(), + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + is.close(); + } catch (Exception e) {//没找到对应的GIF,显示静态图 + String png = tempText.substring("[".length(), tempText.length() - "]".length()); + try { + sb.setSpan( + new ImageSpan(mContext, BitmapFactory.decodeStream(mContext.getAssets().open(png))), + m.start(), + m.end(), + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + } catch (IOException e1) { + e1.printStackTrace(); + } + e.printStackTrace(); + } + } + return sb; + } + + public SpannableStringBuilder getFace(Context mContext, String content) { + SpannableStringBuilder sb = new SpannableStringBuilder(); + try { + /** + * 经过测试,虽然这里tempText被替换为png显示,但是但我单击发送按钮时,获取到輸入框的内容是tempText的值而不是png + * 所以这里对这个tempText值做特殊处理 + * 格式:[face/png/f_static_000.png],以方便判斷當前圖片是哪一個 + * */ + String tempText = "[" + content + "]"; + sb.append(tempText); + sb.setSpan( + new ImageSpan(mContext, BitmapFactory.decodeStream(mContext.getAssets().open(content))), + sb.length() - tempText.length(), + sb.length(), + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + + } catch (Exception e) { + e.printStackTrace(); + } + + return sb; + } + + public void setView(Context mContext, final View view, String content) { + if (view != null && view instanceof ImageView) {//图片不显示GIF + Bitmap bitmap = null; + try { + bitmap = BitmapFactory.decodeStream(mContext.getAssets().open(content)); + } catch (IOException e1) { + e1.printStackTrace(); + } + ((ImageView) view).setImageBitmap(bitmap); + } else if (view != null && view instanceof TextView) {//文字可显示GIF + TextView gifTextView = (TextView) view; + String tempText = "[" + content + "]"; + SpannableStringBuilder sb = prase(mContext, gifTextView, tempText); + gifTextView.setText(sb); + } + + } + + /** + * 横屏时显示 + * @param context + * @param recyclerView + *@param staticGiftsList @return + */ + public void giftView(final Context context, RecyclerView recyclerView, List staticGiftsList) { + LinearLayoutManager layoutManager = new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false); + recyclerView.setLayoutManager(layoutManager); + + final FaceGVAdapter mGvAdapter = new FaceGVAdapter(recyclerView, staticGiftsList, context, isNetData); + recyclerView.setAdapter(mGvAdapter); + + // 单击表情执行的操作 + mGvAdapter.setOnItemClickListener(new FaceGVAdapter.OnItemClickListener() { + @Override + public void onItemClick(View view, GiftDataInfo giftDataInfo, int position) { + try { + String giftPic = giftDataInfo.getGiftPic(); + String giftName = giftDataInfo.getGiftName(); + String giftPrice = giftDataInfo.getGiftPrice(); +// mGvAdapter.setSeclection(position); +// mGvAdapter.notifyDataSetChanged(); + if (giftClickListener != null) { + giftClickListener.onClick(position, giftPic, giftName, giftPrice); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + + /** + * 竖屏时显示,每一页的数据 + * + * @param context + * @param position 第几页 + * @param staticGiftsList 表情集合 + * @param columns 列数 + * @param rows 行数 + * @param showView View + * @return + */ + public View viewPagerItem(final Context context, int position, List staticGiftsList, int columns, int rows, final View showView) { + LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View layout = inflater.inflate(R.layout.face_gridview, null);//表情布局 + + RecyclerView recyclerView = (RecyclerView) layout.findViewById(R.id.chart_face_gv); + GridLayoutManager girdLayoutManager = new GridLayoutManager(context, columns); + recyclerView.setLayoutManager(girdLayoutManager); + + List subList = new ArrayList<>(); + subList.addAll(staticGiftsList + .subList(position * (columns * rows - 0), + (columns * rows - 0) * (position + 1) > staticGiftsList + .size() ? staticGiftsList.size() : (columns * rows - 0) + * (position + 1))); + + final FaceGVAdapter mGvAdapter = new FaceGVAdapter(recyclerView, subList, context, isNetData); + recyclerView.setAdapter(mGvAdapter); + // 单击表情执行的操作 + mGvAdapter.setOnItemClickListener(new FaceGVAdapter.OnItemClickListener() { + @Override + public void onItemClick(View view, GiftDataInfo giftDataInfo, int position) { + try { + String giftPic = giftDataInfo.getGiftPic(); + String pngStr = giftDataInfo.getGiftName(); + String giftPrice = giftDataInfo.getGiftPrice(); + setView(context, showView, pngStr); +// mGvAdapter.setSeclection(position); +// mGvAdapter.notifyDataSetChanged(); + if (giftClickListener != null) { + giftClickListener.onClick(position, giftPic, pngStr, giftPrice); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + + return recyclerView; + } + + public interface GiftClickListener { + void onClick(int position, String giftPic, String giftName, String giftPrice); + } + + private GiftClickListener giftClickListener; + + public void setGiftClickListener(GiftClickListener listener) { + giftClickListener = listener; + } + + /** + * 根据表情数量以及GridView设置的行数和列数计算Pager数量 + * + * @return + */ + public int getPagerCount(int listSize, int columns, int rows) { + return listSize % (columns * rows - 0) == 0 ? listSize / (columns * rows - 0) : listSize / (columns * rows - 0) + 1; + } + + /** + * 初始化表情列表staticGiftsList + */ + public List initStaticGifts(Context context) { + List giftsList = null; + try { + giftsList = new ArrayList<>(); + GiftDataInfo giftDataInfo; + String[] gifts = context.getAssets().list(ASSETS_ROOT.substring(0, ASSETS_ROOT.length() - 1)); + //将Assets中的表情名称转为字符串一一添加进staticGiftsList + for (int i = 0; i < gifts.length; i++) { + giftDataInfo = new GiftDataInfo(); + giftDataInfo.setGiftName(ASSETS_ROOT + gifts[i]).setGiftPic("").setGiftPrice(i + 1 + ""); + giftsList.add(giftDataInfo); + } + } catch (Exception e) { + e.printStackTrace(); + } + return giftsList; + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/gift/util/GiftPanelControl.java b/app/src/main/java/com/chwl/app/ui/gift/util/GiftPanelControl.java new file mode 100644 index 0000000..b771416 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/gift/util/GiftPanelControl.java @@ -0,0 +1,220 @@ +package com.chwl.app.ui.gift.util; + +import static android.content.Context.LAYOUT_INFLATER_SERVICE; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ImageView; +import android.widget.LinearLayout; + +import androidx.recyclerview.widget.RecyclerView; +import androidx.viewpager.widget.ViewPager; + +import com.chwl.app.R; +import com.chwl.app.ui.gift.adapter.FaceGVAdapter; +import com.chwl.app.ui.gift.adapter.FaceVPAdapter; +import com.chwl.app.ui.gift.widget.GiftDataInfo; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by KathLine on 2017/1/12. + */ + +public class GiftPanelControl { + + private int columns = 6; + private int rows = 4; + //每页显示的表情view + private List views = new ArrayList<>(); + private RecyclerView mRecyclerView; + private ExpressionUtil expressionUtil; + private LayoutInflater inflater; + private List mDatas; + private Context mContext; + private LinearLayout mDotsLayout; + private ViewPager mViewpager; + + public interface GiftListener { + void getGiftInfo(String giftPic, String giftName, String giftPrice); + } + + private GiftListener giftListener; + + public void setGiftListener(GiftListener listener) { + giftListener = listener; + } + + /** + * @param context + * @param viewPager 竖屏礼物面板的ViewPager + * @param recyclerView 横屏礼物面板的RecycleView + * @param dotsLayout 竖屏礼物面板的小圆点父布局 + */ + public GiftPanelControl(Context context, ViewPager viewPager, RecyclerView recyclerView, LinearLayout dotsLayout) { + mContext = context; + inflater = (LayoutInflater) context.getSystemService(LAYOUT_INFLATER_SERVICE); + mViewpager = viewPager; + mRecyclerView = recyclerView; + mDotsLayout = dotsLayout; +// init(); + } + + /** + * + * @param datas datas为null时加载本地礼物图片 + */ + public void init(List datas) { + mDatas = datas; + initPortraitGift(); + intitLandscapeGift(); + } + + /** + * 初始化礼物面板,横屏时显示 + */ + private void intitLandscapeGift() { + if (expressionUtil == null) { + expressionUtil = new ExpressionUtil(mDatas != null); + } + if (mDatas == null) { + mDatas = expressionUtil.initStaticGifts(mContext); + } + + expressionUtil.giftView(mContext, mRecyclerView, mDatas); + } + + /** + * 初始化礼物面板,竖屏时显示 + */ + private void initPortraitGift() { + if (expressionUtil == null) { + expressionUtil = new ExpressionUtil(mDatas != null); + } + if (mDatas == null) { + mDatas = expressionUtil.initStaticGifts(mContext); + } + int pagesize = expressionUtil.getPagerCount(mDatas.size(), columns, rows); + // 获取页数 + for (int i = 0; i < pagesize; i++) { + views.add(expressionUtil.viewPagerItem(mContext, i, mDatas, columns, rows, null)); + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(16, 16); + params.setMargins(10, 0, 10, 0); + if (pagesize > 1) { + mDotsLayout.addView(dotsItem(i), params); + } + } + if (pagesize > 1) { + mDotsLayout.setVisibility(View.VISIBLE); + } else { + mDotsLayout.setVisibility(View.GONE); + } + FaceVPAdapter mVpAdapter = new FaceVPAdapter(views); + mViewpager.setAdapter(mVpAdapter); + mViewpager.setOnPageChangeListener(new PageChangeListener()); + mViewpager.setCurrentItem(0); + if (pagesize > 1) { + mDotsLayout.getChildAt(0).setSelected(true); + } + + expressionUtil.setGiftClickListener(new ExpressionUtil.GiftClickListener() { + @Override + public void onClick(int position, String giftPic, String giftName, String giftPrice) { + if (giftListener != null) { + giftListener.getGiftInfo(giftPic, giftName, giftPrice); + } + } + }); + } + + /** + * 表情页切换时,底部小圆点 + * + * @param position + * @return + */ + private ImageView dotsItem(int position) { + View layout = inflater.inflate(R.layout.dot_image, null); + ImageView iv = (ImageView) layout.findViewById(R.id.face_dot); + iv.setId(position); + return iv; + } + + private boolean isScrolling = false; + private boolean left = false;//从右向左,positionOffset值逐渐增大 + private boolean right = false;//从左向右,positionOffset值逐渐减小 + private int lastValue = -1; + private boolean isClearStatus = true;//是否清除礼物选中的状态在切换页面时 + + /** + * 是否清除礼物选中的状态在切换页面时 + * @param isClearStatus + */ + public void isClearStatus(boolean isClearStatus){ + this.isClearStatus = isClearStatus; + } + + /** + * 表情页改变时,dots效果也要跟着改变 + */ + class PageChangeListener implements ViewPager.OnPageChangeListener { + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + //这里的position是当前屏幕可见页面的第一个页面 + if (isScrolling) { + if (lastValue > positionOffsetPixels) { + //递减,向右滑动 + right = true; + left = false; + } else if (lastValue < positionOffsetPixels) { + //递增,向左滑动 + right = false; + left = true; + } else if (lastValue == positionOffsetPixels) { + right = left = false; + } + } +// Log.i("CustormViewPager", "onPageScrolled: positionOffset =>" + positionOffset + "; positionOffsetPixels =>" + positionOffsetPixels); +// Log.i("CustormViewPager", "onPageScrolled: right =>" + right + "; left =>" + left); + lastValue = positionOffsetPixels; + } + + @Override + public void onPageSelected(int position) { + for (int i = 0; i < mDotsLayout.getChildCount(); i++) { + mDotsLayout.getChildAt(i).setSelected(false); + } + mDotsLayout.getChildAt(position).setSelected(true); + for (int i = 0; i < views.size(); i++) {//清除选中,当礼物页面切换到另一个礼物页面 + RecyclerView view = (RecyclerView) views.get(i); + FaceGVAdapter adapter = (FaceGVAdapter) view.getAdapter(); + if (isClearStatus){ + adapter.clearSelection(); + if (giftListener != null) { + giftListener.getGiftInfo("", "", ""); + } + } + + } + } + + @Override + public void onPageScrollStateChanged(int state) { + //ViewPager.SCROLL_STATE_IDLE 空闲状态 0;CustormViewPager.SCROLL_STATE_DRAGGING 正在滑动 1 + //ViewPager.SCROLL_STATE_SETTLING 滑动完毕 2;页面开始滑动时,状态变化(1,2,0) + if (state == ViewPager.SCROLL_STATE_DRAGGING) { + isScrolling = true; + } else { + isScrolling = false; + } + if (state == ViewPager.SCROLL_STATE_SETTLING) { +// Log.i("CustormViewPager", "----------------right =>" + right + "; left =>" + left + "----------------------------"); + right = left = false; +// lastValue = -1; + } + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/gift/util/GlideCacheUtil.java b/app/src/main/java/com/chwl/app/ui/gift/util/GlideCacheUtil.java new file mode 100644 index 0000000..3ab6a0d --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/gift/util/GlideCacheUtil.java @@ -0,0 +1,175 @@ +package com.chwl.app.ui.gift.util; + +import android.content.Context; +import android.os.Looper; +import android.text.TextUtils; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.load.engine.cache.ExternalCacheDiskCacheFactory; +import com.bumptech.glide.load.engine.cache.InternalCacheDiskCacheFactory; + +import java.io.File; +import java.math.BigDecimal; + +/** + * Glide缓存工具类 + * Created by KathLine on 2017/4/27. + */ + +public class GlideCacheUtil { + private static GlideCacheUtil inst; + + public static GlideCacheUtil getInstance() { + if (inst == null) { + inst = new GlideCacheUtil(); + } + return inst; + } + + /** + * 清除图片磁盘缓存 + */ + public void clearImageDiskCache(final Context context) { + try { + if (Looper.myLooper() == Looper.getMainLooper()) { + new Thread(new Runnable() { + @Override + public void run() { + Glide.get(context).clearDiskCache(); + } + }).start(); + } else { + Glide.get(context).clearDiskCache(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 清除图片内存缓存 + */ + public void clearImageMemoryCache(Context context) { + try { + if (Looper.myLooper() == Looper.getMainLooper()) { //只能在主线程执行 + Glide.get(context).clearMemory(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 清除图片所有缓存 + */ + public void clearImageAllCache(Context context) { + clearImageDiskCache(context); + clearImageMemoryCache(context); + String ImageExternalCatchDir = context.getExternalCacheDir() + ExternalCacheDiskCacheFactory.DEFAULT_DISK_CACHE_DIR; + deleteFolderFile(ImageExternalCatchDir, true); + } + + /** + * 获取Glide造成的缓存大小 + * + * @return CacheSize + */ + public String getCacheSize(Context context) { + try { + return getFormatSize(getFolderSize(new File(context.getCacheDir() + "/" + InternalCacheDiskCacheFactory.DEFAULT_DISK_CACHE_DIR))); + } catch (Exception e) { + e.printStackTrace(); + } + return ""; + } + + /** + * 获取指定文件夹内所有文件大小的和 + * + * @param file file + * @return size + * @throws Exception + */ + private long getFolderSize(File file) throws Exception { + long size = 0; + try { + File[] fileList = file.listFiles(); + for (File aFileList : fileList) { + if (aFileList.isDirectory()) { + size = size + getFolderSize(aFileList); + } else { + size = size + aFileList.length(); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return size; + } + + /** + * 删除指定目录下的文件,这里用于缓存的删除 + * + * @param filePath filePath + * @param deleteThisPath deleteThisPath + */ + private void deleteFolderFile(String filePath, boolean deleteThisPath) { + if (!TextUtils.isEmpty(filePath)) { + try { + File file = new File(filePath); + if (file.isDirectory()) { + File files[] = file.listFiles(); + for (File file1 : files) { + deleteFolderFile(file1.getAbsolutePath(), true); + } + } + if (deleteThisPath) { + if (!file.isDirectory()) { + file.delete(); + } else { + if (file.listFiles().length == 0) { + file.delete(); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + /** + * 格式化单位 + * + * @param size size + * @return size + */ + private static String getFormatSize(double size) { + + double kiloByte = size / 1024; + if (kiloByte < 1) { + return size + "Byte"; + } + + double megaByte = kiloByte / 1024; + if (megaByte < 1) { + BigDecimal result1 = new BigDecimal(Double.toString(kiloByte)); + return result1.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "KB"; + } + + double gigaByte = megaByte / 1024; + if (gigaByte < 1) { + BigDecimal result2 = new BigDecimal(Double.toString(megaByte)); + return result2.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "MB"; + } + + double teraBytes = gigaByte / 1024; + if (teraBytes < 1) { + BigDecimal result3 = new BigDecimal(Double.toString(gigaByte)); + return result3.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "GB"; + } + BigDecimal result4 = new BigDecimal(teraBytes); + + return result4.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "TB"; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/gift/util/RecyclerViewUtil.java b/app/src/main/java/com/chwl/app/ui/gift/util/RecyclerViewUtil.java new file mode 100644 index 0000000..4549cbd --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/gift/util/RecyclerViewUtil.java @@ -0,0 +1,86 @@ +package com.chwl.app.ui.gift.util; + +import android.content.Context; +import android.view.GestureDetector; +import android.view.MotionEvent; +import android.view.View; + +import androidx.recyclerview.widget.RecyclerView; + +/** + * Created by KathLine on 2017/4/27. + */ + +public class RecyclerViewUtil { + private RecyclerView mRecyclerView = null; + private GestureDetector mGestureDetector = null; + private RecyclerView.SimpleOnItemTouchListener mSimpleOnItemTouchListener; + private OnItemClickListener mOnItemClickListener = null; + private OnItemLongClickListener mOnItemLongClickListener = null; + private Context context; + + public RecyclerViewUtil(Context context, RecyclerView recyclerView) { + this.context = context; + this.mRecyclerView = recyclerView; + + mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { + //长按事件 + @Override + public void onLongPress(MotionEvent e) { + super.onLongPress(e); + if (mOnItemLongClickListener != null) { + View childView = mRecyclerView.findChildViewUnder(e.getX(), e.getY()); + if (childView != null) { + int position = mRecyclerView.getChildLayoutPosition(childView); + mOnItemLongClickListener.onItemLongClick(position, childView); + } + } + } + + //单击事件 + @Override + public boolean onSingleTapUp(MotionEvent e) { + if (mOnItemClickListener != null) { + View childView = mRecyclerView.findChildViewUnder(e.getX(), e.getY()); + if (childView != null) { + int position = mRecyclerView.getChildLayoutPosition(childView); + mOnItemClickListener.onItemClick(position, childView); + return true; + } + } + + return super.onSingleTapUp(e); + } + }); + + mSimpleOnItemTouchListener = new RecyclerView.SimpleOnItemTouchListener() { + @Override + public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { + if (mGestureDetector.onTouchEvent(e)) { + return true; + } + return false; + } + }; + + mRecyclerView.addOnItemTouchListener(mSimpleOnItemTouchListener); + } + + public void setOnItemClickListener(OnItemClickListener l) { + mOnItemClickListener = l; + } + + public void setOnItemLongClickListener(OnItemLongClickListener l) { + mOnItemLongClickListener = l; + } + + //长按事件接口 + public interface OnItemLongClickListener { + void onItemLongClick(int position, View view); + } + + //单击事件接口 + public interface OnItemClickListener { + void onItemClick(int position, View view); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/gift/widget/CustormAnim.java b/app/src/main/java/com/chwl/app/ui/gift/widget/CustormAnim.java new file mode 100644 index 0000000..1b74594 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/gift/widget/CustormAnim.java @@ -0,0 +1,91 @@ +package com.chwl.app.ui.gift.widget; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.animation.PropertyValuesHolder; +import android.view.View; +import android.view.animation.DecelerateInterpolator; + +import androidx.annotation.NonNull; + +import com.chwl.app.R; + +/** + * @author KathLine + * @date 2017/7/7 + */ + +public class CustormAnim implements ICustormAnim { + + @Override + public AnimatorSet startAnim(final GiftFrameLayout giftFrameLayout, View rootView) { + //礼物飞入 + ObjectAnimator flyFromLtoR2 = GiftAnimationUtil.createFlyFromLtoR(giftFrameLayout, -300, 0, 200, new DecelerateInterpolator()); + flyFromLtoR2.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + giftFrameLayout.initLayoutState(); + } + + @Override + public void onAnimationEnd(Animator animation) { + giftFrameLayout.comboAnimation(); + } + }); + AnimatorSet animSet = new AnimatorSet(); + animSet.play(flyFromLtoR2); + animSet.start(); + return animSet; + } + + @Override + public AnimatorSet comboAnim(final GiftFrameLayout giftFrameLayout, View rootView) { + final StrokeTextView anim_num = (StrokeTextView) rootView.findViewById(R.id.animation_num); + //数量增加 + ObjectAnimator scaleGiftNum = GiftAnimationUtil.scaleGiftNum(anim_num); + scaleGiftNum.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + anim_num.setVisibility(View.VISIBLE); + } + + @Override + public void onAnimationEnd(Animator animation) { + giftFrameLayout.comboEndAnim();//这里一定要回调该方法,不然连击不会生效 + } + }); + scaleGiftNum.start(); + return null; + } + + @Override + public AnimatorSet endAnim(final GiftFrameLayout giftFrameLayout, View rootView) { + return testAnim(giftFrameLayout); + } + + @NonNull + private AnimatorSet testAnim(GiftFrameLayout giftFrameLayout) { + PropertyValuesHolder translationY = PropertyValuesHolder.ofFloat("translationY", 0, -50); + PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 1.0f, 0.5f); + ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(giftFrameLayout, translationY, alpha); + animator.setStartDelay(0); + animator.setDuration(1500); + + translationY = PropertyValuesHolder.ofFloat("translationY", -50, -100); + alpha = PropertyValuesHolder.ofFloat("alpha", 0.5f, 0f); + ObjectAnimator animator1 = ObjectAnimator.ofPropertyValuesHolder(giftFrameLayout, translationY, alpha); + animator1.setStartDelay(0); + animator1.setDuration(1500); + + // 复原 + ObjectAnimator fadeAnimator2 = GiftAnimationUtil.createFadeAnimator(giftFrameLayout, 0, 0, 0, 0); + + AnimatorSet animatorSet = new AnimatorSet(); + animatorSet.play(animator1).after(animator); + animatorSet.play(fadeAnimator2).after(animator1); + animatorSet.start(); + return animatorSet; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/gift/widget/GiftAnimationUtil.java b/app/src/main/java/com/chwl/app/ui/gift/widget/GiftAnimationUtil.java new file mode 100644 index 0000000..ff69ed3 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/gift/widget/GiftAnimationUtil.java @@ -0,0 +1,127 @@ +package com.chwl.app.ui.gift.widget; + +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.animation.PropertyValuesHolder; +import android.animation.TimeInterpolator; +import android.graphics.drawable.AnimationDrawable; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +/** + * Created by KathLine on 2017/1/8. + */ +public class GiftAnimationUtil { + + + /** + * @param target + * @param star 动画起始坐标 + * @param end 动画终止坐标 + * @param duration 持续时间 + * @return 创建一个从左到右的飞入动画 + * 礼物飞入动画 + */ + public static ObjectAnimator createFlyFromLtoR(final View target, float star, float end, int duration, TimeInterpolator interpolator) { + //1.个人信息先飞出来 + ObjectAnimator anim1 = ObjectAnimator.ofFloat(target, "translationX", + star, end); + anim1.setInterpolator(interpolator); + anim1.setDuration(duration); + return anim1; + } + + + /** + * @param target + * @return 播放帧动画 + */ + public static AnimationDrawable startAnimationDrawable(ImageView target) { + AnimationDrawable animationDrawable = (AnimationDrawable) target.getDrawable(); + if (animationDrawable != null) { + target.setVisibility(View.VISIBLE); + animationDrawable.start(); + } + return animationDrawable; + } + + + /** + * @param target + * @param drawable 设置帧动画 + */ + public static void setAnimationDrawable(ImageView target, AnimationDrawable drawable) { + + target.setBackground(drawable); + } + + + /** + * @param target + * @return 送礼数字变化 + */ + public static ObjectAnimator scaleGiftNum(final TextView target) { + PropertyValuesHolder anim4 = PropertyValuesHolder.ofFloat("scaleX", + 1.2f, 0.8f, 1f); + PropertyValuesHolder anim5 = PropertyValuesHolder.ofFloat("scaleY", + 1.2f, 0.8f, 1f); + PropertyValuesHolder anim6 = PropertyValuesHolder.ofFloat("alpha", + 1.0f, 0f, 1f); + ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(target, anim4, anim5, anim6).setDuration(400); + return animator; + + } + + + /** + * @param target + * @param star + * @param end + * @param duration + * @param startDelay + * @return 向上飞 淡出 + */ + public static ObjectAnimator createFadeAnimator(final View target, float star, float end, int duration, int startDelay) { + + PropertyValuesHolder translationY = PropertyValuesHolder.ofFloat("translationY", star, end); + PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 1.0f, 0f); + ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(target, translationY, alpha); + animator.setStartDelay(startDelay); + animator.setDuration(duration); + return animator; + } + + /** + * @param animator1 + * @param animator2 + * @return 按顺序播放动画 + */ + public static AnimatorSet startAnimation(ObjectAnimator animator1, ObjectAnimator animator2) { + AnimatorSet animSet = new AnimatorSet(); +// animSet.playSequentially(animators); + animSet.play(animator1).before(animator2); + animSet.start(); + return animSet; + } + + /** + * @param animator1 + * @param animator2 + * @param animator3 + * @param animator4 + * @param animator5 + * @return 按顺序播放动画 + */ + public static AnimatorSet startAnimation(ObjectAnimator animator1, ObjectAnimator animator2, ObjectAnimator animator3, ObjectAnimator animator4, ObjectAnimator animator5) { + AnimatorSet animSet = new AnimatorSet(); +// animSet.playSequentially(animators); + animSet.play(animator1).before(animator2); + animSet.play(animator3).after(animator2); + animSet.play(animator4).after(animator3); + animSet.play(animator5).after(animator4); + animSet.start(); + return animSet; + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/gift/widget/GiftControl.java b/app/src/main/java/com/chwl/app/ui/gift/widget/GiftControl.java new file mode 100644 index 0000000..4c693d2 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/gift/widget/GiftControl.java @@ -0,0 +1,282 @@ +package com.chwl.app.ui.gift.widget; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.util.Log; +import android.util.SparseArray; + +import androidx.annotation.NonNull; + +import com.chwl.app.R; +import com.chwl.library.utils.ResUtil; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * Created by KathLine on 2017/1/8. + */ + +public class GiftControl implements GiftFrameLayout.LeftGiftAnimationStatusListener { + + private static final String TAG = "GiftControl"; + /** + * 自定义动画 + */ + private ICustormAnim custormAnim; + /** + * 礼物队列 + */ + private ArrayList mGiftQueue; + + /** + * 礼物数量集合 + */ + private SparseArray mGiftLayoutList; + + public GiftControl() { + mGiftQueue = new ArrayList<>(); + } + + public GiftControl setCustormAnim(ICustormAnim anim){ + custormAnim = anim; + + return this; + } + + public GiftControl setGiftLayout(boolean isHideMode, @NonNull SparseArray giftLayoutList){ + mGiftLayoutList = giftLayoutList; + GiftFrameLayout giftFrameLayout; + for (int i = 0; i < mGiftLayoutList.size(); i++) { + giftFrameLayout = mGiftLayoutList.get(i); + giftFrameLayout.setIndex(i); + giftFrameLayout.firstHideLayout(); + giftFrameLayout.setGiftAnimationListener(this); + giftFrameLayout.setHideMode(isHideMode); + } + return this; + } + + public void loadGift(GiftDataInfo gift) { + loadGift(gift, true); + } + + /** + * 加入礼物,具有实时连击效果 + * + * @param gift + * @param supportCombo 是否支持实时连击,如果为true:支持,否则不支持 + */ + public void loadGift(GiftDataInfo gift, boolean supportCombo) { + if (mGiftQueue != null) { + if (supportCombo) { + GiftFrameLayout giftFrameLayout; + for (int i = 0; i < mGiftLayoutList.size(); i++) { + giftFrameLayout = mGiftLayoutList.get(i); + if(giftFrameLayout.isShowing()){ + if (giftFrameLayout.getCurrentGiftId().equals(gift.getGiftId()) + && giftFrameLayout.getCurrentSendUserId().equals(gift.getSendUserId()) + && giftFrameLayout.getCurrentGiftGroup() == gift.getGiftGroup()) { + //连击 + Log.i(TAG, "addGiftQueue: ========giftFrameLayout("+ giftFrameLayout.getIndex()+ResUtil.getString(R.string.gift_widget_giftcontrol_01) + gift.getGiftId() + ResUtil.getString(R.string.gift_widget_giftcontrol_02) + gift.getGiftCount()); + giftFrameLayout.setGiftCount(gift.getGiftCount()); + giftFrameLayout.setSendGiftTime(gift.getSendGiftTime()); + return; + } + } + } + } + + addGiftQueue(gift, supportCombo); + } + } + + private void addGiftQueue(final GiftDataInfo gift, final boolean supportCombo) { + if (mGiftQueue != null) { + if (mGiftQueue.size() == 0) { + Log.d(TAG, ResUtil.getString(R.string.gift_widget_giftcontrol_03) + mGiftQueue.size() + ResUtil.getString(R.string.gift_widget_giftcontrol_04) + gift.getGiftId()); + mGiftQueue.add(gift); + showGift(); + return; + } + } + Log.d(TAG, ResUtil.getString(R.string.gift_widget_giftcontrol_05) + mGiftQueue.size() + ResUtil.getString(R.string.gift_widget_giftcontrol_06) + gift.getGiftId()); + if (supportCombo) { + boolean addflag = false; + for (GiftDataInfo model : mGiftQueue) { + if (model.getGiftId().equals(gift.getGiftId()) && model.getSendUserId().equals(gift.getSendUserId()) && model.getGiftGroup() == gift.getGiftGroup()) { + Log.d(TAG, ResUtil.getString(R.string.gift_widget_giftcontrol_07) + gift.getGiftId() + ResUtil.getString(R.string.gift_widget_giftcontrol_08) + gift.getGiftCount()); + model.setGiftCount(model.getGiftCount() + gift.getGiftCount()); + addflag = true; + break; + } + } + //如果在现有的集合中不存在同一人发的礼物就加入到现有集合中 + if (!addflag) { + Log.d(TAG, ResUtil.getString(R.string.gift_widget_giftcontrol_09) + gift.getGiftId() + ResUtil.getString(R.string.gift_widget_giftcontrol_010) + gift.getGiftCount()); + mGiftQueue.add(gift); + } + } else { + mGiftQueue.add(gift); + } + + } + + /** + * 显示礼物 + */ + public synchronized void showGift() { + if (isEmpty()) { + return; + } + GiftFrameLayout giftFrameLayout; + for (int i = 0; i < mGiftLayoutList.size(); i++) { + giftFrameLayout = mGiftLayoutList.get(i); + Log.d(TAG, ResUtil.getString(R.string.gift_widget_giftcontrol_011) + mGiftQueue.size()); + if (!giftFrameLayout.isShowing() && giftFrameLayout.isEnd()) { + boolean hasGift = giftFrameLayout.setGift(getGift()); + if (hasGift) { + giftFrameLayout.startAnimation(custormAnim); + } + } + Log.d(TAG, ResUtil.getString(R.string.gift_widget_giftcontrol_012) + mGiftQueue.size()); + } + } + + /** + * 取出礼物 + * + * @return + */ + private synchronized GiftDataInfo getGift() { + GiftDataInfo gift = null; + if (mGiftQueue.size() != 0) { + gift = mGiftQueue.get(0); + mGiftQueue.remove(0); + Log.i(TAG, ResUtil.getString(R.string.gift_widget_giftcontrol_013) + mGiftQueue.size() + ResUtil.getString(R.string.gift_widget_giftcontrol_014) + gift.getGiftId() + ResUtil.getString(R.string.gift_widget_giftcontrol_015) + gift.getGiftCount()); + } + return gift; + } + + /** + * 通过获取giftId和getSendUserId当前用户giftId礼物总数 + * @param giftId + * @param userId + * @return + */ + public int getCurGiftCountByUserId(String giftId, String userId) { + int curGiftCount = 0; + GiftFrameLayout giftFrameLayout; + GiftDataInfo giftDataInfo; + for (int i = 0; i < mGiftLayoutList.size(); i++) { + giftFrameLayout = mGiftLayoutList.get(i); + giftDataInfo = giftFrameLayout.getGift(); + if (giftDataInfo != null && giftDataInfo.getGiftId().equals(giftId) && giftDataInfo.getSendUserId().equals(userId)) { + curGiftCount = giftDataInfo.getGiftCount(); + } else {//自己的礼物不正在显示,还在队列中 + Iterator iterator = mGiftQueue.iterator(); + while (iterator.hasNext()){ + giftDataInfo = iterator.next(); + if (giftDataInfo.getGiftId().equals(giftId) && giftDataInfo.getSendUserId().equals(userId)) { + curGiftCount = giftDataInfo.getGiftCount(); + break; + } + } + } + } + return curGiftCount; + } + + /** + * 获取正在展示礼物的个数(即GiftFragmeLayout展示的个数) + * @return + */ + public int getShowingGiftLayoutCount(){ + int count = 0; + GiftFrameLayout giftFrameLayout; + for (int i = 0; i < mGiftLayoutList.size(); i++) { + giftFrameLayout = mGiftLayoutList.get(i); + if(giftFrameLayout.isShowing()){ + count++; + } + } + return count; + } + + /** + * 获取正在展示礼物的个数实例(即GiftFragmeLayout展示的个数实例) + * @return + */ + public List getShowingGiftLayouts(){ + List giftLayoutList = new ArrayList<>(); + GiftFrameLayout giftFrameLayout; + for (int i = 0; i < mGiftLayoutList.size(); i++) { + giftFrameLayout = mGiftLayoutList.get(i); + if(giftFrameLayout.isShowing()){ + giftLayoutList.add(giftFrameLayout); + } + } + return giftLayoutList; + } + + @Override + public void dismiss(int index) { + GiftFrameLayout giftFrameLayout; + for (int i = 0; i < mGiftLayoutList.size(); i++) { + giftFrameLayout = mGiftLayoutList.get(i); + if(giftFrameLayout.getIndex() == index){ + reStartAnimation(giftFrameLayout, giftFrameLayout.getIndex()); + } + } + } + + private void reStartAnimation(final GiftFrameLayout giftFrameLayout, final int index) { + //动画结束,这时不能触发连击动画 + giftFrameLayout.setCurrentShowStatus(false); + Log.d(TAG, ResUtil.getString(R.string.gift_widget_giftcontrol_016)); + AnimatorSet animatorSet = giftFrameLayout.endAnmation(custormAnim); + if (animatorSet != null) { + animatorSet.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + Log.i(TAG, ResUtil.getString(R.string.gift_widget_giftcontrol_017) + index); + //动画完全结束 + giftFrameLayout.CurrentEndStatus(true); + giftFrameLayout.setGiftViewEndVisibility(isEmpty()); + showGift(); + } + }); + } + } + + /** + * 清除所有礼物 + */ + public synchronized void cleanAll() { + if (mGiftQueue != null) { + mGiftQueue.clear(); + } + GiftFrameLayout giftFrameLayout; + for (int i = 0; i < mGiftLayoutList.size(); i++) { + giftFrameLayout = mGiftLayoutList.get(i); + if(giftFrameLayout != null){ + giftFrameLayout.clearHandler(); + } + } + } + + /** + * 礼物是否为空 + * + * @return + */ + public synchronized boolean isEmpty() { + if (mGiftQueue == null || mGiftQueue.size() == 0) { + return true; + } else { + return false; + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/gift/widget/GiftDataInfo.java b/app/src/main/java/com/chwl/app/ui/gift/widget/GiftDataInfo.java new file mode 100644 index 0000000..dff9f77 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/gift/widget/GiftDataInfo.java @@ -0,0 +1,131 @@ +package com.chwl.app.ui.gift.widget; + +/** + * Created by KathLine on 2017/1/8. + */ +public class GiftDataInfo { + + private String giftId;//礼物的id + private String giftName;//礼物的名字 + private int giftCount;//一次发送礼物的数量 + private int giftGroup;//组数 + private String giftPic;//礼物的图片 + private String giftPrice;//礼物的价格 + private String sendUserId;//发送者的id + private String sendUserName;//发送者的名字 + private String sendUserPic;//发送者的头像 + private int hitCombo;//上一次要连击的礼物数 + private Long sendGiftTime;//发送礼物的时间 + private boolean currentStart;//是否从当前数开始连击 + + public GiftDataInfo() { + } + + public String getGiftId() { + return giftId; + } + + public GiftDataInfo setGiftId(String giftId) { + this.giftId = giftId; + return this; + } + + public String getGiftName() { + return giftName; + } + + public GiftDataInfo setGiftName(String giftName) { + this.giftName = giftName; + return this; + } + + public int getGiftCount() { + return giftCount; + } + + public GiftDataInfo setGiftCount(int giftCount) { + this.giftCount = giftCount; + return this; + } + + public String getSendUserId() { + return sendUserId; + } + + public GiftDataInfo setSendUserId(String sendUserId) { + this.sendUserId = sendUserId; + return this; + } + + public String getSendUserName() { + return sendUserName; + } + + public GiftDataInfo setSendUserName(String sendUserName) { + this.sendUserName = sendUserName; + return this; + } + + public String getSendUserPic() { + return sendUserPic; + } + + public GiftDataInfo setSendUserPic(String sendUserPic) { + this.sendUserPic = sendUserPic; + return this; + } + + public String getGiftPic() { + return giftPic; + } + + public GiftDataInfo setGiftPic(String giftPic) { + this.giftPic = giftPic; + return this; + } + + public String getGiftPrice() { + return giftPrice; + } + + public GiftDataInfo setGiftPrice(String giftPrice) { + this.giftPrice = giftPrice; + return this; + } + + public int getHitCombo() { + return hitCombo; + } + + public GiftDataInfo setHitCombo(int hitCombo) { + this.hitCombo = hitCombo; + return this; + } + + public Long getSendGiftTime() { + return sendGiftTime; + } + + public GiftDataInfo setSendGiftTime(Long sendGiftTime) { + this.sendGiftTime = sendGiftTime; + return this; + } + + public boolean isCurrentStart() { + return currentStart; + } + + public GiftDataInfo setCurrentStart(boolean currentStart) { + this.currentStart = currentStart; + return this; + } + + public int getGiftGroup() { + return giftGroup; + } + + public GiftDataInfo setGiftGroup(int giftGroup) { + this.giftGroup = giftGroup; + return this; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/gift/widget/GiftFrameLayout.java b/app/src/main/java/com/chwl/app/ui/gift/widget/GiftFrameLayout.java new file mode 100644 index 0000000..5729963 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/gift/widget/GiftFrameLayout.java @@ -0,0 +1,494 @@ +package com.chwl.app.ui.gift.widget; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.Handler; +import android.os.Message; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.util.Log; +import android.view.View; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.OvershootInterpolator; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.bumptech.glide.load.resource.bitmap.CircleCrop; +import com.bumptech.glide.request.target.SimpleTarget; +import com.bumptech.glide.request.transition.Transition; +import com.netease.nim.uikit.support.glide.GlideApp; +import com.chwl.app.R; +import com.chwl.library.utils.config.BasicConfig; + +import java.io.IOException; + + +/** + * Created by KathLine on 2017/1/8. + */ +public class GiftFrameLayout extends RelativeLayout implements Handler.Callback { + + private static final String TAG = "GiftFrameLayout"; + private Handler mHandler = new Handler(this); + private Handler comboHandler = new Handler(this); + private Runnable runnable; + + private static final int RESTART_GIFT_ANIMATION_CODE = 1002; + /** + * 礼物展示时间 + */ + public static final int GIFT_DISMISS_TIME = 1500; + private static final int INTERVAL = 299; + /** + * 当前动画runnable + */ + private Runnable mCurrentAnimRunnable; + + RelativeLayout anim_rl; + ImageView anim_gift, anim_light, anim_header; + TextView anim_nickname, anim_sign; + StrokeTextView anim_num; + TextView giftGroup; + + private GiftDataInfo mGift; + /** + * item 显示位置 + */ + private int mIndex = 1; + /** + * 礼物连击数 + */ + private int mGiftCount; + /** + * 当前播放连击数 + */ + private int mCombo = 1; + /** + * 礼物动画正在显示,在这期间可触发连击效果 + */ + private boolean isShowing = false; + /** + * 礼物动画结束 + */ + private boolean isEnd = true; + /** + * 自定义动画的接口 + */ + private ICustormAnim anim; + /** + * 是否开启礼物动画隐藏模式(如果两个礼物动画同时显示,并且第一个优先结束,第二个礼物的位置会移动到第一个位置上去) + */ + private boolean isHideMode = false; + + private LeftGiftAnimationStatusListener mGiftAnimationListener; + + public GiftFrameLayout(Context context) { + this(context, null); + } + + public GiftFrameLayout(Context context, AttributeSet attrs) { + super(context, attrs); + initView(context); + } + + + private void initView(Context context) { + inflate(context, R.layout.item_gift, this); + anim_rl = (RelativeLayout) findViewById(R.id.infoRl); + anim_gift = (ImageView) findViewById(R.id.giftIv); + anim_light = (ImageView) findViewById(R.id.light); + anim_num = (StrokeTextView) findViewById(R.id.animation_num); + anim_header = (ImageView) findViewById(R.id.headIv); + anim_nickname = (TextView) findViewById(R.id.nickNameTv); + anim_sign = (TextView) findViewById(R.id.infoTv); + giftGroup = (TextView) findViewById(R.id.gift_group); + + } + + public ImageView getAnimGift() { + return anim_gift; + } + + public void firstHideLayout() { + setVisibility(GONE); + } + + public void setHideMode(boolean isHideMode) { + this.isHideMode = isHideMode; + } + + public void hideView() { + anim_gift.setVisibility(INVISIBLE); + anim_light.setVisibility(INVISIBLE); + anim_num.setVisibility(INVISIBLE); + } + + public void setGiftViewEndVisibility(boolean hasGift) { + + if (isHideMode && hasGift) { + GiftFrameLayout.this.setVisibility(View.GONE); + } else { + GiftFrameLayout.this.setVisibility(View.INVISIBLE); + } + } + + public boolean setGift(GiftDataInfo gift) { + if (gift == null) { + return false; + } + mGift = gift; + + if (mGift.isCurrentStart()) { + mGiftCount = gift.getGiftCount() + mGift.getHitCombo(); + } else { + mGiftCount = gift.getGiftCount(); + } + if (!TextUtils.isEmpty(gift.getSendUserName())) { + anim_nickname.setText(gift.getSendUserName()); + } + if (!TextUtils.isEmpty(gift.getGiftId())) { + anim_sign.setText(gift.getGiftName()); + } + return true; + } + + public GiftDataInfo getGift() { + return mGift; + } + + @Override + public boolean handleMessage(Message msg) { + switch (msg.what) { + case RESTART_GIFT_ANIMATION_CODE: + mCombo++; + anim_num.setText("x " + (mCombo)); + comboAnimation(); + removeDismissGiftCallback(); + break; + default: + break; + } + return true; + } + + /** + * 显示完连击数与动画时,关闭此Item Layout,并通知外部隐藏自身(供内部调用) + */ + private void dismissGiftLayout() { + removeDismissGiftCallback(); + if (mGiftAnimationListener != null) { + mGiftAnimationListener.dismiss(mIndex); + } + } + + private void removeDismissGiftCallback() { + stopCheckGiftCount(); + if (mCurrentAnimRunnable != null) { + mHandler.removeCallbacks(mCurrentAnimRunnable); + mCurrentAnimRunnable = null; + } + } + + private class GiftNumAnimaRunnable implements Runnable { + + @Override + public void run() { + dismissGiftLayout(); + } + } + + /** + * 设置item显示位置 + * + * @param mIndex + */ + public void setIndex(int mIndex) { + this.mIndex = mIndex; + } + + /** + * 获取ite显示位置 + * + * @return + */ + public int getIndex() { + Log.i(TAG, "index : " + mIndex); + return mIndex; + } + + public interface LeftGiftAnimationStatusListener { + void dismiss(int index); + } + + public void setGiftAnimationListener(LeftGiftAnimationStatusListener giftAnimationListener) { + this.mGiftAnimationListener = giftAnimationListener; + } + + public boolean isShowing() { + return isShowing; + } + + public void setCurrentShowStatus(boolean status) { + mCombo = 1; + isShowing = status; + } + + public boolean isEnd() { + return isEnd; + } + + public void CurrentEndStatus(boolean isEnd) { + this.isEnd = isEnd; + } + + /** + * 获取当前显示礼物发送人id + * + * @return + */ + public String getCurrentSendUserId() { + if (mGift != null) { + return mGift.getSendUserId(); + } + return null; + } + + /** + * 获取当前显示礼物id + * + * @return + */ + public String getCurrentGiftId() { + if (mGift != null) { + return mGift.getGiftId(); + } + return null; + } + + public int getCurrentGiftGroup() { + if (mGift != null) { + return mGift.getGiftGroup(); + } + return 0; + } + + /** + * 增加礼物数量,用于连击效果 + * + * @param count + */ + public synchronized void setGiftCount(int count) { + mGiftCount += count; + mGift.setGiftCount(mGiftCount); + } + + public int getGiftCount() { + return mGiftCount; + } + + public synchronized void setSendGiftTime(long sendGiftTime) { + mGift.setSendGiftTime(sendGiftTime); + } + + public long getSendGiftTime() { + return mGift.getSendGiftTime(); + } + + /** + *
+     * 这里不能GIFT_DISMISS_TIME % INVISIBLE == 0,
+     * 因为余数为0的话,说明在这个时刻即执行了{@link GiftControl#reStartAnimation(GiftFrameLayout, int)}移除动画{@link #endAnmation(ICustormAnim)},也执行了检查监听连击动作。
+     * 这导致就会出现在礼物动画消失的一瞬间,点击连击会出现如下日志出现的情况(已经触发连击了,但是礼物的动画已经结束了):
+     * 02-18 20:45:57.900 9060-9060/org.dync.livegiftlayout D/GiftControl: addGiftQueue---集合个数:0,礼物:p/000.png
+     * 02-18 20:45:57.900 9060-9060/org.dync.livegiftlayout D/GiftControl: showGift: begin->集合个数:1
+     * 02-18 20:45:57.900 9060-9060/org.dync.livegiftlayout I/GiftControl: getGift---集合个数:0,送出礼物---p/000.png,礼物数X1
+     * 02-18 20:45:57.910 9060-9060/org.dync.livegiftlayout D/GiftControl: showGift: end->集合个数:0
+     * 02-18 20:46:01.910 9060-9060/org.dync.livegiftlayout I/GiftControl: addGiftQueue: ========mFirstItemGift连击========礼物:p/000.png,连击X1
+     * 02-18 20:46:01.970 9060-9060/org.dync.livegiftlayout D/GiftControl: reStartAnimation: 动画结束
+     * 02-18 20:46:02.490 9060-9060/org.dync.livegiftlayout I/GiftControl: 礼物动画dismiss: index = 0
+     *
+     * 
+ */ + private void checkGiftCountSubscribe() { + + runnable = new Runnable() { + @Override + public void run() { + if (mGiftCount > mCombo) { + mHandler.sendEmptyMessage(RESTART_GIFT_ANIMATION_CODE); + } + comboHandler.postDelayed(runnable, INTERVAL); + } + }; + comboHandler.postDelayed(runnable, INTERVAL); + } + + public void stopCheckGiftCount() { + comboHandler.removeCallbacksAndMessages(null); + } + + public void clearHandler() { + mHandler.removeCallbacksAndMessages(null); + mHandler = null;//这里要置位null,否则当前页面销毁时,正在执行的礼物动画会造成内存泄漏 + mGiftAnimationListener = null; + + comboHandler.removeCallbacksAndMessages(null); + comboHandler = null;//这里要置位null,否则当前页面销毁时,正在执行的礼物动画会造成内存泄漏 + } + + /** + * 动画开始时回调,使用方法借鉴{@link #startAnimation} + */ + public void initLayoutState() { + this.setVisibility(View.VISIBLE); + this.setAlpha(1f); + isShowing = true; + isEnd = false; + + if (mGift.getSendUserPic().equals("")) { + GlideApp.with(BasicConfig.INSTANCE.getAppContext()) + .load(R.drawable.default_avatar) + .transform(new CircleCrop()) + .into(anim_header); + } else { + GlideApp.with(BasicConfig.INSTANCE.getAppContext()) + .load(mGift.getSendUserPic()) + .transform(new CircleCrop()) + .into(anim_header); + } + + if (mGift.getGiftGroup() == 1) { + giftGroup.setVisibility(GONE); + } else { + giftGroup.setVisibility(VISIBLE); + giftGroup.setText("X" + mGift.getGiftGroup()); + } + + if (mGift.isCurrentStart()) { + mCombo = mGift.getHitCombo(); + } + anim_num.setText("x " + mCombo); + if (!mGift.getGiftPic().equals("")) { + GlideApp.with(BasicConfig.INSTANCE.getAppContext()) + .load(mGift.getGiftPic()) + .into(new SimpleTarget() { + @Override + public void onResourceReady(Drawable drawable, Transition transition) { + anim_gift.setImageDrawable(drawable); + } + }); + } else { + Bitmap bitmap = null; + try { + bitmap = BitmapFactory.decodeStream(getContext().getAssets().open(mGift.getGiftId())); + + } catch (IOException e1) { + e1.printStackTrace(); + } + anim_gift.setImageDrawable(new BitmapDrawable(bitmap)); +// anim_gift.setImageBitmap(bitmap); + } + } + + /** + * 连击结束时回调 + */ + public void comboEndAnim() { + if (mHandler != null) { + if (mGiftCount > mCombo) {//连击 + mHandler.sendEmptyMessage(RESTART_GIFT_ANIMATION_CODE); + } else { + mCurrentAnimRunnable = new GiftNumAnimaRunnable(); + mHandler.postDelayed(mCurrentAnimRunnable, GIFT_DISMISS_TIME); + checkGiftCountSubscribe(); + } + } + } + + public AnimatorSet startAnimation(ICustormAnim anim) { + this.anim = anim; + if (anim == null) { + hideView(); + //布局飞入 + ObjectAnimator flyFromLtoR = GiftAnimationUtil.createFlyFromLtoR(anim_rl, -getWidth(), 0, 400, new OvershootInterpolator()); + flyFromLtoR.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + super.onAnimationStart(animation); + initLayoutState(); + } + }); + + //礼物飞入 + ObjectAnimator flyFromLtoR2 = GiftAnimationUtil.createFlyFromLtoR(anim_gift, -getWidth(), 0, 400, new DecelerateInterpolator()); + flyFromLtoR2.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + anim_gift.setVisibility(View.VISIBLE); + } + + @Override + public void onAnimationEnd(Animator animation) { + GiftAnimationUtil.startAnimationDrawable(anim_light); + anim_num.setVisibility(View.VISIBLE); + comboAnimation(); + } + }); + AnimatorSet animatorSet = GiftAnimationUtil.startAnimation(flyFromLtoR, flyFromLtoR2); + + return animatorSet; + } else { + return anim.startAnim(this, this); + } + } + + public void comboAnimation() { + if (anim == null) { + //数量增加 + ObjectAnimator scaleGiftNum = GiftAnimationUtil.scaleGiftNum(anim_num); + scaleGiftNum.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + anim_num.setVisibility(View.VISIBLE); + } + + @Override + public void onAnimationEnd(Animator animation) { + comboEndAnim(); + } + }); + scaleGiftNum.start(); + } else { + anim.comboAnim(this, this); + } + } + + public AnimatorSet endAnmation(ICustormAnim anim) { + if (anim == null) { + //向上渐变消失 + ObjectAnimator fadeAnimator = GiftAnimationUtil.createFadeAnimator(GiftFrameLayout.this, 0, -100, 100, 0); + fadeAnimator.addListener(new AnimatorListenerAdapter() { + + @Override + public void onAnimationEnd(Animator animation) { + anim_num.setVisibility(View.INVISIBLE); + } + }); + // 复原 + ObjectAnimator fadeAnimator2 = GiftAnimationUtil.createFadeAnimator(GiftFrameLayout.this, 100, 0, 0, 0); + + AnimatorSet animatorSet = GiftAnimationUtil.startAnimation(fadeAnimator, fadeAnimator2); + return animatorSet; + } else { + return anim.endAnim(this, this); + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/gift/widget/GlideCircleTransform.java b/app/src/main/java/com/chwl/app/ui/gift/widget/GlideCircleTransform.java new file mode 100644 index 0000000..9b6ff10 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/gift/widget/GlideCircleTransform.java @@ -0,0 +1,61 @@ +package com.chwl.app.ui.gift.widget; + +import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.Paint; + +import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; +import com.bumptech.glide.load.resource.bitmap.BitmapTransformation; + +import java.security.MessageDigest; + +/** + * + * + * Created by Skyline on 2016/5/24. + */ +public class GlideCircleTransform extends BitmapTransformation { + public GlideCircleTransform() { + } + + @Override + protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) { + return circleCrop(pool, toTransform); + } + + private static Bitmap circleCrop(BitmapPool pool, Bitmap source) { + if (source == null) return null; + + int size = Math.min(source.getWidth(), source.getHeight()); + int x = (source.getWidth() - size) / 2; + int y = (source.getHeight() - size) / 2; + + // TODO this could be acquired from the pool too + Bitmap squared = Bitmap.createBitmap(source, x, y, size, size); + + Bitmap result = pool.get(size, size, Bitmap.Config.ARGB_8888); + if (result == null) { + result = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); + } + + Canvas canvas = new Canvas(result); + Paint paint = new Paint(); + paint.setShader(new BitmapShader(squared, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP)); + paint.setAntiAlias(true); + float r = size / 2f; + canvas.drawCircle(r, r, r, paint); + return result; + } + +// @Override +// public String getId() { +// return getClass().getName(); +// } + + @Override + public void updateDiskCacheKey(MessageDigest messageDigest) { + messageDigest.update(getClass().getName().getBytes()); + } +} + diff --git a/app/src/main/java/com/chwl/app/ui/gift/widget/ICustormAnim.java b/app/src/main/java/com/chwl/app/ui/gift/widget/ICustormAnim.java new file mode 100644 index 0000000..9eecb11 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/gift/widget/ICustormAnim.java @@ -0,0 +1,14 @@ +package com.chwl.app.ui.gift.widget; + +import android.animation.AnimatorSet; +import android.view.View; + +/** + * Created by KathLine on 2017/7/7. + */ + +public interface ICustormAnim { + AnimatorSet startAnim(GiftFrameLayout giftFrameLayout, View rootView); + AnimatorSet comboAnim(GiftFrameLayout giftFrameLayout, View rootView); + AnimatorSet endAnim(GiftFrameLayout giftFrameLayout, View rootView); +} diff --git a/app/src/main/java/com/chwl/app/ui/gift/widget/NumberTextView.java b/app/src/main/java/com/chwl/app/ui/gift/widget/NumberTextView.java new file mode 100644 index 0000000..cf762ec --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/gift/widget/NumberTextView.java @@ -0,0 +1,92 @@ +package com.chwl.app.ui.gift.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.widget.ImageView; +import android.widget.LinearLayout; + +import com.chwl.app.R; + + +/** + * Created by KathLine on 2017/1/8. + */ +public class NumberTextView extends LinearLayout { + + private LinearLayout mNumberLl; + + private LayoutParams mLayoutParams; + + public NumberTextView(Context context) { + super(context); + init(); + } + + public NumberTextView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public NumberTextView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + private void init() { + LayoutInflater.from(getContext()).inflate(R.layout.number_calculator_layout, this); + mNumberLl = (LinearLayout) findViewById(R.id.numberLl); + mLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); +// mLayoutParams.leftMargin = -8; + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + } + + public void updataNumber(String number) { + mNumberLl.removeAllViews(); + for (int i = 0; i < number.length(); i++) { + mNumberLl.addView(getTimerImage(number.charAt(i))); + } + } + + private ImageView getTimerImage(char number) { + ImageView image = new ImageView(getContext()); + switch (number) { + case '0': + image.setImageResource(R.mipmap.number_0); + break; + case '1': + image.setImageResource(R.mipmap.number_1); + break; + case '2': + image.setImageResource(R.mipmap.number_2); + break; + case '3': + image.setImageResource(R.mipmap.number_3); + break; + case '4': + image.setImageResource(R.mipmap.number_4); + break; + case '5': + image.setImageResource(R.mipmap.number_5); + break; + case '6': + image.setImageResource(R.mipmap.number_6); + break; + case '7': + image.setImageResource(R.mipmap.number_7); + break; + case '8': + image.setImageResource(R.mipmap.number_8); + break; + case '9': + image.setImageResource(R.mipmap.number_9); + break; + } + image.setLayoutParams(mLayoutParams); + return image; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/gift/widget/StrokeTextView.java b/app/src/main/java/com/chwl/app/ui/gift/widget/StrokeTextView.java new file mode 100644 index 0000000..ee84e4c --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/gift/widget/StrokeTextView.java @@ -0,0 +1,95 @@ +package com.chwl.app.ui.gift.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.text.TextPaint; +import android.util.AttributeSet; +import android.widget.TextView; + +import com.chwl.app.R; + +import java.lang.reflect.Field; + +/** + * Created by KathLine on 2017/1/8. + */ +public class StrokeTextView extends TextView { + + TextPaint m_TextPaint; + int mInnerColor; + int mOuterColor; + + public StrokeTextView(Context context, int outerColor, int innerColor) { + super(context); + m_TextPaint = this.getPaint(); + this.mInnerColor = innerColor; + this.mOuterColor = outerColor; + + // TODO Auto-generated constructor stub + } + + public StrokeTextView(Context context, AttributeSet attrs) { + super(context, attrs); + m_TextPaint = this.getPaint(); + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.StrokeTextView); + this.mInnerColor = a.getColor(R.styleable.StrokeTextView_innnerColor,0xffffff); + this.mOuterColor = a.getColor(R.styleable.StrokeTextView_outerColor,0xffffff); + a.recycle(); + + } + + public StrokeTextView(Context context, AttributeSet attrs, int defStyle, int outerColor, int innnerColor) { + super(context, attrs, defStyle); + m_TextPaint = this.getPaint(); + this.mInnerColor = innnerColor; + this.mOuterColor = outerColor; + // TODO Auto-generated constructor stub + } + + private boolean m_bDrawSideLine = true; // 默认采用描边 + + /** + * + */ + @Override + protected void onDraw(Canvas canvas) { + if (m_bDrawSideLine) { + // 描外层 + setTextColorUseReflection(mOuterColor); + m_TextPaint.setStrokeWidth(5); + m_TextPaint.setStyle(Paint.Style.FILL_AND_STROKE); + super.onDraw(canvas); + + // 描内层,恢复原先的画笔 + setTextColorUseReflection(mInnerColor); + m_TextPaint.setStrokeWidth(0); + m_TextPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + } + super.onDraw(canvas); + } + + /** + * 使用反射的方法进行字体颜色的设置 + * @param color + */ + private void setTextColorUseReflection(int color) { + Field textColorField; + try { + textColorField = TextView.class.getDeclaredField("mCurTextColor"); + textColorField.setAccessible(true); + textColorField.set(this, color); + textColorField.setAccessible(false); + } catch (NoSuchFieldException e) { + e.printStackTrace(); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + m_TextPaint.setColor(color); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/im/GreetPresenter.java b/app/src/main/java/com/chwl/app/ui/im/GreetPresenter.java new file mode 100644 index 0000000..bdb1663 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/GreetPresenter.java @@ -0,0 +1,42 @@ +package com.chwl.app.ui.im; + +import com.chwl.core.bean.response.ServiceResult; +import com.chwl.core.im.GreetModel; +import com.chwl.core.utils.SharedPreferenceUtils; + +import io.reactivex.Single; +import io.reactivex.SingleSource; +import io.reactivex.functions.Function; + +public class GreetPresenter { + private static final String IS_GREETED = "is_greeted"; + private GreetModel greetModel; + private String mSessionId; + + public GreetPresenter(String sessionId) { + greetModel = new GreetModel(); + this.mSessionId = sessionId; + } + + public Single greetMsgGetOne(long uid, long toUid) { + return greetModel.greetMsgGetOne(uid, toUid).flatMap(new Function, SingleSource>() { + @Override + public SingleSource apply(ServiceResult stringServiceResult) throws Exception { + if (stringServiceResult.isSuccess()) { + setIsGreeted(mSessionId); + return Single.just(stringServiceResult.getData()); + } else { + return Single.just(""); + } + } + }); + } + + public boolean isCanSendGreet() { + return (boolean) SharedPreferenceUtils.get(mSessionId + IS_GREETED, true); + } + + public void setIsGreeted(String uid) { + SharedPreferenceUtils.put(uid + IS_GREETED, false); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/im/ImInitHelper.java b/app/src/main/java/com/chwl/app/ui/im/ImInitHelper.java new file mode 100644 index 0000000..e067306 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/ImInitHelper.java @@ -0,0 +1,220 @@ +package com.chwl.app.ui.im; + +import android.content.Context; + +import com.chwl.app.community.holder.DynamicSysHolder; +import com.chwl.app.community.im.WorldDynamicShareViewHolder; +import com.chwl.app.luckymoney.viewholder.LuckyMoneyMsgViewHolder; +import com.chwl.app.luckymoney.viewholder.LuckyMoneyTipsViewHolder; +import com.chwl.app.module_hall.HallDataManager; +import com.chwl.app.module_hall.im.msgholder.ClanMsgViewHolder; +import com.chwl.app.module_hall.im.msgholder.FamilyMsgViewHolder; +import com.chwl.app.share.viewholder.InAppSharingMsgViewHolder; +import com.chwl.app.ui.im.actions.GiftAction; +import com.chwl.app.ui.im.avtivity.NimP2PMessageActivity; +import com.chwl.app.ui.im.chat.GameTeamInviteViewHolder; +import com.chwl.app.ui.im.chat.MsgViewHolderAudioParty; +import com.chwl.app.ui.im.chat.MsgViewHolderChatHint; +import com.chwl.app.ui.im.chat.MsgViewHolderConfirm; +import com.chwl.app.ui.im.chat.MsgViewHolderContent; +import com.chwl.app.ui.im.chat.MsgViewHolderCpRelationalConfirm; +import com.chwl.app.ui.im.chat.MsgViewHolderCpRelationalNotify; +import com.chwl.app.ui.im.chat.MsgViewHolderEventStartNotify; +import com.chwl.app.ui.im.chat.MsgViewHolderFairy; +import com.chwl.app.ui.im.chat.MsgViewHolderGift; +import com.chwl.app.ui.im.chat.MsgViewHolderHello; +import com.chwl.app.ui.im.chat.MsgViewHolderLevel; +import com.chwl.app.ui.im.chat.MsgViewHolderLottery; +import com.chwl.app.ui.im.chat.MsgViewHolderOnline; +import com.chwl.app.ui.im.chat.MsgViewHolderP2PContactRecharge; +import com.chwl.app.ui.im.chat.MsgViewHolderRedPacket; +import com.chwl.app.ui.im.chat.MsgViewHolderSkill; +import com.chwl.app.ui.im.chat.MsgViewHolderText; +import com.chwl.app.ui.im.chat.SysMsgV2ViewHolder; +import com.chwl.app.ui.im.chat.SysMsgViewHolder; +import com.chwl.app.ui.user.activity.UserInfoActivity; +import com.chwl.core.community.attachment.DynamicSysAttachment; +import com.chwl.core.community.im.WorldDynamicAttachment; +import com.chwl.core.im.custom.bean.AssistantAttachment; +import com.chwl.core.im.custom.bean.CarAttachment; +import com.chwl.core.im.custom.bean.CarveUpGoldThirdLevelAttachment; +import com.chwl.core.im.custom.bean.ChatHintAttachment; +import com.chwl.core.im.custom.bean.CpInviteAttachment; +import com.chwl.core.im.custom.bean.FairySendAttachment; +import com.chwl.core.im.custom.bean.GameTeamInviteAttachment; +import com.chwl.core.im.custom.bean.GiftAttachment; +import com.chwl.core.im.custom.bean.InAppSharingFamilyAttachment; +import com.chwl.core.im.custom.bean.InAppSharingMiniWorldAttachment; +import com.chwl.core.im.custom.bean.InAppSharingRoomAttachment; +import com.chwl.core.im.custom.bean.InAppSharingTeamAttachment; +import com.chwl.core.im.custom.bean.LevelUpAttachment; +import com.chwl.core.im.custom.bean.LotteryAttachment; +import com.chwl.core.im.custom.bean.LuckyMoneyAttachment; +import com.chwl.core.im.custom.bean.LuckyMoneyTipsAttachment; +import com.chwl.core.im.custom.bean.MsgConfirmMsgAttachment; +import com.chwl.core.im.custom.bean.MsgCpRelationalChangeConfirmAttachment; +import com.chwl.core.im.custom.bean.MsgCpRelationalChangeNotifyAttachment; +import com.chwl.core.im.custom.bean.MsgEventStartNotifyAttachment; +import com.chwl.core.im.custom.bean.NewbieHelloAttachment; +import com.chwl.core.im.custom.bean.NobleAttachment; +import com.chwl.core.im.custom.bean.NoticeAttachment; +import com.chwl.core.im.custom.bean.OpenRoomNotiAttachment; +import com.chwl.core.im.custom.bean.P2PContactRechargeAttachment; +import com.chwl.core.im.custom.bean.RedPacketAttachment; +import com.chwl.core.im.custom.bean.SkillMsgAttachment; +import com.chwl.core.im.custom.bean.SysMsgAttachment; +import com.chwl.core.im.custom.bean.SysMsgV2Attachment; +import com.chwl.core.miniworld.bean.OpenAudioPartyAttachment; +import com.chwl.core.module_hall.im.ClanAttachment; +import com.chwl.core.module_hall.im.FamilyAttachment; +import com.chwl.core.public_chat_hall.attachment.AitMeAttachment; +import com.netease.nim.uikit.api.NimUIKit; +import com.netease.nim.uikit.api.model.contact.ContactEventListener; +import com.netease.nim.uikit.api.model.session.SessionCustomization; +import com.netease.nim.uikit.api.model.session.SessionEventListener; +import com.netease.nim.uikit.business.session.actions.BaseAction; +import com.netease.nim.uikit.business.session.actions.ImageAction; +import com.netease.nimlib.sdk.msg.model.IMMessage; + +import java.util.ArrayList; + +public class ImInitHelper { + private final ContactEventListener listener1 = new ContactEventListener() { + @Override + public void onItemClick(Context context, String account) { + NimP2PMessageActivity.start(context, account); + } + + @Override + public void onItemLongClick(Context context, String account) { + + } + + @Override + public void onAvatarClick(Context context, String account) { + UserInfoActivity.Companion.start(context, Long.parseLong(account)); + } + }; + private final SessionEventListener listener = new SessionEventListener() { + @Override + public void onAvatarClicked(Context context, IMMessage message) { + if (message == null) return; + UserInfoActivity.Companion.start(context, Long.parseLong(message.getFromAccount())); + } + + @Override + public void onAvatarLongClicked(Context context, IMMessage message) { + + } + }; + + private ImInitHelper() { + + } + + public static ImInitHelper get() { + return Helper.INSTANCE; + } + + public void init() { + initP2PSessionCustomization(); + initTeamSessionCustomization(); + } + + public void unInit(){ + NimUIKit.setSessionListener(null); + NimUIKit.setContactEventListener(null); + } + + private void initP2PSessionCustomization() { + SessionCustomization sessionCustomization = new SessionCustomization(); + ArrayList actions = new ArrayList<>(); + actions.add(new ImageAction()); + actions.add(new GiftAction()); + sessionCustomization.actions = actions; + sessionCustomization.withSticker = true; + NimUIKit.setCommonP2PSessionCustomization(sessionCustomization); + + // 语音派对 + NimUIKit.registerMsgItemViewHolder(OpenAudioPartyAttachment.class, MsgViewHolderAudioParty.class); + + NimUIKit.registerMsgItemViewHolder(OpenRoomNotiAttachment.class, MsgViewHolderOnline.class); + NimUIKit.registerMsgItemViewHolder(GiftAttachment.class, MsgViewHolderGift.class); + NimUIKit.registerMsgItemViewHolder(NoticeAttachment.class, MsgViewHolderContent.class); + NimUIKit.registerMsgItemViewHolder(RedPacketAttachment.class, MsgViewHolderRedPacket.class); + NimUIKit.registerMsgItemViewHolder(NewbieHelloAttachment.class, MsgViewHolderHello.class); + NimUIKit.registerMsgItemViewHolder(LotteryAttachment.class, MsgViewHolderLottery.class); + NimUIKit.registerMsgItemViewHolder(NobleAttachment.class, MsgViewHolderText.class); + NimUIKit.registerMsgItemViewHolder(CarAttachment.class, MsgViewHolderText.class); + NimUIKit.registerMsgItemViewHolder(AssistantAttachment.class, MsgViewHolderText.class); + NimUIKit.registerMsgItemViewHolder(InAppSharingRoomAttachment.class, InAppSharingMsgViewHolder.class); + NimUIKit.registerMsgItemViewHolder(InAppSharingFamilyAttachment.class, InAppSharingMsgViewHolder.class); + NimUIKit.registerMsgItemViewHolder(InAppSharingMiniWorldAttachment.class, InAppSharingMsgViewHolder.class); + NimUIKit.registerMsgItemViewHolder(InAppSharingTeamAttachment.class, InAppSharingMsgViewHolder.class); + NimUIKit.registerMsgItemViewHolder(SysMsgAttachment.class, SysMsgViewHolder.class); + //V2系统消息,废弃23 V1 + NimUIKit.registerMsgItemViewHolder(SysMsgV2Attachment.class, SysMsgV2ViewHolder.class); + NimUIKit.registerMsgItemViewHolder(LevelUpAttachment.class, MsgViewHolderLevel.class); + NimUIKit.registerMsgItemViewHolder(AitMeAttachment.class, MsgViewHolderAitMe.class); + //模厅模块 + HallDataManager.get().mainNimOnCreate(); + //公会模块 + NimUIKit.registerMsgItemViewHolder(ClanAttachment.class, ClanMsgViewHolder.class); + //家族模块 + NimUIKit.registerMsgItemViewHolder(FamilyAttachment.class, FamilyMsgViewHolder.class); + //瓜分钻石 三级 + NimUIKit.registerMsgItemViewHolder(CarveUpGoldThirdLevelAttachment.class, MsgViewHolderText.class); + + // 社区动态 + NimUIKit.registerMsgItemViewHolder(DynamicSysAttachment.class, DynamicSysHolder.class); + NimUIKit.registerMsgItemViewHolder(WorldDynamicAttachment.class, WorldDynamicShareViewHolder.class); + + NimUIKit.registerMsgItemViewHolder(ChatHintAttachment.class, MsgViewHolderChatHint.class); + + //技能卡 + NimUIKit.registerMsgItemViewHolder(SkillMsgAttachment.class, MsgViewHolderSkill.class); + //CP + NimUIKit.registerMsgItemViewHolder(CpInviteAttachment.class, MsgViewHolderText.class); + NimUIKit.registerMsgItemViewHolder(FairySendAttachment.class, MsgViewHolderFairy.class); + // 客服充值 + NimUIKit.registerMsgItemViewHolder(P2PContactRechargeAttachment.class, MsgViewHolderP2PContactRecharge.class); + + // 游戏组队 - 邀请 + NimUIKit.registerMsgItemViewHolder(GameTeamInviteAttachment.class, GameTeamInviteViewHolder.class); + + // 通用确认取消-消息 + NimUIKit.registerMsgItemViewHolder(MsgConfirmMsgAttachment.class, MsgViewHolderConfirm.class); + + // cp关系确认取消 / 关系变更通知-消息 + NimUIKit.registerMsgItemViewHolder(MsgCpRelationalChangeConfirmAttachment.class, MsgViewHolderCpRelationalConfirm.class); + NimUIKit.registerMsgItemViewHolder(MsgCpRelationalChangeNotifyAttachment.class, MsgViewHolderCpRelationalNotify.class); + //-----用户自建活动开启通知 + NimUIKit.registerMsgItemViewHolder(MsgEventStartNotifyAttachment.class, MsgViewHolderEventStartNotify.class); + + NimUIKit.setSessionListener(listener); + NimUIKit.setContactEventListener(listener1); + } + + private void initTeamSessionCustomization() { + SessionCustomization sessionCustomization = new SessionCustomization(); + ArrayList actions = new ArrayList<>(); + actions.add(new ImageAction()); + sessionCustomization.actions = actions; + sessionCustomization.withSticker = true; + NimUIKit.setCommonTeamSessionCustomization(sessionCustomization); + + NimUIKit.registerMsgItemViewHolder(LuckyMoneyAttachment.class, LuckyMoneyMsgViewHolder.class); + NimUIKit.registerMsgItemViewHolder(InAppSharingRoomAttachment.class, InAppSharingMsgViewHolder.class); + NimUIKit.registerMsgItemViewHolder(InAppSharingFamilyAttachment.class, InAppSharingMsgViewHolder.class); + NimUIKit.registerMsgItemViewHolder(InAppSharingMiniWorldAttachment.class, InAppSharingMsgViewHolder.class); + NimUIKit.registerMsgItemViewHolder(InAppSharingTeamAttachment.class, InAppSharingMsgViewHolder.class); + NimUIKit.registerMsgItemViewHolder(LuckyMoneyTipsAttachment.class, LuckyMoneyTipsViewHolder.class); + + NimUIKit.setSessionListener(listener); + NimUIKit.setContactEventListener(listener1); + } + + private static final class Helper { + private static final ImInitHelper INSTANCE = new ImInitHelper(); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/im/MessageListPanelEx.java b/app/src/main/java/com/chwl/app/ui/im/MessageListPanelEx.java new file mode 100644 index 0000000..1ed2514 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/MessageListPanelEx.java @@ -0,0 +1,1385 @@ +package com.chwl.app.ui.im; + +import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; +import android.app.Activity; +import android.content.ActivityNotFoundException; +import android.content.Intent; +import android.graphics.Bitmap; +import android.net.Uri; +import android.os.CountDownTimer; +import android.os.Handler; +import android.text.TextUtils; +import android.util.Pair; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.RelativeLayout; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.netease.nim.uikit.api.NimUIKit; +import com.netease.nim.uikit.api.model.user.UserInfoObserver; +import com.netease.nim.uikit.business.contact.selector.activity.ContactSelectActivity; +import com.netease.nim.uikit.business.preference.UserPreferences; +import com.netease.nim.uikit.business.robot.parser.elements.group.LinkElement; +import com.netease.nim.uikit.business.session.activity.VoiceTrans; +import com.netease.nim.uikit.business.session.audio.MessageAudioControl; +import com.netease.nim.uikit.business.session.helper.MessageHelper; +import com.netease.nim.uikit.business.session.helper.MessageListPanelHelper; +import com.netease.nim.uikit.business.session.module.Container; +import com.netease.nim.uikit.business.session.module.list.IncomingMsgPrompt; +import com.netease.nim.uikit.business.session.module.list.MsgAdapter; +import com.netease.nim.uikit.business.session.viewholder.robot.RobotLinkView; +import com.netease.nim.uikit.common.ui.dialog.CustomAlertDialog; +import com.netease.nim.uikit.common.ui.dialog.EasyAlertDialog; +import com.netease.nim.uikit.common.ui.dialog.EasyAlertDialogHelper; +import com.netease.nim.uikit.common.ui.recyclerview.adapter.BaseFetchLoadAdapter; +import com.netease.nim.uikit.common.ui.recyclerview.adapter.IRecyclerView; +import com.netease.nim.uikit.common.ui.recyclerview.listener.OnItemClickListener; +import com.netease.nim.uikit.common.ui.recyclerview.loadmore.MsgListFetchLoadMoreView; +import com.netease.nim.uikit.common.util.AntiSpamUtil; +import com.netease.nim.uikit.common.util.media.BitmapDecoder; +import com.netease.nim.uikit.common.util.sys.ClipboardUtil; +import com.netease.nim.uikit.common.util.sys.NetworkUtil; +import com.netease.nim.uikit.common.util.sys.ScreenUtil; +import com.netease.nim.uikit.impl.NimUIKitImpl; +import com.netease.nimlib.sdk.NIMClient; +import com.netease.nimlib.sdk.Observer; +import com.netease.nimlib.sdk.RequestCallback; +import com.netease.nimlib.sdk.RequestCallbackWrapper; +import com.netease.nimlib.sdk.ResponseCode; +import com.netease.nimlib.sdk.msg.MessageBuilder; +import com.netease.nimlib.sdk.msg.MsgService; +import com.netease.nimlib.sdk.msg.MsgServiceObserve; +import com.netease.nimlib.sdk.msg.attachment.FileAttachment; +import com.netease.nimlib.sdk.msg.constant.AttachStatusEnum; +import com.netease.nimlib.sdk.msg.constant.MsgDirectionEnum; +import com.netease.nimlib.sdk.msg.constant.MsgStatusEnum; +import com.netease.nimlib.sdk.msg.constant.MsgTypeEnum; +import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum; +import com.netease.nimlib.sdk.msg.model.AttachmentProgress; +import com.netease.nimlib.sdk.msg.model.IMMessage; +import com.netease.nimlib.sdk.msg.model.QueryDirectionEnum; +import com.netease.nimlib.sdk.msg.model.RevokeMsgNotification; +import com.netease.nimlib.sdk.robot.model.RobotAttachment; +import com.netease.nimlib.sdk.robot.model.RobotMsgType; +import com.netease.nimlib.sdk.team.constant.TeamMemberType; +import com.netease.nimlib.sdk.team.model.TeamMember; +import com.chwl.app.R; +import com.chwl.core.module_hall.im.HallAttachment; +import com.chwl.core.module_hall.im.HallImMsgInfo; +import com.chwl.core.room.event.MessageSizeEvent; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; + +import org.greenrobot.eventbus.EventBus; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +/** + * 基于RecyclerView的消息收发模块 + * Created by huangjun on 2016/12/27. + */ +public class MessageListPanelEx { + + private static final int REQUEST_CODE_FORWARD_PERSON = 0x01; + private static final int REQUEST_CODE_FORWARD_TEAM = 0x02; + // 背景图片缓存 + private static Pair background; + private static Comparator comp = new Comparator() { + + @Override + public int compare(IMMessage o1, IMMessage o2) { + long time = o1.getTime() - o2.getTime(); + return time == 0 ? 0 : (time < 0 ? -1 : 1); + } + }; + // container + private Container container; + private View rootView; + // message list view + private RecyclerView messageListView; + private List items; + private MsgAdapter adapter; + private ImageView listviewBk; + // 新消息到达提醒 + private IncomingMsgPrompt incomingMsgPrompt; + private Handler uiHandler; + // 仅显示消息记录,不接收和发送消息 + private boolean recordOnly; + // 从服务器拉取消息记录 + private boolean remote; + // recordId,记录当前消息id + private String recordId; + // 语音转文字 + private VoiceTrans voiceTrans; + // 待转发消息 + private IMMessage forwardMessage; + private CountDownTimer countDownTimer; + + private OnItemClickListener listener = new OnItemClickListener() { + @Override + public void onItemClick(IRecyclerView adapter, View view, int position) { + } + + @Override + public void onItemLongClick(IRecyclerView adapter, View view, int position) { + } + + @Override + public void onItemChildClick(IRecyclerView adapter2, View view, int position) { + if (isSessionMode() && view != null && view instanceof RobotLinkView) { + RobotLinkView robotLinkView = (RobotLinkView) view; + // robotLinkView.onClick(); + LinkElement element = robotLinkView.getElement(); + if (element != null) { + element.getTarget(); + if (LinkElement.TYPE_URL.equals(element.getType())) { + Intent intent = new Intent(); + intent.setAction("android.intent.action.VIEW"); + Uri content_url = Uri.parse(element.getTarget()); + intent.setData(content_url); + try { + container.activity.startActivity(intent); + } catch (ActivityNotFoundException e) { +// Toast.makeText(container.activity, ResUtil.getString(R.string.ui_im_messagelistpanelex_01), Toast.LENGTH_SHORT).show(); + SingleToastUtil.showToastShort(ResUtil.getString(R.string.ui_im_messagelistpanelex_02)); + } + + } else if (LinkElement.TYPE_BLOCK.equals(element.getType())) { + // 发送点击的block + IMMessage message = adapter.getItem(position); + if (message != null) { + String robotAccount = ((RobotAttachment) message.getAttachment()).getFromRobotAccount(); + IMMessage robotMsg = MessageBuilder.createRobotMessage(message.getSessionId(), message.getSessionType(), robotAccount, + robotLinkView.getShowContent(), RobotMsgType.LINK, "", element.getTarget(), element.getParams()); + container.proxy.sendMessage(robotMsg); + } + } + } + } + } + }; + /** + * 消息状态变化观察者 + */ + private Observer messageStatusObserver = new Observer() { + @Override + public void onEvent(IMMessage message) { + if (isMyMessage(message)) { + onMessageStatusChange(message); + } + } + }; + /** + * 消息附件上传/下载进度观察者 + */ + private Observer attachmentProgressObserver = new Observer() { + @Override + public void onEvent(AttachmentProgress progress) { + onAttachmentProgressChange(progress); + } + }; + /** + * 本地消息接收观察者 + */ + private MessageListPanelHelper.LocalMessageObserver incomingLocalMessageObserver = new MessageListPanelHelper.LocalMessageObserver() { + @Override + public void onAddMessage(IMMessage message) { + if (message == null || !container.account.equals(message.getSessionId())) { + return; + } + + onMsgSend(message); + } + + @Override + public void onClearMessages(String account) { + items.clear(); + refreshMessageList(); + adapter.fetchMoreEnd(null, true); + } + }; + /** + * 消息撤回观察者 + */ + private Observer revokeMessageObserver = new Observer() { + @Override + public void onEvent(RevokeMsgNotification notification) { + if (notification == null || notification.getMessage() == null) { + return; + } + IMMessage message = notification.getMessage(); + + if (!container.account.equals(message.getSessionId())) { + return; + } + + deleteItem(message, false); + } + }; + private UserInfoObserver uinfoObserver; + private OnMessageFilterListener onMessageFilterListener; + + public MessageListPanelEx(Container container, View rootView, boolean recordOnly, boolean remote) { + this(container, rootView, null, recordOnly, remote); + } + + public MessageListPanelEx(Container container, View rootView, IMMessage anchor, boolean recordOnly, boolean remote) { + this.container = container; + this.rootView = rootView; + this.recordOnly = recordOnly; + this.remote = remote; + + init(anchor); + } + + public MessageListPanelEx(Container container, View rootView, IMMessage anchor, boolean recordOnly, boolean remote, String recordId) { + this.container = container; + this.rootView = rootView; + this.recordOnly = recordOnly; + this.remote = remote; + this.recordId = recordId; + + init(anchor); + } + + public void onResume() { + setEarPhoneMode(UserPreferences.isEarPhoneModeEnable(), false); + } + + public void onPause() { + MessageAudioControl.getInstance(container.activity).stopAudio(); + } + + public void onDestroy() { + registerObservers(false); + if (countDownTimer != null) { + countDownTimer.cancel(); + } + } + + public boolean onBackPressed() { + uiHandler.removeCallbacks(null); + if (countDownTimer != null) { + countDownTimer.cancel(); + } + MessageAudioControl.getInstance(container.activity).stopAudio(); // 界面返回,停止语音播放 + if (voiceTrans != null && voiceTrans.isShow()) { + voiceTrans.hide(); + return true; + } + return false; + } + + public void reload(Container container, IMMessage anchor) { + this.container = container; + if (adapter != null) { + adapter.clearData(); + } + + initFetchLoadListener(anchor); + } + + private void init(IMMessage anchor) { + initListView(anchor); + + this.uiHandler = new Handler(); + if (!recordOnly) { + incomingMsgPrompt = new IncomingMsgPrompt(container.activity, rootView, messageListView, adapter, uiHandler); + } + + registerObservers(true); + } + + private void initListView(IMMessage anchor) { + listviewBk = (ImageView) rootView.findViewById(R.id.message_activity_background); + + // RecyclerView + messageListView = (RecyclerView) rootView.findViewById(R.id.messageListView); + messageListView.setLayoutManager(new LinearLayoutManager(container.activity)); + messageListView.requestDisallowInterceptTouchEvent(true); + messageListView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrollStateChanged(RecyclerView recyclerView, int newState) { + super.onScrollStateChanged(recyclerView, newState); + if (newState != RecyclerView.SCROLL_STATE_IDLE) { + container.proxy.shouldCollapseInputPanel(); + } + } + }); + messageListView.setOverScrollMode(View.OVER_SCROLL_NEVER); + + // adapter + items = new ArrayList<>(); + adapter = new MsgAdapter(messageListView, items, container); + adapter.setFetchMoreView(new MsgListFetchLoadMoreView()); + adapter.setLoadMoreView(new MsgListFetchLoadMoreView()); + adapter.setEventListener(new MsgItemEventListener()); + initFetchLoadListener(anchor); + messageListView.setAdapter(adapter); + messageListView.addOnItemTouchListener(listener); + } + + public boolean isSessionMode() { + return !recordOnly && !remote; + } + + private void initFetchLoadListener(IMMessage anchor) { + MessageLoader loader = new MessageLoader(anchor, remote); + + if (recordOnly && !remote) { + // 双向Load + adapter.setOnFetchMoreListener(loader); + adapter.setOnLoadMoreListener(loader); + } else { + // 只下来加载old数据 + adapter.setOnFetchMoreListener(loader); + } + } + + // 刷新消息列表 + public void refreshMessageList() { + container.activity.runOnUiThread(new Runnable() { + + @Override + public void run() { + adapter.notifyDataSetChanged(); + } + }); + } + + public void scrollToBottom() { + uiHandler.postDelayed(new Runnable() { + @Override + public void run() { + doScrollToBottom(); + } + }, 200); + } + + private void doScrollToBottom() { + messageListView.scrollToPosition(adapter.getBottomDataPosition()); + } + + public void onIncomingMessage(List messages) { + boolean needScrollToBottom = isLastMessageVisible(); + boolean needRefresh = false; + List addedListItems = new ArrayList<>(messages.size()); + for (IMMessage message : messages) { + + if (isMyMessage(message)) { + items.add(message); + addedListItems.add(message); + needRefresh = true; + } + } + if (needRefresh) { + sortMessages(items); + adapter.notifyDataSetChanged(); + } + + adapter.updateShowTimeItem(addedListItems, false, true); + + // incoming messages tip + IMMessage lastMsg = messages.get(messages.size() - 1); + if (isMyMessage(lastMsg)) { + if (needScrollToBottom) { + doScrollToBottom(); + } else if (incomingMsgPrompt != null && lastMsg.getSessionType() != SessionTypeEnum.ChatRoom) { + incomingMsgPrompt.show(lastMsg); + } + } + } + + private boolean isLastMessageVisible() { + LinearLayoutManager layoutManager = (LinearLayoutManager) messageListView.getLayoutManager(); + int lastVisiblePosition = layoutManager.findLastCompletelyVisibleItemPosition(); + return lastVisiblePosition >= adapter.getBottomDataPosition(); + } + + // 发送消息后,更新本地消息列表 + public void onMsgSend(IMMessage message) { + List addedListItems = new ArrayList<>(1); + addedListItems.add(message); + adapter.updateShowTimeItem(addedListItems, false, true); + + adapter.appendData(message); + + doScrollToBottom(); + } + + /** + * **************************** 排序 *********************************** + */ + private void sortMessages(List list) { + if (list.size() == 0) { + return; + } + Collections.sort(list, comp); + } + + /** + * ************************* 观察者 ******************************** + */ + + private void registerObservers(boolean register) { + MsgServiceObserve service = NIMClient.getService(MsgServiceObserve.class); + service.observeMsgStatus(messageStatusObserver, register); + service.observeAttachmentProgress(attachmentProgressObserver, register); + service.observeRevokeMessage(revokeMessageObserver, register); + if (register) { + registerUserInfoObserver(); + } else { + unregisterUserInfoObserver(); + } + + MessageListPanelHelper.getInstance().registerObserver(incomingLocalMessageObserver, register); + } + + private void onMessageStatusChange(IMMessage message) { + int index = getItemIndex(message.getUuid()); + if (index >= 0 && index < items.size()) { + IMMessage item = items.get(index); + if (AntiSpamUtil.isAntiSpam(message)) { + item.setStatus(MsgStatusEnum.fail); + NIMClient.getService(MsgService.class).updateIMMessageStatus(item); + } else { + item.setStatus(message.getStatus()); + } + item.setAttachStatus(message.getAttachStatus()); + + // 处理语音、音视频通话 + if (item.getMsgType() == MsgTypeEnum.audio || item.getMsgType() == MsgTypeEnum.avchat) { + item.setAttachment(message.getAttachment()); // 附件可能更新了 + } + + // resend的的情况,可能时间已经变化了,这里要重新检查是否要显示时间 + List msgList = new ArrayList<>(1); + msgList.add(message); + adapter.updateShowTimeItem(msgList, false, true); + + refreshViewHolderByIndex(index); + } + } + + private void onAttachmentProgressChange(AttachmentProgress progress) { + int index = getItemIndex(progress.getUuid()); + if (index >= 0 && index < items.size()) { + IMMessage item = items.get(index); + float value = (float) progress.getTransferred() / (float) progress.getTotal(); + adapter.putProgress(item, value); + refreshViewHolderByIndex(index); + } + } + + public boolean isMyMessage(IMMessage message) { + return message.getSessionType() == container.sessionType + && message.getSessionId() != null + && message.getSessionId().equals(container.account); + } + + /** + * 刷新单条消息 + */ + public void refreshViewHolderByIndex(final int index) { + container.activity.runOnUiThread(new Runnable() { + + @Override + public void run() { + if (index < 0) { + return; + } + + adapter.notifyDataItemChanged(index); + } + }); + } + + public int getItemIndex(String uuid) { + for (int i = 0; i < items.size(); i++) { + IMMessage message = items.get(i); + if (TextUtils.equals(message.getUuid(), uuid)) { + return i; + } + } + + return -1; + } + + public int getApplyItemIndex(String recordId) { + for (int i = 0; i < items.size(); i++) { + IMMessage message = items.get(i); + if (message.getMsgType() == MsgTypeEnum.custom && message.getAttachment() != null) { + if (message.getAttachment() instanceof HallAttachment) { + HallAttachment attachment = (HallAttachment) message.getAttachment(); + HallImMsgInfo info = attachment.getHallImMsgInfo(); + if (info != null && info.getUrl() != null && info.getUrl().contains("recordId")) { + Uri uri = Uri.parse(info.getUrl()); + String record = uri.getQueryParameter("recordId"); + if (recordId.equals(record)) { + return i; + } + } + } + } + } + + return -1; + } + + public void setChattingBackground(String uriString, int color) { + if (uriString != null) { + Uri uri = Uri.parse(uriString); + if (uri.getScheme().equalsIgnoreCase("file") && uri.getPath() != null) { + listviewBk.setImageBitmap(getBackground(uri.getPath())); + } else if (uri.getScheme().equalsIgnoreCase("android.resource")) { + List paths = uri.getPathSegments(); + if (paths == null || paths.size() != 2) { + return; + } + String type = paths.get(0); + String name = paths.get(1); + String pkg = uri.getHost(); + int resId = container.activity.getResources().getIdentifier(name, type, pkg); + if (resId != 0) { + listviewBk.setBackgroundResource(resId); + } + } + } else if (color != 0) { + listviewBk.setBackgroundColor(color); + } + } + + private void setEarPhoneMode(boolean earPhoneMode, boolean update) { + if (update) { + UserPreferences.setEarPhoneModeEnable(earPhoneMode); + } + MessageAudioControl.getInstance(container.activity).setEarPhoneModeEnable(earPhoneMode); + } + + private Bitmap getBackground(String path) { + if (background != null && path.equals(background.first) && background.second != null) { + return background.second; + } + + if (background != null && background.second != null) { + background.second.recycle(); + } + + Bitmap bitmap = null; + if (path.startsWith("/android_asset")) { + String asset = path.substring(path.indexOf("/", 1) + 1); + try { + InputStream ais = container.activity.getAssets().open(asset); + bitmap = BitmapDecoder.decodeSampled(ais, ScreenUtil.screenWidth, ScreenUtil.screenHeight); + ais.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } else { + bitmap = BitmapDecoder.decodeSampled(path, ScreenUtil.screenWidth, ScreenUtil.screenHeight); + } + background = new Pair<>(path, bitmap); + return bitmap; + } + + private void registerUserInfoObserver() { + if (uinfoObserver == null) { + uinfoObserver = new UserInfoObserver() { + @Override + public void onUserInfoChanged(List accounts) { + if (container.sessionType == SessionTypeEnum.P2P) { + if (accounts.contains(container.account) || accounts.contains(NimUIKit.getAccount())) { + adapter.notifyDataSetChanged(); + } + } else { // 群的,简单的全部重刷 + adapter.notifyDataSetChanged(); + } + } + }; + } + + NimUIKit.getUserInfoObservable().registerObserver(uinfoObserver, true); + } + + private void unregisterUserInfoObserver() { + if (uinfoObserver != null) { + NimUIKit.getUserInfoObservable().registerObserver(uinfoObserver, false); + } + } + + /** + * 收到已读回执(更新VH的已读label) + */ + + public void receiveReceipt() { + updateReceipt(items); + refreshMessageList(); + } + + public void updateReceipt(final List messages) { + for (int i = messages.size() - 1; i >= 0; i--) { + if (receiveReceiptCheck(messages.get(i))) { + adapter.setUuid(messages.get(i).getUuid()); + break; + } + } + } + + private boolean receiveReceiptCheck(final IMMessage msg) { + if (msg != null && msg.getSessionType() == SessionTypeEnum.P2P + && msg.getDirect() == MsgDirectionEnum.Out + && msg.getMsgType() != MsgTypeEnum.tip + && msg.getMsgType() != MsgTypeEnum.notification + && msg.isRemoteRead()) { + return true; + } + + return false; + } + + /** + * 发送已读回执(需要过滤) + */ + + public void sendReceipt() { + // 查询全局已读回执功能开关配置 + if (!NimUIKitImpl.getOptions().shouldHandleReceipt) { + return; + } + + if (container.account == null || container.sessionType != SessionTypeEnum.P2P) { + return; + } + + IMMessage message = getLastReceivedMessage(); + if (!sendReceiptCheck(message)) { + return; + } + + NIMClient.getService(MsgService.class).sendMessageReceipt(container.account, message); + } + + private IMMessage getLastReceivedMessage() { + IMMessage lastMessage = null; + for (int i = items.size() - 1; i >= 0; i--) { + if (sendReceiptCheck(items.get(i))) { + lastMessage = items.get(i); + break; + } + } + + return lastMessage; + } + + private boolean sendReceiptCheck(final IMMessage msg) { + if (msg == null || msg.getDirect() != MsgDirectionEnum.In || + msg.getMsgType() == MsgTypeEnum.tip || msg.getMsgType() == MsgTypeEnum.notification) { + return false; // 非收到的消息,Tip消息和通知类消息,不要发已读回执 + } + + return true; + } + + // 删除消息 + private void deleteItem(IMMessage messageItem, boolean isRelocateTime) { + NIMClient.getService(MsgService.class).deleteChattingHistory(messageItem); + List messages = new ArrayList<>(); + for (IMMessage message : items) { + if (message.getUuid().equals(messageItem.getUuid())) { + continue; + } + messages.add(message); + } + updateReceipt(messages); + adapter.deleteItem(messageItem, isRelocateTime); + } + + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (resultCode != Activity.RESULT_OK) { + return; + } + final ArrayList selected = data.getStringArrayListExtra(ContactSelectActivity.RESULT_DATA); + if (selected != null && !selected.isEmpty()) { + switch (requestCode) { + case REQUEST_CODE_FORWARD_TEAM: + doForwardMessage(selected.get(0), SessionTypeEnum.Team); + break; + case REQUEST_CODE_FORWARD_PERSON: + doForwardMessage(selected.get(0), SessionTypeEnum.P2P); + break; + } + } + } + + // 转发消息 + private void doForwardMessage(final String sessionId, SessionTypeEnum sessionTypeEnum) { + IMMessage message; + if (forwardMessage.getMsgType() == MsgTypeEnum.robot) { + message = buildForwardRobotMessage(sessionId, sessionTypeEnum); + } else { + message = MessageBuilder.createForwardMessage(forwardMessage, sessionId, sessionTypeEnum); + } + + if (message == null) { +// Toast.makeText(container.activity, ResUtil.getString(R.string.ui_im_messagelistpanelex_03), Toast.LENGTH_SHORT).show(); + SingleToastUtil.showToastShort(ResUtil.getString(R.string.ui_im_messagelistpanelex_04)); + return; + } + + NIMClient.getService(MsgService.class) + .sendMessage(message, false) + .setCallback(new RequestCallbackWrapper() { + @Override + public void onResult(int code, Void result, Throwable exception) { + } + }); + if (container.account.equals(sessionId)) { + onMsgSend(message); + } + } + + private IMMessage buildForwardRobotMessage(final String sessionId, SessionTypeEnum sessionTypeEnum) { + if (forwardMessage.getMsgType() == MsgTypeEnum.robot && forwardMessage.getAttachment() != null) { + RobotAttachment robotAttachment = (RobotAttachment) forwardMessage.getAttachment(); + if (robotAttachment.isRobotSend()) { + return null; // 机器人发的消息不能转发了 + } + + return MessageBuilder.createTextMessage(sessionId, sessionTypeEnum, forwardMessage.getContent()); + } + + return null; + } + + public void setOnMessageFilterListener(OnMessageFilterListener onMessageFilterListener) { + this.onMessageFilterListener = onMessageFilterListener; + } + + public interface OnMessageFilterListener { + List filterLoadedMessage(List messages); + } + + /** + * ***************************************** 数据加载 ********************************************* + */ + + private class MessageLoader implements BaseFetchLoadAdapter.RequestLoadMoreListener, BaseFetchLoadAdapter.RequestFetchMoreListener { + + private int loadMsgCount = getLoadMsgCount(); + + private QueryDirectionEnum direction = null; + + private IMMessage anchor; + private boolean remote; + + private boolean isShowAnim = false; + + private boolean firstLoad = true; + private RequestCallback> callback = new RequestCallbackWrapper>() { + @Override + public void onResult(int code, List messages, Throwable exception) { + if (code != ResponseCode.RES_SUCCESS || exception != null) { + if (direction == QueryDirectionEnum.QUERY_OLD) { + adapter.fetchMoreFailed(); + } else if (direction == QueryDirectionEnum.QUERY_NEW) { + adapter.loadMoreFail(); + } + + return; + } + + if (messages != null) { + onMessageLoaded(messages); + } + } + }; + + public MessageLoader(IMMessage anchor, boolean remote) { + this.anchor = anchor; + this.remote = remote; + if (remote) { + loadFromRemote(); + } else { + if (anchor == null) { + loadFromLocal(QueryDirectionEnum.QUERY_OLD); + } else { + loadAnchorContext(); // 加载指定anchor的上下文 + } + } + } + + private void loadAnchorContext() { + // query new, auto load old + direction = QueryDirectionEnum.QUERY_NEW; + NIMClient.getService(MsgService.class).queryMessageListEx(anchor(), direction, loadMsgCount, true) + .setCallback(new RequestCallbackWrapper>() { + @Override + public void onResult(int code, List messages, Throwable exception) { + if (code != ResponseCode.RES_SUCCESS || exception != null) { + return; + } + + onAnchorContextMessageLoaded(messages); + } + }); + } + + private void loadFromLocal(QueryDirectionEnum direction) { + this.direction = direction; + NIMClient.getService(MsgService.class).queryMessageListEx(anchor(), direction, loadMsgCount, true) + .setCallback(callback); + } + + private void loadFromRemote() { + this.direction = QueryDirectionEnum.QUERY_OLD; + NIMClient.getService(MsgService.class).pullMessageHistory(anchor(), loadMsgCount, true) + .setCallback(callback); + } + + private IMMessage anchor() { + if (items.size() == 0) { + return anchor == null ? MessageBuilder.createEmptyMessage(container.account, container.sessionType, 0) : anchor; + } else { + int index = (direction == QueryDirectionEnum.QUERY_NEW ? items.size() - 1 : 0); + return items.get(index); + } + } + + private int getLoadMsgCount() { + if (TextUtils.isEmpty(recordId)) { + return NimUIKitImpl.getOptions().messageCountLoadOnce; + } else { + return 50; + } + } + + /** + * 私聊聊天信息数(发起私聊限制需要用到) + * + * @param messages + */ + private void onMessageLoaded(List messages) { + if (messages == null) { + return; + } + List tempMessages = new ArrayList<>(); + for (IMMessage message : messages) { + if (message.getMsgType() == MsgTypeEnum.text) { + tempMessages.add(message); + } + } + EventBus.getDefault().post(new MessageSizeEvent(tempMessages.size())); + if (onMessageFilterListener != null) { + messages = onMessageFilterListener.filterLoadedMessage(messages); + } + boolean noMoreMessage = messages.size() < loadMsgCount; + + if (remote) { + Collections.reverse(messages); + } + + // 在第一次加载的过程中又收到了新消息,做一下去重 + if (firstLoad && items.size() > 0) { + for (IMMessage message : messages) { + int removeIndex = 0; + for (IMMessage item : items) { + if (item.isTheSame(message)) { + adapter.remove(removeIndex); + break; + } + removeIndex++; + } + } + } + + // 加入anchor + if (firstLoad && anchor != null) { + messages.add(anchor); + } + + // 在更新前,先确定一些标记 + List total = new ArrayList<>(); + total.addAll(items); + boolean isBottomLoad = direction == QueryDirectionEnum.QUERY_NEW; + if (isBottomLoad) { + total.addAll(messages); + } else { + total.addAll(0, messages); + } + adapter.updateShowTimeItem(total, true, firstLoad); // 更新要显示时间的消息 + updateReceipt(total); // 更新已读回执标签 + + // 加载状态修改,刷新界面 + if (isBottomLoad) { + // 底部加载 + if (noMoreMessage) { + adapter.loadMoreEnd(messages, true); + } else { + adapter.loadMoreComplete(messages); + } + } else { + // 顶部加载 + if (noMoreMessage) { + adapter.fetchMoreEnd(messages, true); + } else { + adapter.fetchMoreComplete(messages); + } + } + + // 如果是第一次加载,updateShowTimeItem返回的就是lastShowTimeItem + if (firstLoad) { + doScrollToBottom(); + sendReceipt(); // 发送已读回执 + } + + if (!TextUtils.isEmpty(recordId) && !isShowAnim) { + doScrollToPosition(); + } + + firstLoad = false; + loadMsgCount = NimUIKitImpl.getOptions().messageCountLoadOnce; + } + + private void doScrollToPosition() { + uiHandler.postDelayed(new Runnable() { + @Override + public void run() { + int index = getApplyItemIndex(recordId); + if(index == -1){ + messageListView.scrollToPosition(0); + return; + } + if (index >= 0 && index < items.size()) { + messageListView.scrollToPosition(adapter.getHeaderLayoutCount()+index); + messageListView.post(() -> { + RecyclerView.LayoutManager layoutManager = messageListView.getLayoutManager(); + if (layoutManager != null) { + try { + View view = layoutManager.findViewByPosition(index); + RelativeLayout relativeLayout = (RelativeLayout) view; //获取布局中任意控件对象 + FrameLayout frameLayout = null; + if (relativeLayout != null) { + frameLayout = relativeLayout.findViewById(R.id.message_item_content); + } + if (frameLayout != null) { + //透明度起始为1,结束时为0 + ObjectAnimator animator = ObjectAnimator.ofFloat(frameLayout, "alpha", 0f, 1f); + animator.setDuration(1000);//时间1s + animator.setRepeatCount(1); + animator.setRepeatMode(ValueAnimator.RESTART); + animator.start(); + + isShowAnim = true; + } + }catch (Exception e){ + e.printStackTrace(); + } + } + }); + } + } + }, 500); + } + + private void onAnchorContextMessageLoaded(final List messages) { + if (messages == null) { + return; + } + + if (remote) { + Collections.reverse(messages); + } + + int loadCount = messages.size(); + if (firstLoad && anchor != null) { + messages.add(0, anchor); + } + + // 在更新前,先确定一些标记 + adapter.updateShowTimeItem(messages, true, firstLoad); // 更新要显示时间的消息 + updateReceipt(messages); // 更新已读回执标签 + + // new data + if (loadCount < loadMsgCount) { + adapter.loadMoreEnd(messages, true); + } else { + adapter.appendData(messages); + } + + firstLoad = false; + } + + @Override + public void onFetchMoreRequested() { + // 顶部加载历史数据 + if (remote) { + loadFromRemote(); + } else { + loadFromLocal(QueryDirectionEnum.QUERY_OLD); + } + } + + @Override + public void onLoadMoreRequested() { + // 底部加载新数据 + if (!remote) { + loadFromLocal(QueryDirectionEnum.QUERY_NEW); + } + } + } + + private class MsgItemEventListener implements MsgAdapter.ViewHolderEventListener { + + @Override + public void onFailedBtnClick(IMMessage message) { + if (message.getDirect() == MsgDirectionEnum.Out) { + // 发出的消息,如果是发送失败,直接重发,否则有可能是漫游到的多媒体消息,但文件下载 + if (message.getStatus() == MsgStatusEnum.fail) { + if (AntiSpamUtil.isAntiSpam(message)) { + return; + } + resendMessage(message); // 重发 + } else { + if (message.getAttachment() instanceof FileAttachment) { + FileAttachment attachment = (FileAttachment) message.getAttachment(); + if (TextUtils.isEmpty(attachment.getPath()) + && TextUtils.isEmpty(attachment.getThumbPath())) { + showReDownloadConfirmDlg(message); + } + } else { + resendMessage(message); + } + } + } else { + showReDownloadConfirmDlg(message); + } + } + + @Override + public boolean onViewHolderLongClick(View clickView, View viewHolderView, IMMessage item) { + if (container.proxy.isLongClickEnabled()) { + showLongClickAction(item); + } + return true; + } + + @Override + public void onFooterClick(IMMessage message) { + // 与 robot 对话 + container.proxy.onItemFooterClick(message); + } + + // 重新下载(对话框提示) + private void showReDownloadConfirmDlg(final IMMessage message) { + EasyAlertDialogHelper.OnDialogActionListener listener = new EasyAlertDialogHelper.OnDialogActionListener() { + + @Override + public void doCancelAction() { + } + + @Override + public void doOkAction() { + // 正常情况收到消息后附件会自动下载。如果下载失败,可调用该接口重新下载 + if (message.getAttachment() != null && message.getAttachment() instanceof FileAttachment) + NIMClient.getService(MsgService.class).downloadAttachment(message, true); + } + }; + + final EasyAlertDialog dialog = EasyAlertDialogHelper.createOkCancelDiolag(container.activity, null, + container.activity.getString(R.string.repeat_download_message), true, listener); + dialog.show(); + } + + // 重发消息到服务器 + private void resendMessage(IMMessage message) { + // 重置状态为unsent + int index = getItemIndex(message.getUuid()); + if (index >= 0 && index < items.size()) { + IMMessage item = items.get(index); + item.setStatus(MsgStatusEnum.sending); + deleteItem(item, true); + onMsgSend(item); + } + + NIMClient.getService(MsgService.class) + .sendMessage(message, true) + .setCallback(new RequestCallbackWrapper() { + @Override + public void onResult(int code, Void result, Throwable exception) { + } + }); + } + + /** + * ****************************** 长按菜单 ******************************** + */ + + // 长按消息Item后弹出菜单控制 + private void showLongClickAction(IMMessage selectedItem) { + onNormalLongClick(selectedItem); + } + + /** + * 长按菜单操作 + * + * @param item + */ + private void onNormalLongClick(IMMessage item) { + CustomAlertDialog alertDialog = new CustomAlertDialog(container.activity); + alertDialog.setCancelable(true); + alertDialog.setCanceledOnTouchOutside(true); + + prepareDialogItems(item, alertDialog); + alertDialog.show(); + } + + // 长按消息item的菜单项准备。如果消息item的MsgViewHolder处理长按事件(MsgViewHolderBase#onItemLongClick),且返回为true, + // 则对应项的长按事件不会调用到此处 + private void prepareDialogItems(final IMMessage selectedItem, CustomAlertDialog alertDialog) { + MsgTypeEnum msgType = selectedItem.getMsgType(); + + MessageAudioControl.getInstance(container.activity).stopAudio(); + + // 0 EarPhoneMode + longClickItemEarPhoneMode(alertDialog, msgType); + // 1 resend + longClickItemResend(selectedItem, alertDialog); + // 2 copy + longClickItemCopy(selectedItem, alertDialog, msgType); + // 3 revoke + if (enableRevokeButton(selectedItem)) { + longClickRevokeMsg(selectedItem, alertDialog); + } + // 4 delete + longClickItemDelete(selectedItem, alertDialog); + // 5 trans + longClickItemVoidToText(selectedItem, alertDialog, msgType); + + if (NimUIKitImpl.getMsgForwardFilter() != null && !NimUIKitImpl.getMsgForwardFilter().shouldIgnore(selectedItem) && !recordOnly) { + // 6 forward to person + longClickItemForwardToPerson(selectedItem, alertDialog); + // 7 forward to team + longClickItemForwardToTeam(selectedItem, alertDialog); + } + } + + private boolean enableRevokeButton(IMMessage selectedItem) { + if (selectedItem.getStatus() == MsgStatusEnum.success + && NimUIKitImpl.getMsgRevokeFilter() != null + && !NimUIKitImpl.getMsgRevokeFilter().shouldIgnore(selectedItem) + && !recordOnly) { + if (selectedItem.getDirect() == MsgDirectionEnum.Out) { + return true; + } else if (NimUIKit.getOptions().enableTeamManagerRevokeMsg && selectedItem.getSessionType() == SessionTypeEnum.Team) { + TeamMember member = NimUIKit.getTeamProvider().getTeamMember(selectedItem.getSessionId(), NimUIKit.getAccount()); + return member != null && member.getType() == TeamMemberType.Owner || member.getType() == TeamMemberType.Manager; + } + } + return false; + } + + // 长按菜单项--重发 + private void longClickItemResend(final IMMessage item, CustomAlertDialog alertDialog) { + if (item.getStatus() != MsgStatusEnum.fail) { + return; + } + alertDialog.addItem(container.activity.getString(R.string.repeat_send_has_blank), new CustomAlertDialog.onSeparateItemClickListener() { + + @Override + public void onClick() { + onResendMessageItem(item); + } + }); + } + + private void onResendMessageItem(IMMessage message) { + int index = getItemIndex(message.getUuid()); + if (index >= 0) { + showResendConfirm(message, index); // 重发确认 + } + } + + private void showResendConfirm(final IMMessage message, final int index) { + EasyAlertDialogHelper.OnDialogActionListener listener = new EasyAlertDialogHelper.OnDialogActionListener() { + + @Override + public void doCancelAction() { + } + + @Override + public void doOkAction() { + resendMessage(message); + } + }; + final EasyAlertDialog dialog = EasyAlertDialogHelper.createOkCancelDiolag(container.activity, null, + container.activity.getString(R.string.repeat_send_message), true, listener); + dialog.show(); + } + + // 长按菜单项--复制 + private void longClickItemCopy(final IMMessage item, CustomAlertDialog alertDialog, MsgTypeEnum msgType) { + if (msgType == MsgTypeEnum.text || + (msgType == MsgTypeEnum.robot && item.getAttachment() != null && !((RobotAttachment) item.getAttachment()).isRobotSend())) { + alertDialog.addItem(container.activity.getString(R.string.copy_has_blank), new CustomAlertDialog.onSeparateItemClickListener() { + + @Override + public void onClick() { + onCopyMessageItem(item); + } + }); + } + } + + private void onCopyMessageItem(IMMessage item) { + ClipboardUtil.clipboardCopyText(container.activity, item.getContent()); + } + + // 长按菜单项--删除 + private void longClickItemDelete(final IMMessage selectedItem, CustomAlertDialog alertDialog) { + if (recordOnly) { + return; + } + alertDialog.addItem(container.activity.getString(R.string.delete_has_blank), new CustomAlertDialog.onSeparateItemClickListener() { + + @Override + public void onClick() { + deleteItem(selectedItem, true); + } + }); + } + + // 长按菜单项 -- 音频转文字 + private void longClickItemVoidToText(final IMMessage item, CustomAlertDialog alertDialog, MsgTypeEnum msgType) { + if (msgType != MsgTypeEnum.audio) return; + + if (item.getDirect() == MsgDirectionEnum.In + && item.getAttachStatus() != AttachStatusEnum.transferred) + return; + if (item.getDirect() == MsgDirectionEnum.Out + && item.getAttachStatus() != AttachStatusEnum.transferred) + return; + + alertDialog.addItem(container.activity.getString(R.string.voice_to_text), new CustomAlertDialog.onSeparateItemClickListener() { + + @Override + public void onClick() { + onVoiceToText(item); + } + }); + } + + // 语音转文字 + private void onVoiceToText(IMMessage item) { + if (voiceTrans == null) + voiceTrans = new VoiceTrans(container.activity); + voiceTrans.voiceToText(item); + if (item.getDirect() == MsgDirectionEnum.In && item.getStatus() != MsgStatusEnum.read) { + item.setStatus(MsgStatusEnum.read); + NIMClient.getService(MsgService.class).updateIMMessageStatus(item); + adapter.notifyDataSetChanged(); + } + } + + // 长按菜单项 -- 听筒扬声器切换 + private void longClickItemEarPhoneMode(CustomAlertDialog alertDialog, MsgTypeEnum msgType) { + if (msgType != MsgTypeEnum.audio) return; + + String content = UserPreferences.isEarPhoneModeEnable() ? ResUtil.getString(R.string.ui_im_messagelistpanelex_05) : ResUtil.getString(R.string.ui_im_messagelistpanelex_06); + final String finalContent = content; + alertDialog.addItem(content, new CustomAlertDialog.onSeparateItemClickListener() { + + @Override + public void onClick() { +// Toast.makeText(container.activity, finalContent, Toast.LENGTH_SHORT).show(); + SingleToastUtil.showToastShort(finalContent); + setEarPhoneMode(!UserPreferences.isEarPhoneModeEnable(), true); + } + }); + } + + // 长按菜单项 -- 转发到个人 + private void longClickItemForwardToPerson(final IMMessage item, CustomAlertDialog alertDialog) { + alertDialog.addItem(container.activity.getString(R.string.forward_to_person), new CustomAlertDialog.onSeparateItemClickListener() { + + @Override + public void onClick() { + forwardMessage = item; + ContactSelectActivity.Option option = new ContactSelectActivity.Option(); + option.title = ResUtil.getString(R.string.ui_im_messagelistpanelex_07); + option.type = ContactSelectActivity.ContactSelectType.BUDDY; + option.multi = false; + option.maxSelectNum = 1; + NimUIKit.startContactSelector(container.activity, option, REQUEST_CODE_FORWARD_PERSON); + } + }); + } + + // 长按菜单项 -- 转发到群组 + private void longClickItemForwardToTeam(final IMMessage item, CustomAlertDialog alertDialog) { + alertDialog.addItem(container.activity.getString(R.string.forward_to_team), new CustomAlertDialog.onSeparateItemClickListener() { + + @Override + public void onClick() { + forwardMessage = item; + ContactSelectActivity.Option option = new ContactSelectActivity.Option(); + option.title = ResUtil.getString(R.string.ui_im_messagelistpanelex_08); + option.type = ContactSelectActivity.ContactSelectType.TEAM; + option.multi = false; + option.maxSelectNum = 1; + NimUIKit.startContactSelector(container.activity, option, REQUEST_CODE_FORWARD_TEAM); + } + }); + } + + // 长按菜单项 -- 撤回消息 + private void longClickRevokeMsg(final IMMessage item, CustomAlertDialog alertDialog) { + alertDialog.addItem(container.activity.getString(R.string.withdrawn_msg), new CustomAlertDialog.onSeparateItemClickListener() { + + @Override + public void onClick() { + if (!NetworkUtil.isNetAvailable(container.activity)) { +// Toast.makeText(container.activity, R.string.network_is_not_available, Toast.LENGTH_SHORT).show(); + SingleToastUtil.showToastShort(R.string.network_is_not_available); + return; + } + NIMClient.getService(MsgService.class).revokeMessage(item).setCallback(new RequestCallback() { + @Override + public void onSuccess(Void param) { + deleteItem(item, false); + MessageHelper.getInstance().onRevokeMessage(item, NimUIKit.getAccount()); + } + + @Override + public void onFailed(int code) { + if (code == ResponseCode.RES_OVERDUE) { +// Toast.makeText(container.activity, R.string.revoke_failed, Toast.LENGTH_SHORT).show(); + SingleToastUtil.showToastShort(R.string.revoke_failed); + } else { +// Toast.makeText(container.activity, "revoke msg failed, code:" + code, Toast.LENGTH_SHORT).show(); + SingleToastUtil.showToastShort("revoke msg failed, code:" + code); + } + } + + @Override + public void onException(Throwable exception) { + + } + }); + } + }); + } + + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/im/MsgViewHolderAitMe.java b/app/src/main/java/com/chwl/app/ui/im/MsgViewHolderAitMe.java new file mode 100644 index 0000000..cae2ea6 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/MsgViewHolderAitMe.java @@ -0,0 +1,55 @@ +package com.chwl.app.ui.im; + +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.style.ForegroundColorSpan; +import android.widget.TextView; + +import androidx.core.content.ContextCompat; + +import com.netease.nim.uikit.business.session.viewholder.MsgViewHolderBase; +import com.netease.nim.uikit.common.ui.recyclerview.adapter.BaseMultiItemFetchLoadAdapter; +import com.chwl.app.R; +import com.chwl.app.ui.im.RouterHandler; +import com.chwl.core.public_chat_hall.attachment.AitMeAttachment; +import com.chwl.core.public_chat_hall.bean.AitMeInfo; +import com.chwl.core.utils.StringFormatUtils; +import com.chwl.library.utils.ResUtil; + +public class MsgViewHolderAitMe extends MsgViewHolderBase { + + private TextView messageView; + + public MsgViewHolderAitMe(BaseMultiItemFetchLoadAdapter adapter) { + super(adapter); + } + + @Override + protected int getContentResId() { + return R.layout.view_holder_public_chat_hall_ait_friends; + } + + @Override + protected void inflateContentView() { + messageView = findViewById(R.id.nim_message_item_text_body); + } + + @Override + protected void bindContentView() { + if (message.getAttachment() != null) { + AitMeAttachment aitMeAttachment = (AitMeAttachment) message.getAttachment(); + AitMeInfo aitMeInfo = aitMeAttachment.getAitMeInfo(); + String content = message.getContent(); + if (StringFormatUtils.isEmpty(content)) { + content = aitMeInfo.getContent(); + } + SpannableStringBuilder builder = new SpannableStringBuilder(content); + int start = content.indexOf(ResUtil.getString(R.string.msg_viewholder_msgviewholderaitme_01)); + builder.setSpan(new ForegroundColorSpan(ContextCompat.getColor(context, R.color.color_FF3D56)), + start, start + 3, Spannable.SPAN_INCLUSIVE_INCLUSIVE); + messageView.setText(builder); + messageView.setOnClickListener(v -> RouterHandler.handle(context, aitMeInfo.getRouterType(), aitMeInfo.getRouterValue())); + } + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/im/RouterHandler.java b/app/src/main/java/com/chwl/app/ui/im/RouterHandler.java new file mode 100644 index 0000000..5989201 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/RouterHandler.java @@ -0,0 +1,321 @@ +package com.chwl.app.ui.im; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.Intent; + +import com.chwl.app.R; +import com.chwl.app.UIHelper; +import com.chwl.app.audio.VoiceMatchActivity; +import com.chwl.app.avroom.activity.AVRoomActivity; +import com.chwl.app.avroom.recommendcard.MyRecommendCardActivity; +import com.chwl.app.base.BaseActivity; +import com.chwl.app.base.DialogManagerInterface; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.app.decoration.ui.activity.DressUpTabActivity; +import com.chwl.app.earn.activity.EarnRecordActivity; +import com.chwl.app.home.activity.CollectionRoomActivity; +import com.chwl.app.home.activity.VisitorListActivity; +import com.chwl.app.home.helper.OpenRoomHelper; +import com.chwl.app.module_hall.HallDataManager; +import com.chwl.app.module_hall.hall.activity.ModuleClanActivity; +import com.chwl.app.module_hall.hall.activity.ModuleHallActivity; +import com.chwl.app.pay.activity.GiveGoldActivity; +import com.chwl.app.radish.task.activity.TaskCenterActivity; +import com.chwl.app.relation.cp.activity.CpHomeActivity; +import com.chwl.app.relation.cp.activity.CpInviteRecordActivity; +import com.chwl.app.relation.cp.activity.CpTaskActivity; +import com.chwl.app.team.view.NimTeamMessageActivity; +import com.chwl.app.ui.feedback.FeedbackActivity; +import com.chwl.app.ui.game_team.record.GameTeamRecordActivity; +import com.chwl.app.ui.login.BindPhoneActivity; +import com.chwl.app.ui.login.ShowBindPhoneActivity; +import com.chwl.app.ui.pay.ChargeActivity; +import com.chwl.app.ui.setting.ModifyPwdActivity; +import com.chwl.app.ui.user.activity.UserInfoActivity; +import com.chwl.app.ui.webview.CommonWebViewActivity; +import com.chwl.app.vip.VipCenterActivity; +import com.chwl.core.DemoCache; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.community.event.SquareTaskEvent; +import com.chwl.core.im.custom.bean.RouterType; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.module_hall.hall.HallModel; +import com.chwl.core.module_hall.hall.bean.H5FamilyInfo; +import com.chwl.core.module_hall.hall.bean.HallInfo; +import com.chwl.core.module_hall.hall.bean.UserClanInfo; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.core.room.model.AvRoomModel; +import com.chwl.core.utils.net.BeanObserver; +import com.chwl.core.utils.net.RxHelper; +import com.chwl.library.net.rxnet.callback.CallBack; +import com.chwl.library.utils.JavaUtil; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; +import com.trello.rxlifecycle3.components.support.RxAppCompatActivity; + +import org.greenrobot.eventbus.EventBus; + +import io.reactivex.SingleObserver; +import io.reactivex.disposables.Disposable; + +/** + * Created by MadisonRong on 08/06/2018. + */ + +public class RouterHandler { + + private static final String IS_FIRST = "isFirst"; + + private static final int TIME_DIFF = 600; + private static long lastClickTime; + + @SuppressLint("CheckResult") + public static boolean handle(Context context, int routerType, String routerValue) { + if (System.currentTimeMillis() - lastClickTime < TIME_DIFF) { + return false; + } + lastClickTime = System.currentTimeMillis(); + int intRouterValue = JavaUtil.str2int(routerValue); + DialogManagerInterface dmi; + switch (routerType) { + case RouterType.ROOM: + AVRoomActivity.start(context, JavaUtil.str2long(routerValue)); + break; + case RouterType.H5: + CommonWebViewActivity.start(context, routerValue); + break; + case RouterType.RECHARGE: +// if(AppMetaDataUtil.getChannelID().equals(Constants.GOOGLE)) { + ChargeActivity.start(context); +// }else { +// CommonWebViewActivity.start( +// context, UriProvider.getOfficialPay( +// 4, +// DeviceUtil.getDeviceId(context) +// ) +// ); +// } + break; + case RouterType.PERSON: + UserInfoActivity.Companion.start(context, JavaUtil.str2long(routerValue)); + break; + case RouterType.CAR: + if (JavaUtil.str2int(routerValue) == 0) { + DressUpTabActivity.Companion.start(context,false); + } else { + DressUpTabActivity.Companion.start(context,true); + } + break; + case RouterType.DECORATION: + if (JavaUtil.str2int(routerValue) == 0) { + DressUpTabActivity.Companion.start(context,false); + } else { + DressUpTabActivity.Companion.start(context,true); + } + break; + case RouterType.NAMEPLATE: + if (JavaUtil.str2int(routerValue) == 0) { + DressUpTabActivity.Companion.start(context,false); + } else { + DressUpTabActivity.Companion.start(context,true); + } + break; + case RouterType.USER_CARD_WEAR: + DressUpTabActivity.Companion.start(context,true); + break; + case RouterType.TEAM: + NimTeamMessageActivity.start(context, routerValue); + break; + case RouterType.BINDING_PHONE: + AuthModel.get().isBindPhone() + .subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onSuccess(String s) { + ShowBindPhoneActivity.start(context); + } + + @Override + public void onError(Throwable e) { + BindPhoneActivity.start(context); + } + }); + break; + + case RouterType.SETTING_PAY_PWD: + ModifyPwdActivity.start(context, ModifyPwdActivity.PAY_PWD); + break; + //推荐卡仓库 + case RouterType.MY_RECOMMEND: + MyRecommendCardActivity.start(context); + break; + case RouterType.MODULE_HALL_HOME: + DialogManager manager = new DialogManager(context); + manager.showProgressDialog(context); + HallModel.get().getHallInfo(AuthModel.get().getCurrentUid(), JavaUtil.str2long(routerValue)) + .compose(RxHelper.bindContext(context)) + .doAfterTerminate(manager::dismissDialog) + .subscribe(new BeanObserver() { + @Override + public void onErrorMsg(String error) { + + } + + @Override + public void onSuccess(HallInfo hallInfo) { + ModuleHallActivity.start(context); + } + }); + break; + case RouterType.DO_TASK: + TaskCenterActivity.start(context, TaskCenterActivity.FromPage.FIND); + break; + case RouterType.GAME_LIST: + break; + case RouterType.PERSION_SETTING: + UIHelper.showUserInfoModifyAct(context, JavaUtil.str2long(routerValue)); + break; + case RouterType.VOICE_BOTTLE_PAGE: + VoiceMatchActivity.start(context); + break; + //异性匹配 + case RouterType.OPPOSITE_SEX_MATCHING: + if (!(context instanceof DialogManagerInterface) || !(context instanceof RxAppCompatActivity)) { + return false; + } + dmi = (DialogManagerInterface) context; + if (AvRoomDataManager.get().isRoomOwner() + && AvRoomDataManager.get().isCpRoom() + && DemoCache.readBoolean(IS_FIRST, true)) { + DemoCache.saveBoolean(IS_FIRST, false); + dmi.getDialogManager().showOkCancelDialog(ResUtil.getString(R.string.ui_im_routerhandler_02), true, + () -> showSexMatchDialog(context)); + } else { + showSexMatchDialog(context); + } + break; + case RouterType.CITY_MATCHING: + SingleToastUtil.showToast(ResUtil.getString(R.string.ui_im_routerhandler_04)); + break; + case RouterType.GAME_MATCHING: + break; + case RouterType.SQUARE_PUBLISH: + EventBus.getDefault().post(new SquareTaskEvent()); + break; + + case RouterType.FEED_BACK: + context.startActivity(new Intent(context, FeedbackActivity.class)); + break; + case RouterType.SET_PASSWORD: + ModifyPwdActivity.start(context, ModifyPwdActivity.LOGIN_PWD); + break; + case RouterType.VIP_MAIN: + VipCenterActivity.start(context); + break; + case RouterType.CP_INVITE: + CpInviteRecordActivity.Companion.start(context, false); + break; + case RouterType.CP_TASK: + CpTaskActivity.Companion.start(context); + break; + case RouterType.CP_WARE: + DressUpTabActivity.Companion.start(context,true); + break; + case RouterType.USER_BUBBLE: + DressUpTabActivity.Companion.start(context,true); + break; + case RouterType.MY_ROOM: + //我的房间,开房 + OpenRoomHelper.openRoom((BaseActivity) context); + break; + case RouterType.COLLECTION_ROOM: + //收藏的房间 + CollectionRoomActivity.start(context); + break; + case RouterType.MODULE_CLAN: + //公会或房间主页 + UserClanInfo info = HallDataManager.get().getUserClanInfo(); + H5FamilyInfo familyInfo = null; + if (info != null) { + familyInfo = info.asFamily(); + } + if (familyInfo != null) { + if (familyInfo.getFamilyId() != null && familyInfo.getFamilyId() > 0) { + CommonWebViewActivity.start(context, familyInfo.getFullMyFamilyUrl()); + } else { + CommonWebViewActivity.start(context, familyInfo.getFullFamilyListUrl()); + } + } else { + if (HallDataManager.get().isHasClan()) { + ModuleClanActivity.start(context); + } else if (HallDataManager.get().hasLiveHall()) { + ModuleHallActivity.start(context); + } else { + SingleToastUtil.showToast(ResUtil.getString(R.string.ui_im_routerhandler_06)); + } + } + break; +// case RouterType.PATRIARCH_MODE: +// //青少年模式 +// PatriarchModeActivity.start(context); +// break; + case RouterType.VISITOR_LIST: + //访客记录 + VisitorListActivity.start(context); + break; + case RouterType.CP_HOME: + //CP主页 + CpHomeActivity.Companion.start(context); + break; + case RouterType.DECORATION_STORE: + if (intRouterValue < 0 || intRouterValue > 4) { + intRouterValue = 0; + } + DressUpTabActivity.Companion.start(context,false); + break; + case RouterType.MY_DECORATION: + if (intRouterValue < 0 || intRouterValue > 4) { + intRouterValue = 0; + } + DressUpTabActivity.Companion.start(context,true); + break; + case RouterType.MY_SET: + UIHelper.showSettingAct(context); + break; + case RouterType.MY_REVENUE: + EarnRecordActivity.start(context); + break; + case RouterType.MY_DONATION: + GiveGoldActivity.Companion.start(context); + break; + case RouterType.GAME_TEAM_RECORD: + GameTeamRecordActivity.Companion.start(context); + break; + case RouterType.MY_DRESS_ITEM: + DressUpTabActivity.Companion.start(context,true); + break; + default: + SingleToastUtil.showToast(ResUtil.getString(R.string.ui_im_routerhandler_07)); + return false; + } + return true; + } + + private static void showSexMatchDialog(Context context) { + AvRoomModel.get().exitRoom(new CallBack() { + @Override + public void onSuccess(RoomInfo data) { + } + + @Override + public void onFail(int code, String error) { + } + }); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/im/actions/ChatterBoxAction.java b/app/src/main/java/com/chwl/app/ui/im/actions/ChatterBoxAction.java new file mode 100644 index 0000000..afb2c6f --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/actions/ChatterBoxAction.java @@ -0,0 +1,42 @@ +package com.chwl.app.ui.im.actions; + +import android.os.Handler; + +import com.netease.nim.uikit.business.session.actions.BaseAction; +import com.chwl.app.R; +import com.chwl.app.ui.widget.higuide.TuTuGuideHelper; +import com.chwl.core.im.chatterbox.ChatterBoxHelper; +import com.chwl.core.im.chatterbox.HideInputEvent; + +import org.greenrobot.eventbus.EventBus; + +public class ChatterBoxAction extends BaseAction { + + private long lastClick = 0L; + public static String sessionId; + + public ChatterBoxAction() { + super(R.drawable.chat_icon_say, R.string.chat_action); + } + + @Override + public void onClick() { + long currentClick = System.currentTimeMillis(); + + if (currentClick - lastClick > 1000L) { + + EventBus.getDefault().post(new HideInputEvent()); + lastClick = currentClick; + + if (TuTuGuideHelper.isNeedHiGuide(TuTuGuideHelper.KEY_GUIDE_CHATTER_BOX)) { + new Handler().post(() -> { + TuTuGuideHelper helper = new TuTuGuideHelper(getActivity()); + helper.createHiGuide(() -> helper.createDiceOverLayer()); + TuTuGuideHelper.setNoNeedHiGuide(TuTuGuideHelper.KEY_GUIDE_CHATTER_BOX); + }); + } + ChatterBoxHelper.topicBoxCanSend(); + + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/im/actions/FamilyGameAction.java b/app/src/main/java/com/chwl/app/ui/im/actions/FamilyGameAction.java new file mode 100644 index 0000000..d8ba129 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/actions/FamilyGameAction.java @@ -0,0 +1,29 @@ +package com.chwl.app.ui.im.actions; + +import com.netease.nim.uikit.business.session.actions.BaseAction; +import com.chwl.app.R; + +/** + * Created by MadisonRong on 29/05/2018. + */ + +public class FamilyGameAction extends BaseAction { + + public FamilyGameAction() { + this(R.drawable.icon_family_game_action, R.string.action_family_game); + } + + /** + * 构造函数 + * + * @param iconResId 图标 res id + * @param titleId 图标标题的string res id + */ + protected FamilyGameAction(int iconResId, int titleId) { + super(iconResId, titleId); + } + + @Override + public void onClick() { + } +} diff --git a/app/src/main/java/com/chwl/app/ui/im/actions/GiftAction.java b/app/src/main/java/com/chwl/app/ui/im/actions/GiftAction.java new file mode 100644 index 0000000..3dfecc3 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/actions/GiftAction.java @@ -0,0 +1,75 @@ +package com.chwl.app.ui.im.actions; + +import android.annotation.SuppressLint; + +import com.netease.nim.uikit.business.session.actions.BaseAction; +import com.netease.nim.uikit.business.session.helper.MessageListPanelHelper; +import com.chwl.app.R; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.app.ui.widget.GiftDialog; +import com.chwl.core.gift.GiftModel; +import com.chwl.core.gift.bean.GiftInfo; +import com.chwl.core.gift.toolbox.GiftToolbox; +import com.chwl.core.room.queue.bean.MicMemberInfo; +import com.chwl.core.utils.net.VipLevelNotEnoughException; +import com.chwl.library.utils.ResUtil; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by xiaoyu + * on 2017/10/2. + */ + +public class GiftAction extends BaseAction implements GiftDialog.OnGiftDialogBtnClickListener { + + + transient private GiftDialog giftDialog; + + public GiftAction() { + super(R.drawable.icon_gift_action, R.string.gift_action); + } + + @Override + public void onClick() { + if (giftDialog == null) { + GiftDialog.GIFT_DIALOG_FROM = ResUtil.getString(R.string.im_actions_giftaction_01); + + giftDialog = new GiftDialog(getActivity(), Long.valueOf(getAccount()), false, false, true); + giftDialog.setGiftDialogBtnClickListener(this); + giftDialog.setOnDismissListener(dialog -> giftDialog = null); + } + if (!giftDialog.isShowing()) { + giftDialog.show(); + } + } + + @SuppressLint("CheckResult") + @Override + public void onSendGiftBtnClick(GiftInfo giftInfo, ArrayList micMemberInfos, int number, String msg, boolean isknap, boolean isWholeMic, List> drawFixedArray, GiftDialog.SenGiftCallback callback) { + if (giftInfo == null) return; + GiftModel.get().sendPersonalGift(giftInfo.getGiftId(), micMemberInfos.get(0).getAccount(), number, msg, isknap) + .doOnError(throwable -> { + if (callback != null) { + callback.onFail(); + } + if (throwable instanceof VipLevelNotEnoughException) { + new DialogManager(getActivity()).showOkDialog(ResUtil.getString(R.string.im_actions_giftaction_02) + + giftInfo.getGiftName() + + ResUtil.getString(R.string.im_actions_giftaction_03) + + giftInfo.getGiftVipInfo().getVipName()); + } + }) + .flatMap(serviceResult -> GiftToolbox.sendGiftPrivateChatMessage(serviceResult.getData())) + .subscribe(imMessage -> { + // 手动更新送礼物的消息 + MessageListPanelHelper.getInstance().notifyAddMessage(imMessage); + if (callback != null) { + callback.onSuccess(); + } + }); + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/im/actions/GiftActionEvent.java b/app/src/main/java/com/chwl/app/ui/im/actions/GiftActionEvent.java new file mode 100644 index 0000000..afb0a28 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/actions/GiftActionEvent.java @@ -0,0 +1,43 @@ +package com.chwl.app.ui.im.actions; + +import java.io.Serializable; + +/** + * Created by chenran on 2017/11/14. + */ + +public class GiftActionEvent implements Serializable { + public GiftActionEvent() { + + } + + public void onGiftActionEvent(long uid) { + + } + +// +// @Override +// public int describeContents() { +// return 0; +// } +// +// @Override +// public void writeToParcel(Parcel dest, int flags) { +// // 序列化过程:必须按成员变量声明的顺序进行封装 +// } +// +// // 反序列过程:必须实现Parcelable.Creator接口,并且对象名必须为CREATOR +// // 读取Parcel里面数据时必须按照成员变量声明的顺序,Parcel数据来源上面writeToParcel方法,读出来的数据供逻辑层使用 +// public static final Parcelable.Creator CREATOR = new Creator() { +// +// @Override +// public GiftActionEvent createFromParcel(Parcel source) { +// return new GiftActionEvent(); +// } +// +// @Override +// public GiftActionEvent[] newArray(int size) { +// return new GiftActionEvent[size]; +// } +// }; +} diff --git a/app/src/main/java/com/chwl/app/ui/im/actions/LuckyMoneyAction.java b/app/src/main/java/com/chwl/app/ui/im/actions/LuckyMoneyAction.java new file mode 100644 index 0000000..943eb2a --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/actions/LuckyMoneyAction.java @@ -0,0 +1,31 @@ +package com.chwl.app.ui.im.actions; + +import com.netease.nim.uikit.business.session.actions.BaseAction; +import com.chwl.app.R; +import com.chwl.app.luckymoney.view.LuckyMoneyCreationActivity; + +/** + * Created by MadisonRong on 29/05/2018. + */ + +public class LuckyMoneyAction extends BaseAction { + + public LuckyMoneyAction() { + this(R.drawable.icon_lucky_money_action, R.string.action_red_packet); + } + + /** + * 构造函数 + * + * @param iconResId 图标 res id + * @param titleId 图标标题的string res id + */ + protected LuckyMoneyAction(int iconResId, int titleId) { + super(iconResId, titleId); + } + + @Override + public void onClick() { + LuckyMoneyCreationActivity.start(getActivity()); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/im/audio/ShakeHeartDialogFragment.java b/app/src/main/java/com/chwl/app/ui/im/audio/ShakeHeartDialogFragment.java new file mode 100644 index 0000000..db47dab --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/audio/ShakeHeartDialogFragment.java @@ -0,0 +1,174 @@ +package com.chwl.app.ui.im.audio; + +import android.app.Dialog; +import android.content.Context; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.view.animation.AlphaAnimation; +import android.view.animation.Animation; +import android.view.animation.AnimationSet; +import android.view.animation.LinearInterpolator; +import android.view.animation.RotateAnimation; +import android.view.animation.ScaleAnimation; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.DialogFragment; + +import com.chwl.app.R; + +public class ShakeHeartDialogFragment extends DialogFragment { + + public static final String KEY_SHAKE_HEART_HINT = "key_shake_heart"; + private String textHint; + + public static ShakeHeartDialogFragment newInstance(String textHint) { + + Bundle args = new Bundle(); + args.putString(KEY_SHAKE_HEART_HINT, textHint); + ShakeHeartDialogFragment fragment = new ShakeHeartDialogFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + if (getArguments() != null) { + textHint = getArguments().getString(KEY_SHAKE_HEART_HINT); + } else { + textHint = ""; + } + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);// 去掉标题 + return inflater.inflate(R.layout.fragment_shake_heart, container); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + TextView tvHint = view.findViewById(R.id.tv_heart_hint); + tvHint.setText(textHint); + + ImageView ivHeart = view.findViewById(R.id.iv_heart); + + // 缩放动画 + Animation scaleAnimation1 = new ScaleAnimation(0, 1.2f, 0, 1.2f, + Animation.RELATIVE_TO_SELF, 0.5f, + Animation.RELATIVE_TO_SELF, 0.5f); + scaleAnimation1.setInterpolator(new LinearInterpolator()); + scaleAnimation1.setDuration(250); + scaleAnimation1.setFillAfter(true);// 动画播放完毕后,是否会停止在动画结束的状态 + Animation scaleAnimation2 = new ScaleAnimation(1.2f, 1, 1.2f, 1, + Animation.RELATIVE_TO_SELF, 0.5f, + Animation.RELATIVE_TO_SELF, 0.5f); + scaleAnimation2.setInterpolator(new LinearInterpolator()); + scaleAnimation2.setStartOffset(250); + scaleAnimation2.setDuration(250); + scaleAnimation2.setFillAfter(true);// 动画播放完毕后,是否会停止在动画结束的状态 + // 晃动动画 + Animation rotateAnimation1 = new RotateAnimation(0, -10, + Animation.RELATIVE_TO_SELF, 0.5f, + Animation.RELATIVE_TO_SELF, 0.5f); + rotateAnimation1.setInterpolator(new LinearInterpolator()); + rotateAnimation1.setStartOffset(650); + rotateAnimation1.setDuration(300); + rotateAnimation1.setFillAfter(true); + Animation rotateAnimation2 = new RotateAnimation(-10, 20, + Animation.RELATIVE_TO_SELF, 0.5f, + Animation.RELATIVE_TO_SELF, 0.5f); + rotateAnimation2.setInterpolator(new LinearInterpolator()); + rotateAnimation2.setStartOffset(950); + rotateAnimation2.setDuration(100); + rotateAnimation2.setFillAfter(true); + Animation rotateAnimation3 = new RotateAnimation(10, -20, + Animation.RELATIVE_TO_SELF, 0.5f, + Animation.RELATIVE_TO_SELF, 0.5f); + rotateAnimation3.setInterpolator(new LinearInterpolator()); + rotateAnimation3.setStartOffset(1050); + rotateAnimation3.setDuration(100); + rotateAnimation3.setFillAfter(true); + Animation rotateAnimation4 = new RotateAnimation(-10, 20, + Animation.RELATIVE_TO_SELF, 0.5f, + Animation.RELATIVE_TO_SELF, 0.5f); + rotateAnimation4.setInterpolator(new LinearInterpolator()); + rotateAnimation4.setStartOffset(1150); + rotateAnimation4.setDuration(100); + rotateAnimation4.setFillAfter(true); + Animation rotateAnimation5 = new RotateAnimation(10, -10, + Animation.RELATIVE_TO_SELF, 0.5f, + Animation.RELATIVE_TO_SELF, 0.5f); + rotateAnimation5.setInterpolator(new LinearInterpolator()); + rotateAnimation5.setStartOffset(1250); + rotateAnimation5.setDuration(100); + rotateAnimation5.setFillAfter(true); + Animation alphaAnimation = new AlphaAnimation(1, 0); + alphaAnimation.setInterpolator(new LinearInterpolator()); + alphaAnimation.setStartOffset(1350); + alphaAnimation.setDuration(1000); + alphaAnimation.setFillAfter(true); + // 动画集 + AnimationSet animationSet = new AnimationSet(false); + animationSet.addAnimation(scaleAnimation1); + animationSet.addAnimation(scaleAnimation2); + animationSet.addAnimation(rotateAnimation1); + animationSet.addAnimation(rotateAnimation2); + animationSet.addAnimation(rotateAnimation3); + animationSet.addAnimation(rotateAnimation4); + animationSet.addAnimation(rotateAnimation5); + animationSet.addAnimation(alphaAnimation); + animationSet.setAnimationListener(new Animation.AnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + + } + + @Override + public void onAnimationEnd(Animation animation) { + dismiss(); + } + + @Override + public void onAnimationRepeat(Animation animation) { + + } + }); + ivHeart.startAnimation(animationSet); + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setStyle(DialogFragment.STYLE_NO_TITLE, R.style.FullScreenDialog); + } + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + Dialog dialog = super.onCreateDialog(savedInstanceState); + Window window = dialog.getWindow(); + WindowManager.LayoutParams params; + if (window != null) { + params = window.getAttributes(); + params.gravity = Gravity.CENTER; + params.width = ViewGroup.LayoutParams.MATCH_PARENT; + params.height = ViewGroup.LayoutParams.MATCH_PARENT; + window.setAttributes(params); + window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); + } + return dialog; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/im/avtivity/AddBlackListActivity.java b/app/src/main/java/com/chwl/app/ui/im/avtivity/AddBlackListActivity.java new file mode 100644 index 0000000..fd4a4d9 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/avtivity/AddBlackListActivity.java @@ -0,0 +1,155 @@ +package com.chwl.app.ui.im.avtivity; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.netease.nim.uikit.StatusBarUtil; +import com.netease.nim.uikit.business.session.constant.Extras; +import com.chwl.app.R; +import com.chwl.app.UIHelper; +import com.chwl.app.base.BaseMvpActivity; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.app.ui.user.activity.UserInfoActivity; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.app.utils.RegexUtil; +import com.chwl.core.XConstants; +import com.chwl.core.user.UserModel; +import com.chwl.library.base.factory.CreatePresenter; +import com.chwl.library.utils.JavaUtil; +import com.chwl.library.utils.ResUtil; + +import java.util.List; + +/** + * @author Administrator + * @date 2018/1/27 + */ +@CreatePresenter(AddBlackListPresenter.class) +public class AddBlackListActivity extends BaseMvpActivity + implements IAddBlackListView, View.OnClickListener { + + private String account; + private RelativeLayout rlContent; + private TextView tvAddBlackList; + private TextView tvName; + private ImageView ivAvatar; + + public static void start(Context context, String contactId) { + Intent intent = new Intent(); + intent.putExtra(Extras.EXTRA_ACCOUNT, contactId); + intent.setClass(context, AddBlackListActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); + context.startActivity(intent); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_nim_add_black_list); + account = getIntent().getStringExtra(Extras.EXTRA_ACCOUNT); + if (TextUtils.isEmpty(account)) account = "0"; + rlContent = findViewById(R.id.rl_content); + tvName = findViewById(R.id.tv_name); + tvAddBlackList = findViewById(R.id.tv_add_black_list); + ivAvatar = findViewById(R.id.iv_avatar); + rlContent.setOnClickListener(this); + tvAddBlackList.setOnClickListener(this); + findViewById(R.id.tv_report).setOnClickListener(this); + List blackListAccount = NimFriendModel.get().getMyBlackListAccount(); + if (blackListAccount != null) + changeText(blackListAccount.contains(account)); + initTarget(); + + } + + void changeText(boolean contains) { + tvAddBlackList.setText(contains ? ResUtil.getString(R.string.im_avtivity_addblacklistactivity_01) : ResUtil.getString(R.string.im_avtivity_addblacklistactivity_02)); + initWhiteTitleBar(contains ? ResUtil.getString(R.string.im_avtivity_addblacklistactivity_03) : ResUtil.getString(R.string.im_avtivity_addblacklistactivity_04)); + } + + /** + * 初始化目标的信息 + */ + @SuppressLint("CheckResult") + private void initTarget() { + UserModel.get().getUserInfo(Long.valueOf(account)).subscribe(userInfo -> { + // 头像 + ImageLoadUtils.loadAvatar(AddBlackListActivity.this, userInfo.getAvatar(), ivAvatar); + // 名字 + tvName.setText(RegexUtil.getPrintableString(userInfo.getNick())); + }); + + } + + @Override + public void onClick(View v) { + if (v.getId() == R.id.rl_content) { + if (!TextUtils.isEmpty(account)) + UserInfoActivity.Companion.start(this, Long.parseLong(account)); + } else if (v.getId() == R.id.tv_add_black_list) { + try { + boolean contains = NimFriendModel.get().getMyBlackListAccount().contains(account); + if (!contains){ + ensureAddToBlackList(); + } else{ + ensureRemoveFromBlackList(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } else if (v.getId() == R.id.tv_report) { + UIHelper.showReportPage(context, JavaUtil.str2long(account), XConstants.REPORT_TYPE_CHAT); + } + } + + private void ensureRemoveFromBlackList() { + getDialogManager().showOkCancelDialog(ResUtil.getString(R.string.im_avtivity_addblacklistactivity_05), true, + new DialogManager.AbsOkDialogListener() { + @Override + public void onOk() { + getMvpPresenter().removeFromBlackList(account); + } + }); + } + + private void ensureAddToBlackList() { + getDialogManager().showOkCancelDialog(ResUtil.getString(R.string.im_avtivity_addblacklistactivity_06), true, + new DialogManager.AbsOkDialogListener() { + @Override + public void onOk() { + getMvpPresenter().addToBlackList(account); + } + }); + } + + @Override + public void addToBlackListSuccessOrNot(boolean success) { + changeText(success); + toast(success ? ResUtil.getString(R.string.im_avtivity_addblacklistactivity_07) : ResUtil.getString(R.string.im_avtivity_addblacklistactivity_08)); + } + + @Override + public void removeFromBlackListSuccessOrNot(boolean success) { + changeText(!success); + toast(success ? ResUtil.getString(R.string.im_avtivity_addblacklistactivity_09) : ResUtil.getString(R.string.im_avtivity_addblacklistactivity_010)); + } + + @Override + protected boolean needSteepStateBar() { + return true; + } + + @Override + protected void setStatusBar() { + super.setStatusBar(); + StatusBarUtil.transparencyBar(this); + StatusBarUtil.StatusBarLightMode(this); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/im/avtivity/AddBlackListPresenter.java b/app/src/main/java/com/chwl/app/ui/im/avtivity/AddBlackListPresenter.java new file mode 100644 index 0000000..df20d71 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/avtivity/AddBlackListPresenter.java @@ -0,0 +1,29 @@ +package com.chwl.app.ui.im.avtivity; + + +import com.chwl.app.base.BaseMvpPresenter; + +/** + * @author Administrator + * @date 2018/1/27 + */ + +public class AddBlackListPresenter extends BaseMvpPresenter { + private NimFriendModel model; + + public AddBlackListPresenter() { + model = NimFriendModel.get(); + } + + void addToBlackList(String targetUid) { + model.addToBlackList(targetUid).subscribe((aBoolean, throwable) -> { + getMvpView().addToBlackListSuccessOrNot(throwable == null); + }); + } + + void removeFromBlackList(String targetUid) { + model.removeFromBlackList(targetUid).subscribe((aBoolean, throwable) -> { + getMvpView().removeFromBlackListSuccessOrNot(throwable == null); + }); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/im/avtivity/BaseMessageActivity.java b/app/src/main/java/com/chwl/app/ui/im/avtivity/BaseMessageActivity.java new file mode 100644 index 0000000..e6579a6 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/avtivity/BaseMessageActivity.java @@ -0,0 +1,205 @@ +package com.chwl.app.ui.im.avtivity; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; + +import androidx.appcompat.widget.Toolbar; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; + +import com.netease.nim.uikit.R; +import com.netease.nim.uikit.api.model.session.SessionCustomization; +import com.netease.nim.uikit.business.session.constant.Extras; +import com.netease.nim.uikit.business.session.fragment.MessageFragment; +import com.netease.nim.uikit.common.activity.ToolBarOptions; +import com.netease.nim.uikit.common.fragment.TFragment; +import com.netease.nim.uikit.common.util.sys.ScreenUtil; +import com.chwl.app.base.BaseActivity; + +import java.util.List; + +/** + * Created by zhoujianghua on 2015/9/10. + */ +public abstract class BaseMessageActivity extends BaseActivity { + + private static final String TAG = "BaseMessageActivity"; + + protected String sessionId; + + private SessionCustomization customization; + + private MessageFragment messageFragment; + + + protected abstract MessageFragment fragment(); + + protected abstract int getContentViewId(); + + protected abstract void initToolBar(); + + private Toolbar toolbar; + + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(getContentViewId()); + initToolBar(); + parseIntent(); + + messageFragment = (MessageFragment) switchContent(fragment()); + } + + @Override + protected void onResume() { + super.onResume(); + } + + @Override + protected void onPause() { + super.onPause(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + } + + @Override + public void onBackPressed() { + if (messageFragment == null || !messageFragment.onBackPressed()) { + super.onBackPressed(); + } + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (messageFragment != null) { + messageFragment.onActivityResult(requestCode, resultCode, data); + } + + if (customization != null) { + customization.onActivityResult(this, requestCode, resultCode, data); + } + } + + private void parseIntent() { + sessionId = getIntent().getStringExtra(Extras.EXTRA_ACCOUNT); + customization = (SessionCustomization) getIntent().getSerializableExtra(Extras.EXTRA_CUSTOMIZATION); + + if (customization != null) { + addRightCustomViewOnActionBar(this, customization.buttons); + } + } + + // 添加action bar的右侧按钮及响应事件 + private void addRightCustomViewOnActionBar(Activity activity, List buttons) { + if (buttons == null || buttons.size() == 0) { + return; + } + + Toolbar toolbar = getToolBar(); + if (toolbar == null) { + return; + } + + LinearLayout view = (LinearLayout) LayoutInflater.from(activity).inflate(R.layout.nim_action_bar_custom_view, null); + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT); + for (final SessionCustomization.OptionsButton button : buttons) { + ImageView imageView = new ImageView(activity); + imageView.setImageResource(button.iconId); + imageView.setBackgroundResource(R.drawable.nim_nim_action_bar_button_selector); + imageView.setPadding(ScreenUtil.dip2px(10), 0, ScreenUtil.dip2px(10), 0); + imageView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + button.onClick(BaseMessageActivity.this, v, sessionId); + } + }); + view.addView(imageView, params); + } + + toolbar.addView(view, new Toolbar.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT, Gravity.RIGHT | Gravity.CENTER)); + } + + /** + * 当前Activity 是否有效 + */ + protected boolean isValid() { + return !isFinishing() && !isDestroyed(); + } + + public TFragment switchContent(TFragment fragment) { + return switchContent(fragment, false); + } + + protected TFragment switchContent(TFragment fragment, boolean needAddToBackStack) { + FragmentManager fm = getSupportFragmentManager(); + FragmentTransaction fragmentTransaction = fm.beginTransaction(); + fragmentTransaction.replace(fragment.getContainerId(), fragment); + if (needAddToBackStack) { + fragmentTransaction.addToBackStack(null); + } + try { + fragmentTransaction.commitAllowingStateLoss(); + } catch (Exception e) { + + } + + return fragment; + } + + public void setToolBar(int toolBarId, ToolBarOptions options) { + toolbar = (Toolbar) findViewById(toolBarId); + if (options.titleId != 0) { + toolbar.setTitle(options.titleId); + } + if (!TextUtils.isEmpty(options.titleString)) { + toolbar.setTitle(options.titleString); + } + if (options.logoId != 0) { + toolbar.setLogo(options.logoId); + } + setSupportActionBar(toolbar); + + if (options.isNeedNavigate) { + toolbar.setNavigationIcon(options.navigateId); + toolbar.setContentInsetStartWithNavigation(0); + toolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onBackPressed(); + } + }); + } + } + + public void setToolBar(int toolbarId, int titleId, int logoId) { + toolbar = (Toolbar) findViewById(toolbarId); + toolbar.setTitle(titleId); + toolbar.setLogo(logoId); + setSupportActionBar(toolbar); + } + + public Toolbar getToolBar() { + return toolbar; + } + + public void setSubTitle(String subTitle) { + if (toolbar != null) { + toolbar.setSubtitle(subTitle); + } + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/im/avtivity/BlackListAdapter.java b/app/src/main/java/com/chwl/app/ui/im/avtivity/BlackListAdapter.java new file mode 100644 index 0000000..fc2bf09 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/avtivity/BlackListAdapter.java @@ -0,0 +1,148 @@ +package com.chwl.app.ui.im.avtivity; + +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import androidx.recyclerview.widget.RecyclerView; + +import com.chwl.app.R; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; +import com.netease.nimlib.sdk.uinfo.model.NimUserInfo; + +import java.util.List; + +/** + * @author Administrator + * @date 2018/1/27 + */ + +public class BlackListAdapter extends RecyclerView.Adapter implements View.OnTouchListener { + + private List nimUserInfos; + private RecyclerView recyclerView; + + BlackListAdapter(RecyclerView recyclerView) { + this.recyclerView = recyclerView; + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { +// return new BlackListHolder(new SwipeRecyclerViewItem(parent.getContext())); + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_friend_black_list_manage, parent, false); + return new BlackListHolder(view); + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + if (holder instanceof BlackListHolder) { + ((BlackListHolder) holder).bind(nimUserInfos.get(position)); + } + } + + public void setNewData(List nimUserInfoList) { + this.nimUserInfos = nimUserInfoList; + notifyDataSetChanged(); + } + + @Override + public void onAttachedToRecyclerView(RecyclerView recyclerView) { + super.onAttachedToRecyclerView(recyclerView); + } + + @Override + public int getItemCount() { + return nimUserInfos == null ? 0 : nimUserInfos.size(); + } + + /** + * 当用户触碰其他item的时候,需要隐藏已经显示出remove按钮的item + * + * @param v - + * @param event - + * @return - + */ + @Override + public boolean onTouch(View v, MotionEvent event) { + int actionMasked = event.getActionMasked(); + switch (actionMasked) { + case MotionEvent.ACTION_DOWN: + int childCount = recyclerView.getChildCount(); + for (int i = 0; i < childCount; i++) { + View child = recyclerView.getChildAt(i); + RecyclerView.ViewHolder holder = recyclerView.getChildViewHolder(child); + if (holder instanceof BlackListHolder) { + if (((BlackListHolder) holder).rlContent != v) + ((BlackListHolder) holder).hideRemoveButton(); + } + } + break; + default: + break; + } + return false; + } + + class BlackListHolder extends RecyclerView.ViewHolder implements View.OnClickListener { + private RelativeLayout rlContent; + private ImageView ivAvatar; + private TextView tvName; + private TextView tvRemove; + + BlackListHolder(View itemView) { + super(itemView); + ivAvatar = itemView.findViewById(R.id.iv_avatar); + rlContent = itemView.findViewById(R.id.rl_content); + rlContent.setOnTouchListener(BlackListAdapter.this); + tvName = itemView.findViewById(R.id.tv_name); + tvRemove = itemView.findViewById(R.id.tv_remove); + tvRemove.setOnClickListener(this); + } + + private NimUserInfo userInfo; + + void bind(NimUserInfo nimUserInfo) { + this.userInfo = nimUserInfo; + // 加载头像 + ImageLoadUtils.loadAvatar(itemView.getContext(), nimUserInfo.getAvatar(), ivAvatar); + // 名字 + tvName.setText(nimUserInfo.getName()); + // 清除view的translationX + rlContent.setTranslationX(0); + } + + void hideRemoveButton() { + rlContent.animate().setDuration(70).translationX(0).start(); + } + + @Override + public void onClick(View v) { + if (v.getId() == R.id.tv_remove) { + // 如果没有完全展开也返回 +// if (rlContent.getTranslationX() > -tvRemove.getWidth()) return; + if (ListUtils.isListEmpty(nimUserInfos)) return; + if (nimUserInfos.remove(userInfo)) { + notifyItemRemoved(getAdapterPosition()); + // 从云信的黑名单中移除 + NimFriendModel.get().removeFromBlackList(userInfo.getAccount()) + .subscribe((aBoolean, throwable) -> { + if (throwable != null) { +// Toast.makeText(itemView.getContext(), ResUtil.getString(R.string.im_avtivity_blacklistadapter_01), Toast.LENGTH_SHORT).show(); + SingleToastUtil.showToastShort(ResUtil.getString(R.string.im_avtivity_blacklistadapter_02)); + } else { +// Toast.makeText(itemView.getContext(), ResUtil.getString(R.string.im_avtivity_blacklistadapter_03), Toast.LENGTH_SHORT).show(); + SingleToastUtil.showToastShort(ResUtil.getString(R.string.im_avtivity_blacklistadapter_04)); + } + }); + } + } + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/im/avtivity/BlackListManageActivity.java b/app/src/main/java/com/chwl/app/ui/im/avtivity/BlackListManageActivity.java new file mode 100644 index 0000000..3f6ba3c --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/avtivity/BlackListManageActivity.java @@ -0,0 +1,121 @@ +package com.chwl.app.ui.im.avtivity; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.netease.nim.uikit.StatusBarUtil; +import com.netease.nimlib.sdk.uinfo.model.NimUserInfo; +import com.chwl.app.R; +import com.chwl.app.base.BaseMvpActivity; +import com.chwl.app.common.NoDataFragment; +import com.chwl.library.base.factory.CreatePresenter; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; + +import java.util.List; + +/** + * @description: 黑名单管理页面 + * @author: hewenhao + * @date: 2018/9/4 14:43 + */ +@CreatePresenter(BlackListManagePresenter.class) +public class BlackListManageActivity extends BaseMvpActivity implements + IBlackListManageView { + + private BlackListAdapter mAdapter; + private RecyclerView mRecyclerView; + private LinearLayoutManager mLayoutManager; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_friend_black_list_manage); + initWhiteTitleBar(ResUtil.getString(R.string.im_avtivity_blacklistmanageactivity_01)); + initViews(); + } + + private void initViews() { + showLoading(); + // 黑名单 + mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view); + mAdapter = new BlackListAdapter(mRecyclerView); + mLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false); + mRecyclerView.setLayoutManager(mLayoutManager); + mRecyclerView.setAdapter(mAdapter); + // 获取黑名单用户的数据 + BlackListManagePresenter mvpPresenter = getMvpPresenter(); + if (mvpPresenter != null) { + mvpPresenter.getMyBlackListUsers(); + } + } + + @Override + public void onGetBlackListInfoSuccess(List nimUserInfos) { + if (ListUtils.isListEmpty(nimUserInfos)) { + showNoData(R.drawable.icon_common_failure, ResUtil.getString(R.string.im_avtivity_blacklistmanageactivity_02)); + } else { + hideStatus(); + if (mAdapter != null) { + mAdapter.setNewData(nimUserInfos); + } + } + } + + @Override + public void showNoData(int drawable, CharSequence charSequence) { + if (!checkActivityValid()) { + return; + } + + View status = findViewById(R.id.status_layout); + if (status == null || status.getId() == View.NO_ID) { + return; + } + NoDataFragment fragment = NoDataFragment.newInstance(R.layout.fragment_no_data_large_iv, drawable, charSequence); + fragment.setListener(getLoadListener()); + getSupportFragmentManager().beginTransaction().replace(status.getId(), fragment, STATUS_TAG).commitAllowingStateLoss(); + } + + @Override + public void onGetBlackListInfoFail(Throwable throwable) { + showNetworkErr(); + toast(ResUtil.getString(R.string.im_avtivity_blacklistmanageactivity_03)); + } + + @Override + public void onReloadDate() { + super.onReloadDate(); + showLoading(); + BlackListManagePresenter mvpPresenter = getMvpPresenter(); + if (mvpPresenter != null) { + mvpPresenter.getMyBlackListUsers(); + } + } + + public static void start(Context context) { + Intent intent = new Intent(); + intent.setClass(context, BlackListManageActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); + context.startActivity(intent); + } + + @Override + protected boolean needSteepStateBar() { + return true; + } + + @Override + protected void setStatusBar() { + super.setStatusBar(); + StatusBarUtil.transparencyBar(this); + StatusBarUtil.StatusBarLightMode(this); + } + + +} diff --git a/app/src/main/java/com/chwl/app/ui/im/avtivity/BlackListManagePresenter.java b/app/src/main/java/com/chwl/app/ui/im/avtivity/BlackListManagePresenter.java new file mode 100644 index 0000000..6fc3423 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/avtivity/BlackListManagePresenter.java @@ -0,0 +1,26 @@ +package com.chwl.app.ui.im.avtivity; + +import com.chwl.app.base.BaseMvpPresenter; + +/** + * @author Administrator + * @date 2018/1/27 + */ + +public class BlackListManagePresenter extends BaseMvpPresenter { + private NimFriendModel model; + + public BlackListManagePresenter() { + model = NimFriendModel.get(); + } + + void getMyBlackListUsers() { + model.getMyBlackListInfos().subscribe((nimUserInfos, throwable) -> { + if (throwable != null) { + getMvpView().onGetBlackListInfoFail(throwable); + } else { + getMvpView().onGetBlackListInfoSuccess(nimUserInfos); + } + }); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/im/avtivity/IAddBlackListView.java b/app/src/main/java/com/chwl/app/ui/im/avtivity/IAddBlackListView.java new file mode 100644 index 0000000..f357ddb --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/avtivity/IAddBlackListView.java @@ -0,0 +1,27 @@ +package com.chwl.app.ui.im.avtivity; + +import com.chwl.library.base.IMvpBaseView; + +/** + *

+ * + * @author xiaoyu + * @date 2017/12/12 + */ +public interface IAddBlackListView extends IMvpBaseView { + + /** + * 加入黑名单失败 + * + * @param success -是否成功 + */ + void addToBlackListSuccessOrNot(boolean success); + + /** + * 移除黑名单失败 + * + * @param success -是否成功 + */ + void removeFromBlackListSuccessOrNot(boolean success); + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/im/avtivity/IBlackListManageView.java b/app/src/main/java/com/chwl/app/ui/im/avtivity/IBlackListManageView.java new file mode 100644 index 0000000..8350330 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/avtivity/IBlackListManageView.java @@ -0,0 +1,29 @@ +package com.chwl.app.ui.im.avtivity; + +import com.netease.nimlib.sdk.uinfo.model.NimUserInfo; +import com.chwl.library.base.IMvpBaseView; + +import java.util.List; + +/** + *

+ * + * @author xiaoyu + * @date 2017/12/12 + */ +public interface IBlackListManageView extends IMvpBaseView { + + /** + * 获取黑名单成功的回调 + * + * @param nimUserInfos 用户信息 + */ + void onGetBlackListInfoSuccess(List nimUserInfos); + + /** + * 获取黑名单失败的回调 + * + * @param throwable - + */ + void onGetBlackListInfoFail(Throwable throwable); +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/im/avtivity/NewBaseMessageActivity.java b/app/src/main/java/com/chwl/app/ui/im/avtivity/NewBaseMessageActivity.java new file mode 100644 index 0000000..e72b9bf --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/avtivity/NewBaseMessageActivity.java @@ -0,0 +1,200 @@ +package com.chwl.app.ui.im.avtivity; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; + +import androidx.appcompat.widget.Toolbar; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; + +import com.netease.nim.uikit.R; +import com.netease.nim.uikit.api.model.session.SessionCustomization; +import com.netease.nim.uikit.business.session.constant.Extras; +import com.netease.nim.uikit.common.activity.ToolBarOptions; +import com.netease.nim.uikit.common.fragment.TFragment; +import com.netease.nim.uikit.common.util.sys.ScreenUtil; +import com.chwl.app.base.BaseActivity; +import com.chwl.app.ui.im.fragment.MessageFragment; + +import java.util.List; + +/** + * Created by zhoujianghua on 2015/9/10. + */ +public abstract class NewBaseMessageActivity extends BaseActivity { + + private static final String TAG = "BaseMessageActivity"; + + protected String sessionId; + protected MessageFragment messageFragment; + private SessionCustomization customization; + private Toolbar toolbar; + + protected abstract MessageFragment fragment(Intent intent); + + protected abstract int getContentViewId(); + + protected abstract void initToolBar(); + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(getContentViewId()); + initToolBar(); + parseIntent(); + + messageFragment = (MessageFragment) switchContent(fragment(getIntent())); + } + + @Override + protected void onResume() { + super.onResume(); + } + + @Override + protected void onPause() { + super.onPause(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + } + + @Override + public void onBackPressed() { + if (messageFragment == null || !messageFragment.onBackPressed()) { + super.onBackPressed(); + } + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (messageFragment != null) { + messageFragment.onActivityResult(requestCode, resultCode, data); + } + + if (customization != null) { + customization.onActivityResult(this, requestCode, resultCode, data); + } + } + + private void parseIntent() { + sessionId = getIntent().getStringExtra(Extras.EXTRA_ACCOUNT); + customization = (SessionCustomization) getIntent().getSerializableExtra(Extras.EXTRA_CUSTOMIZATION); + + if (customization != null) { + addRightCustomViewOnActionBar(this, customization.buttons); + } + } + + // 添加action bar的右侧按钮及响应事件 + private void addRightCustomViewOnActionBar(Activity activity, List buttons) { + if (buttons == null || buttons.size() == 0) { + return; + } + + Toolbar toolbar = getToolBar(); + if (toolbar == null) { + return; + } + + LinearLayout view = (LinearLayout) LayoutInflater.from(activity).inflate(R.layout.nim_action_bar_custom_view, null); + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT); + for (final SessionCustomization.OptionsButton button : buttons) { + ImageView imageView = new ImageView(activity); + imageView.setImageResource(button.iconId); + imageView.setBackgroundResource(R.drawable.nim_nim_action_bar_button_selector); + imageView.setPadding(ScreenUtil.dip2px(10), 0, ScreenUtil.dip2px(10), 0); + imageView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + button.onClick(NewBaseMessageActivity.this, v, sessionId); + } + }); + view.addView(imageView, params); + } + + toolbar.addView(view, new Toolbar.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT, Gravity.RIGHT | Gravity.CENTER)); + } + + /** + * 当前Activity 是否有效 + */ + protected boolean isValid() { + return !isFinishing() && !isDestroyed(); + } + + public TFragment switchContent(TFragment fragment) { + return switchContent(fragment, false); + } + + protected TFragment switchContent(TFragment fragment, boolean needAddToBackStack) { + FragmentManager fm = getSupportFragmentManager(); + FragmentTransaction fragmentTransaction = fm.beginTransaction(); + fragmentTransaction.replace(fragment.getContainerId(), fragment); + if (needAddToBackStack) { + fragmentTransaction.addToBackStack(null); + } + try { + fragmentTransaction.commitAllowingStateLoss(); + } catch (Exception e) { + + } + + return fragment; + } + + public void setToolBar(int toolBarId, ToolBarOptions options) { + toolbar = (Toolbar) findViewById(toolBarId); + if (options.titleId != 0) { + toolbar.setTitle(options.titleId); + } + if (!TextUtils.isEmpty(options.titleString)) { + toolbar.setTitle(options.titleString); + } + if (options.logoId != 0) { + toolbar.setLogo(options.logoId); + } + setSupportActionBar(toolbar); + + if (options.isNeedNavigate) { + toolbar.setNavigationIcon(options.navigateId); + toolbar.setContentInsetStartWithNavigation(0); + toolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onBackPressed(); + } + }); + } + } + + public void setToolBar(int toolbarId, int titleId, int logoId) { + toolbar = (Toolbar) findViewById(toolbarId); + toolbar.setTitle(titleId); + toolbar.setLogo(logoId); + setSupportActionBar(toolbar); + } + + public Toolbar getToolBar() { + return toolbar; + } + + public void setSubTitle(String subTitle) { + if (toolbar != null) { + toolbar.setSubtitle(subTitle); + } + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/im/avtivity/NimFriendModel.java b/app/src/main/java/com/chwl/app/ui/im/avtivity/NimFriendModel.java new file mode 100644 index 0000000..d472a82 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/avtivity/NimFriendModel.java @@ -0,0 +1,164 @@ +package com.chwl.app.ui.im.avtivity; + +import com.netease.nimlib.sdk.InvocationFuture; +import com.netease.nimlib.sdk.NIMClient; +import com.netease.nimlib.sdk.friend.FriendService; +import com.netease.nimlib.sdk.uinfo.UserService; +import com.netease.nimlib.sdk.uinfo.model.NimUserInfo; +import com.netease.nimlib.sdk.util.api.RequestResult; +import com.chwl.app.R; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; + +import java.util.ArrayList; +import java.util.List; + +import io.reactivex.Single; +import io.reactivex.SingleOnSubscribe; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; + +/** + * @author Administrator + * @date 2018/1/27 + */ + +public class NimFriendModel { + private static final int RESULT_OK = 200; + + private static NimFriendModel sInstance; + + public static NimFriendModel get() { + if (sInstance == null) { + synchronized (NimFriendModel.class) { + if (sInstance == null) { + sInstance = new NimFriendModel(); + } + } + } + return sInstance; + } + + private NimFriendModel() { + + } + + + public Single addToBlackList(String targetUid) { + return Single.create((SingleOnSubscribe) e -> { + InvocationFuture invocationFuture = + NIMClient.getService(FriendService.class).addToBlackList(targetUid); + RequestResult result = NIMClient.syncRequest(invocationFuture); + if (result.exception != null) { + e.onError(result.exception); + } else if (result.code != RESULT_OK) { + e.onError(new Exception(ResUtil.getString(R.string.im_avtivity_nimfriendmodel_01) + result.code)); + } else { + e.onSuccess(true); + } + }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()); + } + + public Single removeFromBlackList(String targetUid) { + return Single.create((SingleOnSubscribe) e -> { + InvocationFuture invocationFuture = + NIMClient.getService(FriendService.class).removeFromBlackList(targetUid); + RequestResult result = NIMClient.syncRequest(invocationFuture); + if (result.exception != null) { + e.onError(result.exception); + } else if (result.code != RESULT_OK) { + e.onError(new Exception(ResUtil.getString(R.string.im_avtivity_nimfriendmodel_02) + result.code)); + } else { + e.onSuccess(true); + } + }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()); + } + + + /** + * 返回我所有的黑名单成员的账号 + * + * @return - + */ + List getMyBlackListAccount() { + return NIMClient.getService(FriendService.class).getBlackList(); + } + + /** + * 返回我所有的黑名单成员的数量 + * + * @return - 数量 + */ + int getMyBlackListSize() { + List blackList = NIMClient.getService(FriendService.class).getBlackList(); + if (ListUtils.isListEmpty(blackList)) return 0; + return blackList.size(); + } + + /** + * 返回该成员是否在我的黑名单中 + * + * @return - + */ + public boolean isInMyBlackList(String account) { + return NIMClient.getService(FriendService.class).isInBlackList(account); + } + + /** + * 获取黑名单所有账号的用户信息 + * + * @return - + */ + public Single> getMyBlackListInfos() { + List myBlackListAccount = getMyBlackListAccount(); + if (ListUtils.isListEmpty(myBlackListAccount)) { + List temp = new ArrayList<>(1); + return Single.just(temp).observeOn(AndroidSchedulers.mainThread()); + } + List users = NIMClient.getService(UserService.class).getUserInfoList(myBlackListAccount); + if (users.size() == myBlackListAccount.size()) + return Single.just(users).observeOn(AndroidSchedulers.mainThread()); + return Single.create((SingleOnSubscribe>) e -> { + + List totalResult = new ArrayList<>(); + List subAccount = new ArrayList<>(); + + for (String sub :myBlackListAccount) { + if (subAccount.size() == 150) { + InvocationFuture> future = + NIMClient.getService(UserService.class).fetchUserInfo(subAccount); + RequestResult> result = NIMClient.syncRequest(future); + if (result.exception != null) { + e.onError(result.exception); + } else if (result.code != RESULT_OK) { + e.onError(new Exception(ResUtil.getString(R.string.im_avtivity_nimfriendmodel_03) + result.code)); + } else { + totalResult.addAll(result.data); + } + + subAccount.clear(); + } + + subAccount.add(sub); + } + + if (subAccount.size() > 0) { + InvocationFuture> future = + NIMClient.getService(UserService.class).fetchUserInfo(subAccount); + RequestResult> result = NIMClient.syncRequest(future); + if (result.exception != null) { + e.onError(result.exception); + } else if (result.code != RESULT_OK) { + e.onError(new Exception(ResUtil.getString(R.string.im_avtivity_nimfriendmodel_04) + result.code)); + } else { + totalResult.addAll(result.data); + } + } + + e.onSuccess(totalResult); + + }).observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.io()); + } + + +} diff --git a/app/src/main/java/com/chwl/app/ui/im/avtivity/NimP2PMessageActivity.java b/app/src/main/java/com/chwl/app/ui/im/avtivity/NimP2PMessageActivity.java new file mode 100644 index 0000000..f1277f6 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/avtivity/NimP2PMessageActivity.java @@ -0,0 +1,512 @@ +package com.chwl.app.ui.im.avtivity; + +import static com.netease.nim.uikit.business.session.constant.Extras.EXTRA_RECORDID; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.Intent; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.TextUtils; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.chwl.app.R; +import com.chwl.app.avroom.activity.AVRoomActivity; +import com.chwl.app.common.widget.CustomImageSpan; +import com.chwl.app.ui.im.audio.ShakeHeartDialogFragment; +import com.chwl.app.ui.im.fragment.MessageFragment; +import com.chwl.app.ui.user.activity.UserInfoActivity; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.app.vip.util.VipHelper; +import com.chwl.core.audio.event.VoiceShakeHeartEvent; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.im.friend.IMFriendModel; +import com.chwl.core.initial.InitialModel; +import com.chwl.core.initial.bean.InitInfo; +import com.chwl.core.level.UserLevelVo; +import com.chwl.core.mentoring_relationship.event.MentoringSuccessEvent; +import com.chwl.core.noble.NobleUtil; +import com.chwl.core.praise.PraiseModel; +import com.chwl.core.praise.event.IsLikedEvent; +import com.chwl.core.praise.event.PraiseEvent; +import com.chwl.core.user.UserModel; +import com.chwl.core.user.bean.UserDetailInfo; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.core.utils.SystemUidUtil; +import com.chwl.core.utils.extension.StringExtensionKt; +import com.chwl.core.utils.net.BeanObserver; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; +import com.netease.nim.uikit.api.NimUIKit; +import com.netease.nim.uikit.api.model.contact.ContactChangedObserver; +import com.netease.nim.uikit.api.model.main.OnlineStateChangeObserver; +import com.netease.nim.uikit.api.model.user.UserInfoObserver; +import com.netease.nim.uikit.api.wrapper.NimToolBarOptions; +import com.netease.nim.uikit.business.session.constant.Extras; +import com.netease.nim.uikit.business.uinfo.UserInfoHelper; +import com.netease.nim.uikit.common.activity.ToolBarOptions; +import com.netease.nim.uikit.impl.NimUIKitImpl; +import com.netease.nimlib.sdk.NIMClient; +import com.netease.nimlib.sdk.Observer; +import com.netease.nimlib.sdk.msg.MsgServiceObserve; +import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum; +import com.netease.nimlib.sdk.msg.model.CustomNotification; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.List; + +import io.reactivex.functions.Consumer; + + +/** + * 点对点聊天界面 + *

+ * Created by huangjun on 2015/2/1. + */ +public class NimP2PMessageActivity extends NewBaseMessageActivity { + + public static final String IS_BY_MATCH = "isByMatch"; + private static final String TAG = "NimP2PMessageActivity"; + private final OnlineStateChangeObserver onlineStateChangeObserver = accounts -> { + // 更新 toolbar + if (accounts.contains(sessionId)) { + // 按照交互来展示 + displayOnlineState(); + } + }; + private boolean isResume = false; + /** + * 命令消息接收观察者 + */ + private final Observer commandObserver = message -> { + if (!sessionId.equals(message.getSessionId()) || message.getSessionType() != SessionTypeEnum.P2P) { + return; + } + showCommandMessage(message); + }; + private TextView ivAddBlackList; + private TextView tvTips; + private View tipsLayout; + private ImageView closeIcon; + @Nullable + private UserInfo buddyUserInfo; + private final ContactChangedObserver friendDataChangedObserver = new ContactChangedObserver() { + @Override + public void onAddedOrUpdatedFriends(List accounts) { + displayAntiFraudTips(); + } + + @Override + public void onDeletedFriends(List accounts) { + displayAntiFraudTips(); + } + + @Override + public void onAddUserToBlackList(List account) { + displayAntiFraudTips(); + } + + @Override + public void onRemoveUserFromBlackList(List account) { + displayAntiFraudTips(); + } + }; + private ImageView ivAttention; + private UserInfoObserver uinfoObserver; + + public static void start(Context context, String contactId) { + startReal(context, contactId, new Intent()); + } + + public static void start(Context context, String contactId, boolean isFromVoiceMatch) { + Intent intent = new Intent(); + intent.putExtra(Extras.EXTRA_ACCOUNT, contactId); + intent.putExtra(Extras.EXTRA_CUSTOMIZATION, NimUIKitImpl.commonP2PSessionCustomization); + intent.putExtra("isFromVoiceMatch", isFromVoiceMatch); + intent.setClass(context, NimP2PMessageActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); + + context.startActivity(intent); + } + + public static void startRecord(Context context, String contactId, String recordId) { + Intent intent = new Intent(); + intent.putExtra(EXTRA_RECORDID, recordId); + startReal(context, contactId, intent); + } + + public static void start(Context context, String contactId, String gameId) { + Intent intent = new Intent(); + intent.putExtra("gameId", gameId); + startReal(context, contactId, intent); + } + + public static void startReal(Context context, String contactId, Intent intent) { + if (intent == null) + intent = new Intent(); + + intent.putExtra(Extras.EXTRA_ACCOUNT, contactId); + intent.putExtra(Extras.EXTRA_CUSTOMIZATION, NimUIKitImpl.commonP2PSessionCustomization); + intent.setClass(context, NimP2PMessageActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); + context.startActivity(intent); + + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + tipsLayout = findViewById(R.id.rl_tips); + closeIcon = findViewById(R.id.iv_close_tips); + tvTips = findViewById(R.id.tv_tips); + closeIcon.setOnClickListener(view -> { + IMFriendModel.get().addCloseTipsAccount(sessionId); + tipsLayout.setVisibility(View.GONE); + }); + // 单聊特例话数据,包括个人信息,黑名单 + addBlackList(); + requestBuddyInfo(); + displayOnlineState(); + registerObservers(true); + registerOnlineStateChangeListener(true); + EventBus.getDefault().register(this); + displayAntiFraudTips(); + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + + String sessionId = intent.getStringExtra(Extras.EXTRA_ACCOUNT); + //如果sessionId与之前的sessionId不是同一个,刷新数据 + if (!TextUtils.isEmpty(this.sessionId) && !this.sessionId.equals(sessionId)) { + this.sessionId = sessionId; + buddyUserInfo = null; + requestBuddyInfo(); + displayOnlineState(); + displayAntiFraudTips(); + messageFragment = (MessageFragment) switchContent(fragment(intent)); + } + } + + private void displayAntiFraudTips() { + if (buddyUserInfo != null && (buddyUserInfo.isBanAccount() || buddyUserInfo.isRevoked())) { + //账号封禁 + tipsLayout.setVisibility(View.VISIBLE); + tvTips.setText(ResUtil.getString(R.string.im_avtivity_nimp2pmessageactivity_01)); + } else { + tipsLayout.setVisibility(View.GONE); + } + } + + private boolean shouldDisplayAntiFraudTips() { + return !IMFriendModel.get().isMyFriend(sessionId) && + !SystemUidUtil.isSystemUid(sessionId) && + !IMFriendModel.get().hasCloseTips(sessionId); + } + + private void addBlackList() { + if (SystemUidUtil.isSystemUid(sessionId)) return; + ivAddBlackList = findViewById(R.id.iv_add_black_list); + ivAddBlackList.setVisibility(View.VISIBLE); + ivAddBlackList.setOnClickListener((view) -> { + // 跳转到加入黑名单 + String account = getIntent().getStringExtra(Extras.EXTRA_ACCOUNT); + AddBlackListActivity.start(NimP2PMessageActivity.this, account); + }); + + } + + @Override + protected void onDestroy() { + super.onDestroy(); + registerObservers(false); + registerOnlineStateChangeListener(false); + EventBus.getDefault().unregister(this); + } + + @Override + protected void onResume() { + super.onResume(); + isResume = true; + } + + @Override + protected void onStop() { + super.onStop(); + isResume = false; + } + + private void getNickFromSession() { + String userTitleName = UserInfoHelper.getUserTitleName(sessionId, SessionTypeEnum.P2P); + TextView tvToolbarTitle = getToolBar().findViewById(R.id.tv_toolbar_title); + if (tvToolbarTitle != null) { + tvToolbarTitle.setText(userTitleName); + tvToolbarTitle.setVisibility(View.VISIBLE); + } + } + + @SuppressLint("CheckResult") + private void requestBuddyInfo() { + getNickFromSession(); + tipsLayout.setVisibility(View.GONE); + // 如果有个人信息可以获取 + UserModel.get().getUserInfo(Long.valueOf(sessionId)). + doOnSuccess(userInfo -> { + String badge = ""; + if (userInfo.getNobleInfo() != null) { + badge = NobleUtil.getLocalResourcePath(userInfo.getNobleInfo().getBadge()); + } + Drawable drawable = Drawable.createFromPath(badge); + // 显示自己的textView并且居中 + TextView tvToolbarTitle = getToolBar().findViewById(R.id.tv_toolbar_title); + // 不知道为什么要从云信获取titleName; + String userTitleName = (drawable == null ? "" : " ") + userInfo.getNick(); + SpannableStringBuilder builder = new SpannableStringBuilder(userTitleName); + if (drawable != null) { + int dimension = (int) getResources().getDimension(R.dimen.badge_tab_category_height); + drawable.setBounds(0, 0, dimension, dimension); + CustomImageSpan imageSpan = new CustomImageSpan(drawable); + builder.setSpan(imageSpan, 0, 1, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + } + tvToolbarTitle.setText(builder); + tvToolbarTitle.setVisibility(View.VISIBLE); + + ivAttention = (ImageView) findViewById(R.id.iv_attention); + if (AuthModel.get().getCurrentUid() != userInfo.getUid()) { + PraiseModel.get().isPraised(AuthModel.get().getCurrentUid(), userInfo.getUid()).subscribe(); + } + buddyUserInfo = userInfo; + displayAntiFraudTips(); + }) + .doOnError(throwable -> { + finish(); + }) + .subscribe(); + + setTitle(""); + // 显示是否 已经加入黑名单 + TextView tvAddBlackTip = getToolBar().findViewById(com.chwl.app.R.id.tv_add_black_tip); + List blackListAccount = NimFriendModel.get().getMyBlackListAccount(); + tvAddBlackTip.setVisibility(View.GONE); + if (!ListUtils.isListEmpty(blackListAccount)) { + boolean contains = blackListAccount.contains(sessionId); + tvAddBlackTip.setVisibility(contains ? View.VISIBLE : View.GONE); + } + + if (!SystemUidUtil.isSystemUid(sessionId)) { + View clUserDetails = findViewById(R.id.cl_user_details); + UserModel.get().getUserInfoDetail(Long.parseLong(sessionId)) + .compose(bindToLifecycle()) + .subscribe(new BeanObserver() { + @Override + public void onErrorMsg(String error) { + clUserDetails.setVisibility(View.GONE); + } + + @SuppressLint("SetTextI18n") + @Override + public void onSuccess(@NonNull UserDetailInfo info) { + UserDetailInfo.DataBean userInfo = info.getData(); + if (userInfo == null || userInfo.getRoomUid() <= 0) { + clUserDetails.setVisibility(View.GONE); + return; + } + clUserDetails.setVisibility(View.VISIBLE); + ImageView ivAvatar = findViewById(R.id.iv_avatar); + TextView tvNick = findViewById(R.id.tv_nick); + TextView tvContent = findViewById(R.id.tv_content); + tvNick.setText(userInfo.getNick()); + ImageLoadUtils.loadAvatar(userInfo.getAvatar(), ivAvatar); + tvContent.setText(ResUtil.getString(R.string.im_avtivity_nimp2pmessageactivity_03) + StringExtensionKt.subAndReplaceDot(userInfo.getRoomTitle(), 5) + ResUtil.getString(R.string.im_avtivity_nimp2pmessageactivity_04)); + ivAvatar.setOnClickListener(v -> UserInfoActivity.Companion.start(context, userInfo.getUid())); + clUserDetails.setOnClickListener(v -> AVRoomActivity.startForFromType( + context, + userInfo.getRoomUid(), + AVRoomActivity.FROM_TYPE_USER, + userInfo.getNick(), + String.valueOf(userInfo.getUid()))); + + UserModel.get().getUserInfoFromServerUpdate(Long.parseLong(sessionId),false) + .doOnSuccess(new Consumer() { + @Override + public void accept(UserInfo userInfo) throws Exception { + if (VipHelper.notTrace(userInfo) || VipHelper.enterHide(userInfo)){ + clUserDetails.setVisibility(View.GONE); + } + } + }).compose(bindToLifecycle()).subscribe(); + } + }); + + } + } + + private void registerObservers(boolean register) { + if (register) { + registerUserInfoObserver(); + } else { + unregisterUserInfoObserver(); + } + NIMClient.getService(MsgServiceObserve.class).observeCustomNotification(commandObserver, register); + NimUIKit.getContactChangedObservable().registerObserver(friendDataChangedObserver, register); + } + + private void registerOnlineStateChangeListener(boolean register) { + if (!NimUIKitImpl.enableOnlineState()) { + return; + } + NimUIKitImpl.getOnlineStateChangeObservable().registerOnlineStateChangeListeners(onlineStateChangeObserver, register); + } + + private void displayOnlineState() { + if (!NimUIKitImpl.enableOnlineState()) { + return; + } + String detailContent = NimUIKitImpl.getOnlineStateContentProvider().getDetailDisplay(sessionId); + setSubTitle(detailContent); + } + + private void registerUserInfoObserver() { + if (uinfoObserver == null) { + uinfoObserver = new UserInfoObserver() { + @Override + public void onUserInfoChanged(List accounts) { + if (accounts.contains(sessionId)) { + requestBuddyInfo(); + } + } + }; + } + NimUIKit.getUserInfoObservable().registerObserver(uinfoObserver, true); + } + + private void unregisterUserInfoObserver() { + if (uinfoObserver != null) { + NimUIKit.getUserInfoObservable().registerObserver(uinfoObserver, false); + } + } + + protected void showCommandMessage(CustomNotification message) { + if (!isResume) { + return; + } + + String content = message.getContent(); + try { + JSONObject json = JSON.parseObject(content); + int id = json.getIntValue("id"); + // id 为 2,表示这是师徒里用到的系统通知,不要 toast 出来 + if (id == 2) return; + if (id == 1) { + // 正在输入 + SingleToastUtil.showToast(ResUtil.getString(R.string.im_avtivity_nimp2pmessageactivity_05)); + } + + } catch (Exception e) { + + } + } + + @Override + protected MessageFragment fragment(Intent intent) { + Bundle arguments = intent.getExtras(); + if (arguments == null) { + arguments = new Bundle(); + } + arguments.putSerializable(Extras.EXTRA_TYPE, SessionTypeEnum.P2P); + String gameId = intent.getStringExtra("gameId"); + if (!TextUtils.isEmpty(gameId)) { + arguments.putString("gameId", gameId); + } + String recordId = intent.getStringExtra(EXTRA_RECORDID); + if (!TextUtils.isEmpty(recordId)) { + arguments.putString(EXTRA_RECORDID, recordId); + } + MessageFragment fragment = new MessageFragment(); + fragment.setArguments(arguments); + fragment.setContainerId(R.id.message_fragment_container); + + // 等级限制:官方小秘书 和 系统消息,不设置等级限制 + if (!SystemUidUtil.isSystemUid(sessionId)) { + UserInfo userInfo = UserModel.get().getCacheLoginUserInfo(); + if (userInfo != null) { + UserLevelVo userLevelVo = userInfo.getUserLevelVo(); + if (userLevelVo != null) { + fragment.setCurrentLevel(userLevelVo.experLevelSeq); + } + } + InitInfo initInfo = InitialModel.get().getCacheInitInfo(); + if (initInfo != null) { + fragment.setLimitLevel(initInfo.getPrivateChatLevelNo()); + } + } + return fragment; + } + + @Override + protected int getContentViewId() { + return R.layout.activity_p2p_message; + } + + @Override + protected void initToolBar() { + ToolBarOptions options = new NimToolBarOptions(); + setToolBar(R.id.toolbar, options); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onMentoringSuccessEvent(MentoringSuccessEvent event) { + } + + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onIsLiked(IsLikedEvent event) { + if (event.isLiked) { + ivAttention.setVisibility(View.GONE); + } else { + ivAttention.setVisibility(View.VISIBLE); + ivAttention.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + PraiseModel.get().praise(Long.valueOf(sessionId), true).subscribe(); + } + }); + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onPraise(PraiseEvent event) { + if (event.getLikedUid() != Long.valueOf(sessionId) || + Long.valueOf(sessionId) == AuthModel.get().getCurrentUid()) { + return; + } + if (event.isFailed()) { + toast(event.getError()); + return; + } + ivAttention.setVisibility(View.GONE); + ivAttention.setOnClickListener(null); + toast(event.isPraise() ? R.string.attention_success : R.string.cancel_fan_success); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onVoiceShakeHeart(VoiceShakeHeartEvent event) { + // 显示动画 + ShakeHeartDialogFragment shakeHeartDialogFragment = ShakeHeartDialogFragment.newInstance(event.showTextHint); + shakeHeartDialogFragment.show(getSupportFragmentManager(), "shake_heart"); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/im/avtivity/SwipeRecyclerViewItem.java b/app/src/main/java/com/chwl/app/ui/im/avtivity/SwipeRecyclerViewItem.java new file mode 100644 index 0000000..f0ab9e7 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/avtivity/SwipeRecyclerViewItem.java @@ -0,0 +1,149 @@ +package com.chwl.app.ui.im.avtivity; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.VelocityTracker; +import android.view.View; +import android.view.ViewConfiguration; +import android.widget.FrameLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.interpolator.view.animation.LinearOutSlowInInterpolator; + +import com.chwl.app.R; + +/** + * 一个支持侧滑删除的item + * + * @author Administrator + * @date 2018/1/29 + */ + +public class SwipeRecyclerViewItem extends FrameLayout { + private Context mContext; + private RelativeLayout rlContent; + private TextView tvRemove; + private View root; + + public SwipeRecyclerViewItem(@NonNull Context context) { + this(context, null); + } + + public SwipeRecyclerViewItem(@NonNull Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public SwipeRecyclerViewItem(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context); + } + + private void init(Context context) { + mContext = context; + mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); + mMaxFlingVelocity = ViewConfiguration.get(context).getScaledMaximumFlingVelocity(); + mMinFlingVelocity = 600; + root = LayoutInflater.from(context).inflate(R.layout.item_friend_black_list_manage, this, false); + rlContent = root.findViewById(R.id.rl_content); + tvRemove = root.findViewById(R.id.tv_remove); + addView(root); + } + + private int mTouchSlop; + private float mStartX; + private float mStartY; + private float mLastX; + private float mLastY; + private boolean disallowIntercept = false; + private VelocityTracker velocityTracker; + private int mMaxFlingVelocity; + private int mMinFlingVelocity; + + @Override + public boolean dispatchTouchEvent(MotionEvent event) { + int actionMasked = event.getActionMasked(); + if (velocityTracker == null) { + velocityTracker = VelocityTracker.obtain(); + } + velocityTracker.addMovement(event); + + switch (actionMasked) { + case MotionEvent.ACTION_DOWN: + mStartX = event.getX(); + mStartY = event.getY(); + mLastX = event.getX(); + mLastY = event.getY(); + break; + case MotionEvent.ACTION_MOVE: + float dx = event.getX() - mLastX; + float dy = event.getY() - mLastY; + // 如果没有拦截这个touch事件序列并且总体上是左右滑动的 + // 则要拦截这个事件 + if (!disallowIntercept && + Math.abs(event.getX() - mStartX) > Math.abs(event.getY() - mStartY)) { + // 一定要从左到右滑动 + // 并且横滑的距离要大于最小的touch slop + if (-(event.getX() - mStartX) > mTouchSlop) { + disallowIntercept = true; + } + } + // 只有自己拦截了touch事件才能滑动item + if (disallowIntercept) { + getParent().requestDisallowInterceptTouchEvent(true); + onItemSwipe(dx); + } + mLastX = event.getX(); + mLastY = event.getY(); + break; + case MotionEvent.ACTION_UP: + // 松开手后要根据已经滑动了的距离 + // 确定要自动滑动到哪个方向 + if (disallowIntercept) { + velocityTracker.computeCurrentVelocity(1000, mMaxFlingVelocity); + board(velocityTracker.getXVelocity()); + } + break; + default: + break; + } + // perform click + super.dispatchTouchEvent(event); + return true; + } + + /** + * 靠边动画 + */ + private void board(float velocityX) { + float translationX = rlContent.getTranslationX(); + float width = tvRemove.getWidth(); + // 确定要靠边的方向 + boolean overMiddle = Math.abs(-translationX) > width / 2; + // 从右往左滑动 + if (velocityX < 0 && -velocityX > mMinFlingVelocity) { + rlContent.animate().translationX(-width).setDuration(70).setInterpolator(new LinearOutSlowInInterpolator()).start(); + } else if (velocityX > 0 && velocityX > mMinFlingVelocity / 2) { + // 从左往右滑动 + rlContent.animate().translationX(0).setDuration(70).setInterpolator(new LinearOutSlowInInterpolator()).start(); + } else if (overMiddle) { + rlContent.animate().translationX(-width).setDuration(70).setInterpolator(new LinearOutSlowInInterpolator()).start(); + } else { + rlContent.animate().translationX(0).setDuration(70).setInterpolator(new LinearOutSlowInInterpolator()).start(); + } + } + + private void onItemSwipe(float dx) { + float translationX = rlContent.getTranslationX(); + if (dx + translationX < -tvRemove.getWidth()) { + dx = -tvRemove.getWidth() - translationX; + } else if (translationX + dx > 0) { + dx = -translationX; + } + rlContent.setTranslationX(translationX + dx); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/im/chat/GameTeamInviteViewHolder.kt b/app/src/main/java/com/chwl/app/ui/im/chat/GameTeamInviteViewHolder.kt new file mode 100644 index 0000000..1acedd6 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/chat/GameTeamInviteViewHolder.kt @@ -0,0 +1,118 @@ +package com.chwl.app.ui.im.chat + +import android.content.Context +import android.graphics.Color +import android.widget.ImageView +import android.widget.TextView +import androidx.annotation.Keep +import com.chwl.app.R +import com.chwl.app.ui.utils.load +import com.chwl.core.im.custom.bean.GameTeamInviteAttachment +import com.example.lib_utils.AppUtils +import com.example.lib_utils.UiUtils +import com.google.android.material.imageview.ShapeableImageView +import com.google.android.material.shape.CornerFamily +import com.google.android.material.shape.ShapeAppearanceModel +import com.netease.nim.uikit.business.session.viewholder.MsgViewHolderBase +import com.netease.nim.uikit.common.ui.recyclerview.adapter.BaseMultiItemFetchLoadAdapter + +@Keep +class GameTeamInviteViewHolder(adapter: BaseMultiItemFetchLoadAdapter<*, *>) : + MsgViewHolderBase(adapter) { + + private val isRTL = UiUtils.isRtl(AppUtils.getApp()) + + private val leftShapeAppearance: ShapeAppearanceModel by lazy(LazyThreadSafetyMode.NONE) { + buildBackgroundShapeAppearance(context ?: AppUtils.getApp(), true) + } + private val rightShapeAppearance: ShapeAppearanceModel by lazy(LazyThreadSafetyMode.NONE) { + buildBackgroundShapeAppearance(context ?: AppUtils.getApp(), false) + } + + override fun getContentResId(): Int { + return R.layout.layout_msg_view_holder_game_team_invite + } + + override fun inflateContentView() { + } + + override fun leftBackground(): Int { + return R.color.transparent + } + + override fun rightBackground(): Int { + return R.color.transparent + } + + override fun bindContentView() { + val attachment = message?.attachment as? GameTeamInviteAttachment + val data = attachment?.msgData + val gameNameView = findViewById(R.id.tv_game_name) + val gameInningView = findViewById(R.id.tv_game_inning) + val gameIconView = findViewById(R.id.iv_icon) + val gameBackgroundView = findViewById(R.id.iv_image) + val gameBackgroundMaskView = findViewById(R.id.iv_image_mask) + val shapeAppearance = getBackgroundShapeAppearance() + gameBackgroundView.shapeAppearanceModel = shapeAppearance + gameBackgroundMaskView.shapeAppearanceModel = shapeAppearance + gameNameView.text = data?.gameName ?: "" + gameInningView.text = + context?.getString(R.string.game_team_18)?.format(data?.inning?.toString() ?: "0") ?: "" + gameIconView.load(data?.gameLogo) + gameBackgroundView.load(data?.gamePic, defaultRes = R.color.color_33000000) + } + + private fun getBackgroundShapeAppearance(): ShapeAppearanceModel { + return if (isReceivedMessage) { + if (isRTL) { + rightShapeAppearance + } else { + leftShapeAppearance + } + } else { + if (isRTL) { + leftShapeAppearance + } else { + rightShapeAppearance + } + } + } + + private fun buildBackgroundShapeAppearance( + context: Context, + isLeft: Boolean + ): ShapeAppearanceModel { + val cornerA = context.resources.getDimension(R.dimen.dp_12) + val cornerB = context.resources.getDimension(R.dimen.dp_2) + val topLeftCorner: Float + val topRightCorner: Float + if (isLeft) { + topLeftCorner = cornerB + topRightCorner = cornerA + } else { + topLeftCorner = cornerA + topRightCorner = cornerB + } + return ShapeAppearanceModel.Builder().apply { + this.setTopLeftCorner( + CornerFamily.ROUNDED, + topLeftCorner + ) + + this.setTopRightCorner( + CornerFamily.ROUNDED, + topRightCorner + ) + + this.setBottomLeftCorner( + CornerFamily.ROUNDED, + cornerA + ) + + this.setBottomRightCorner( + CornerFamily.ROUNDED, + cornerA + ) + }.build() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/im/chat/MVHChatterBoxStart.java b/app/src/main/java/com/chwl/app/ui/im/chat/MVHChatterBoxStart.java new file mode 100644 index 0000000..64c28da --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/chat/MVHChatterBoxStart.java @@ -0,0 +1,169 @@ +package com.chwl.app.ui.im.chat; + +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.netease.nim.uikit.business.session.helper.MessageListPanelHelper; +import com.netease.nim.uikit.business.session.viewholder.MsgViewHolderBase; +import com.netease.nim.uikit.common.ui.recyclerview.adapter.BaseMultiItemFetchLoadAdapter; +import com.netease.nimlib.sdk.msg.MessageBuilder; +import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum; +import com.netease.nimlib.sdk.msg.model.CustomMessageConfig; +import com.netease.nimlib.sdk.msg.model.IMMessage; +import com.chwl.app.R; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.im.chatterbox.ChatterBoxModel; +import com.chwl.core.im.chatterbox.bean.TopicBoxItemInfo; +import com.chwl.core.im.custom.bean.ChatterBoxAttachment; +import com.chwl.core.im.custom.bean.DiceThrowAttachment; +import com.chwl.core.manager.IMNetEaseManager; +import com.chwl.library.utils.ResUtil; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import io.reactivex.functions.BiConsumer; + +public class MVHChatterBoxStart extends MsgViewHolderBase implements View.OnClickListener { + private static final String FLAG_THROW = "throwed"; + private TextView tvThrowDice; + private LinearLayout llChatTaskList; + private String sessionId; + + public static boolean isFromHome = false; + + public MVHChatterBoxStart(BaseMultiItemFetchLoadAdapter adapter) { + super(adapter); + } + + @Override + protected int getContentResId() { + return R.layout.layout_mvh_chatter_box_start; + } + + @Override + protected void inflateContentView() { + tvThrowDice = findViewById(R.id.tv_throw_dice); + llChatTaskList = findViewById(R.id.ll_chat_task_list); + tvThrowDice.setOnClickListener(this); + + } + + @Override + protected void bindContentView() { + contentContainer.setBackgroundResource(0); + llChatTaskList.removeAllViews(); + ChatterBoxAttachment attachment = (ChatterBoxAttachment) message.getAttachment(); + sessionId = message.getSessionId(); + + long startTime = attachment.startTime; + List taskList = attachment.listArray; + + if (taskList != null && taskList.size() > 0) { + + for (int i = 0; i < taskList.size(); i++) { + if (i == 11) // 最多展示11条数据 2~12 + break; + + View item = LayoutInflater.from(context).inflate(R.layout.item_chat_task, null); + TextView tvNum = item.findViewById(R.id.tv_task_num); + tvNum.setText(String.valueOf(i + 2)); + + TextView tvDescription = item.findViewById(R.id.tv_task_description); + tvDescription.setText("" + taskList.get(i).getContent()); + + llChatTaskList.addView(item); + } + + } + + boolean canClick; + Map map = message.getLocalExtension(); + + if (startTime != 0L && System.currentTimeMillis() - startTime >= 3 * 24 * 60 * 60 * 1000) { + canClick = false; + tvThrowDice.setText(ResUtil.getString(R.string.im_chat_mvhchatterboxstart_01)); + + } else { + + if (map == null) { + canClick = true; + } else { + Object valueObject = map.get(FLAG_THROW); + if (valueObject != null) { + boolean value = (boolean) map.get(FLAG_THROW); + canClick = !value; + } else { + canClick = true; + } + } + + tvThrowDice.setText(canClick ? ResUtil.getString(R.string.im_chat_mvhchatterboxstart_02) : ResUtil.getString(R.string.im_chat_mvhchatterboxstart_03)); + + } + + + tvThrowDice.setBackgroundResource(canClick ? R.drawable.chat_button_say : R.drawable.chat_button_say_unenable); + tvThrowDice.setEnabled(canClick); + + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.tv_throw_dice: + + if (tvThrowDice.isEnabled()) { + + } + tvThrowDice.setEnabled(false); + + int pointCount = (int) (1 + Math.random() * 6); + Log.i("pointCount", "" + pointCount); + + DiceThrowAttachment diceThrowAttachment = new DiceThrowAttachment(); + diceThrowAttachment.pointCount = pointCount; + CustomMessageConfig customMessageConfig = new CustomMessageConfig(); + customMessageConfig.enablePush = false; + IMMessage imMessage = MessageBuilder.createCustomMessage(sessionId, + SessionTypeEnum.P2P, "", diceThrowAttachment, customMessageConfig); + + // 发送掷骰子自定义消息 + IMNetEaseManager.get().sendMessageSingle(imMessage).subscribe(new BiConsumer() { + @Override + public void accept(IMMessage imMessage, Throwable throwable) throws Exception { + if (imMessage != null) { + MessageListPanelHelper.getInstance().notifyAddMessage(imMessage); + + // 更新消息状态 + Map map = message.getLocalExtension(); + if (map == null) { + map = new HashMap<>(); + map.put(FLAG_THROW, true); + message.setLocalExtension(map); + IMNetEaseManager.get().updateMessageToLocal(message); + adapter.notifyDataSetChanged(); + + } + + topicBoxReport(AuthModel.get().getCurrentUid(), Long.valueOf(imMessage.getSessionId())); + + } else + tvThrowDice.setEnabled(true); + + } + }); + + break; + } + + } + + private void topicBoxReport(long from, long to) { + ChatterBoxModel.get().topicBoxMsgReport(from, to, ChatterBoxModel.FLAG_TYPE_THROW_DICE).subscribe(); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderAudioParty.java b/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderAudioParty.java new file mode 100644 index 0000000..b658ed5 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderAudioParty.java @@ -0,0 +1,78 @@ +package com.chwl.app.ui.im.chat; + +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.core.content.ContextCompat; + +import com.netease.nim.uikit.business.session.viewholder.MsgViewHolderBase; +import com.netease.nim.uikit.common.ui.recyclerview.adapter.BaseMultiItemFetchLoadAdapter; +import com.chwl.app.R; +import com.chwl.app.avroom.activity.AVRoomActivity; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.miniworld.bean.OpenAudioPartyAttachment; +import com.chwl.core.miniworld.model.MiniWorldHelper; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; + +public class MsgViewHolderAudioParty extends MsgViewHolderBase implements View.OnClickListener { + private ImageView ivIcAudioParty; + private TextView tvLabel; + private View container; + + public MsgViewHolderAudioParty(BaseMultiItemFetchLoadAdapter adapter) { + super(adapter); + } + + @Override + protected int getContentResId() { + return R.layout.msg_open_audio_party; + } + + @Override + protected void inflateContentView() { + ivIcAudioParty = findViewById(R.id.iv_ic_audio_party); + tvLabel = findViewById(R.id.tv_label_audio_party); + container = findViewById(R.id.layout_container); + } + + @Override + protected void bindContentView() { + OpenAudioPartyAttachment attachment = (OpenAudioPartyAttachment) message.getAttachment(); + + if (message.getFromAccount().equals(String.valueOf(AuthModel.get().getCurrentUid()))) { // 自己 + contentContainer.setBackgroundResource(R.drawable.bg_ap_water_drop_self); + ivIcAudioParty.setImageResource(R.drawable.ic_msg_audio_party_white); + tvLabel.setTextColor(ContextCompat.getColor(tvLabel.getContext(), R.color.white)); + tvLabel.setCompoundDrawablesWithIntrinsicBounds(null, null, ContextCompat.getDrawable(tvLabel.getContext(), R.drawable.ic_msg_audio_party_arrow_white), null); + + } else if (attachment.isOwnerFlag()) { // 群主 + contentContainer.setBackgroundResource(R.drawable.bg_ap_water_drop_owner); + ivIcAudioParty.setImageResource(R.drawable.ic_msg_audio_party_white); + tvLabel.setTextColor(ContextCompat.getColor(tvLabel.getContext(), R.color.white)); + tvLabel.setCompoundDrawablesWithIntrinsicBounds(null, null, ContextCompat.getDrawable(tvLabel.getContext(), R.drawable.ic_msg_audio_party_arrow_white), null); + + } else { + contentContainer.setBackgroundResource(R.drawable.bg_nim_water_drop_other); + ivIcAudioParty.setImageResource(R.drawable.ic_msg_audio_party_color); + tvLabel.setTextColor(ContextCompat.getColor(tvLabel.getContext(), R.color.color_FE6974)); + tvLabel.setCompoundDrawablesWithIntrinsicBounds(null, null, ContextCompat.getDrawable(tvLabel.getContext(), R.drawable.ic_msg_audio_party_arrow), null); + + } + + container.setOnClickListener(this); + + } + + @Override + public void onClick(View v) { + OpenAudioPartyAttachment attachment = (OpenAudioPartyAttachment) message.getAttachment(); + if (attachment == null || attachment.getRoomUid() == 0) { + SingleToastUtil.showToast(ResUtil.getString(R.string.im_chat_msgviewholderaudioparty_01)); + return; + } + MiniWorldHelper.report(attachment.getWorldId(), MiniWorldHelper.TYPE_AUDIO_PARTY_JOIN); + AVRoomActivity.start(v.getContext(), attachment.getRoomUid()); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderChatHint.java b/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderChatHint.java new file mode 100644 index 0000000..6fdffe3 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderChatHint.java @@ -0,0 +1,51 @@ +package com.chwl.app.ui.im.chat; + +import android.widget.TextView; +import com.netease.nim.uikit.business.session.viewholder.MsgViewHolderBase; +import com.netease.nim.uikit.common.ui.recyclerview.adapter.BaseMultiItemFetchLoadAdapter; +import com.chwl.app.R; +import com.chwl.core.im.custom.bean.ChatHintAttachment; + +public class MsgViewHolderChatHint extends MsgViewHolderBase { + + private TextView tvContent; + + public MsgViewHolderChatHint(BaseMultiItemFetchLoadAdapter adapter) { + super(adapter); + } + + @Override + protected int getContentResId() { + return R.layout.layout_msg_view_holder_chat_hint; + } + + @Override + protected boolean isMiddleItem() { + return true; + } + + @Override + protected void inflateContentView() { + tvContent = findViewById(R.id.tv_content); + } + + @Override + protected boolean isShowHeadImage() { + return false; + } + + @Override + protected boolean shouldDisplayReceipt() { + return false; + } + + @Override + protected void bindContentView() { + ChatHintAttachment attachment = (ChatHintAttachment) message.getAttachment(); + if (attachment != null) { + String content = attachment.getContent(); + tvContent.setText(content); + } + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderConfirm.java b/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderConfirm.java new file mode 100644 index 0000000..58e479e --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderConfirm.java @@ -0,0 +1,217 @@ +package com.chwl.app.ui.im.chat; + +import android.graphics.Color; +import android.graphics.Typeface; +import android.view.View; +import android.widget.TextView; + +import com.chwl.app.R; +import com.chwl.core.gift.bean.MsgConfirmEntity; +import com.chwl.core.gift.bean.MsgConfirmStyleBean; +import com.chwl.core.im.custom.bean.MsgConfirmMsgAttachment; +import com.chwl.core.manager.IMNetEaseManager; +import com.chwl.core.module_hall.hall.HallModel; +import com.chwl.core.module_hall.hall.bean.ApplyResult; +import com.chwl.core.utils.net.BeanObserver; +import com.chwl.library.common.util.OtherExtKt; +import com.chwl.library.utils.SingleToastUtil; +import com.example.lib_utils.spannable.SpannableTextBuilder; +import com.netease.nim.uikit.business.session.viewholder.MsgViewHolderBase; +import com.netease.nim.uikit.common.ui.recyclerview.adapter.BaseMultiItemFetchLoadAdapter; +import com.netease.nimlib.sdk.NIMClient; +import com.netease.nimlib.sdk.msg.MsgService; +import com.netease.nimlib.sdk.msg.model.IMMessage; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + *

文字消息holder

+ * + * @author jiahui + * @date 2018/1/10 + */ +public class MsgViewHolderConfirm extends MsgViewHolderBase { + + private TextView mTitle; + private TextView mContent; + private TextView mConfirm; + private TextView mCancel; + private View mSpace; + + public MsgViewHolderConfirm(BaseMultiItemFetchLoadAdapter adapter) { + super(adapter); + } + + @Override + protected int getContentResId() { + return R.layout.im_customer_msg_confirm; + } + + @Override + protected void inflateContentView() { + mTitle = findViewById(R.id.title); + mContent = findViewById(R.id.content); + mConfirm = findViewById(R.id.confirm); + mCancel = findViewById(R.id.cancel); + mSpace = findViewById(R.id.space1); + } + + @Override + protected void bindContentView() { + + IMMessage imMessage = IMNetEaseManager.get().queryMessageByUuid(message.getUuid()); + if (imMessage == null || imMessage.getAttachment() == null) { + return; + } + if (!(imMessage.getAttachment() instanceof MsgConfirmMsgAttachment)) { + return; + } + MsgConfirmMsgAttachment attachment = (MsgConfirmMsgAttachment) imMessage.getAttachment(); + MsgConfirmEntity data = attachment.getMsgConfirmEntity(); + if (data == null) { + return; + } + + Boolean handleApply; + if (message.getLocalExtension() != null) { + Map localExtension = message.getLocalExtension(); + if (localExtension.containsKey("handleApply")){ + Object handleApplyValue = localExtension.get("handleApply"); + if (handleApplyValue instanceof Boolean) { + handleApply = (boolean) handleApplyValue; + } else { + handleApply = null; + } + } else { + handleApply = null; + } + } else { + handleApply = null; + } + + +// MsgAttachment attachment = message.getAttachment(); +// if(attachment instanceof MsgConfirmMsgAttachment){ +// MsgConfirmEntity data = ((MsgConfirmMsgAttachment) attachment).getMsgConfirmEntity(); + if (data != null) { + + if (OtherExtKt.isVerify(data.getTitle())) { + mTitle.setText(data.getTitle()); + if (data.getTitleFontSize() > 0) { + mTitle.setTextSize(data.getTitleFontSize()); + } + setTextStyles(mTitle,data.getTitle(),data.getTitleStyles()); + } + + + if (OtherExtKt.isVerify(data.getContent())) { + mContent.setText(data.getContent()); + if (data.getContentFontSize() > 0) { + mContent.setTextSize(data.getContentFontSize()); + } + setTextStyles(mContent,data.getContent(),data.getContentsStyles()); + } + + + + + + mConfirm.setOnClickListener(v -> { + handleApply(true,data.getConfirmUrl()); + }); + mCancel.setOnClickListener(v -> { + handleApply(false,data.getCancelUrl()); + }); + + + if (handleApply != null){ + OtherExtKt.setVis(mConfirm,false,false); + OtherExtKt.setVis(mCancel,false,false); + }else { + if (data.isDef()) { + OtherExtKt.setVis(mConfirm,true,false); + OtherExtKt.setVis(mCancel,true,false); + }else if (data.isConfirm()) { + OtherExtKt.setVis(mConfirm,true,false); + OtherExtKt.setVis(mCancel,false,false); + }else if (data.isCancel()) { + OtherExtKt.setVis(mConfirm,false,false); + OtherExtKt.setVis(mCancel,true,false); + }else { + OtherExtKt.setVis(mConfirm,false,false); + OtherExtKt.setVis(mCancel,false,false); + } + } + + OtherExtKt.postSafe(mSpace, () -> { + OtherExtKt.setViewWH(mConfirm,mSpace.getWidth(), null,false); + OtherExtKt.setViewWH(mCancel,mSpace.getWidth(), null,false); + return null; + }); + + } +// } + } + + private void setTextStyles(TextView textView, String title,List titleStyles) { + if (OtherExtKt.isVerify(titleStyles)) { + List textStyles = new ArrayList<>(); + for (int i = 0; i < titleStyles.size(); i++) { + MsgConfirmStyleBean bean = titleStyles.get(i); + SpannableTextBuilder.TextStyleBean textStyle = new SpannableTextBuilder.TextStyleBean(); + if (OtherExtKt.isVerify(bean.content)) { + textStyle.setText(bean.content); + } + if (OtherExtKt.isVerify(bean.fontColor)) { + textStyle.setTextColor(Color.parseColor(bean.fontColor)); + } + + if (bean.isFontBold()) { + textStyle.setTextStyle(Typeface.BOLD); + } + + if (bean.getFontSize() > 0) { + textStyle.setTextSize(bean.getFontSize()); + } + textStyles.add(textStyle); + } + new SpannableTextBuilder(textView).appendText(title).addTextStyleListAll(textStyles).apply(); + } + } + + private void handleApply(boolean isConfirm,String url) { + + HallModel.get().confirm(url) + .subscribe(new BeanObserver<>() { + @Override + public void onErrorMsg(String error) { + SingleToastUtil.showToast(error); + + + } + + @Override + public void onSuccess(ApplyResult result) { + + Map localExtension = new HashMap<>(); + localExtension.put("handleApply",isConfirm); + + message.setLocalExtension(localExtension); + IMMessage msg = IMNetEaseManager.get().queryMessageByUuid(message.getUuid()); + if (msg != null) { + msg.setLocalExtension(localExtension); + NIMClient.getService(MsgService.class).updateIMMessage(msg); + } + + bindContentView(); + + } + }); + + } + + +} diff --git a/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderContent.java b/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderContent.java new file mode 100644 index 0000000..4526c04 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderContent.java @@ -0,0 +1,66 @@ +package com.chwl.app.ui.im.chat; + +import android.view.View; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.netease.nim.uikit.business.session.viewholder.MsgViewHolderBase; +import com.netease.nim.uikit.common.ui.recyclerview.adapter.BaseMultiItemFetchLoadAdapter; +import com.netease.nim.uikit.common.util.string.StringUtil; +import com.chwl.app.R; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.app.ui.webview.CommonWebViewActivity; +import com.chwl.core.im.custom.bean.NoticeAttachment; + +/** + * Created by chenran on 2017/9/21. + */ + +public class MsgViewHolderContent extends MsgViewHolderBase implements View.OnClickListener { + + private ImageView bg; + private TextView title; + private TextView desc; + private LinearLayout container; + + public MsgViewHolderContent(BaseMultiItemFetchLoadAdapter adapter) { + super(adapter); + } + + @Override + protected int getContentResId() { + return R.layout.layout_msg_view_holder_content; + } + + @Override + protected void inflateContentView() { + bg = findViewById(R.id.bg_image); + title = findViewById(R.id.title); + desc = findViewById(R.id.desc); + container = findViewById(R.id.layout); + } + + @Override + protected void bindContentView() { + NoticeAttachment attachment = (NoticeAttachment) message.getAttachment(); + if (!StringUtil.isEmpty(attachment.getPicUrl())) { + bg.setVisibility(View.VISIBLE); + ImageLoadUtils.loadImage(bg.getContext(), attachment.getPicUrl(), bg, R.drawable.default_cover); + } else { + bg.setVisibility(View.GONE); + } + + title.setText(attachment.getTitle()); + desc.setText(attachment.getDesc()); + container.setOnClickListener(this); + } + + @Override + public void onClick(View v) { + NoticeAttachment attachment = (NoticeAttachment) message.getAttachment(); + if (!StringUtil.isEmpty(attachment.getWebUrl())) { + CommonWebViewActivity.start(context, attachment.getWebUrl()); + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderCpRelationalConfirm.java b/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderCpRelationalConfirm.java new file mode 100644 index 0000000..845c66c --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderCpRelationalConfirm.java @@ -0,0 +1,173 @@ +package com.chwl.app.ui.im.chat; + +import android.view.View; +import android.widget.TextView; + +import com.chwl.app.R; +import com.chwl.app.ui.utils.CpUtils; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.gift.bean.MsgCpRelationalChangeEntity; +import com.chwl.core.helper.NetViewModel; +import com.chwl.core.im.custom.bean.MsgCpRelationalChangeConfirmAttachment; +import com.chwl.core.manager.IMNetEaseManager; +import com.chwl.library.common.util.OtherExtKt; +import com.chwl.library.utils.SingleToastUtil; +import com.example.lib_utils.ktx.ResourcesKtxKt; +import com.netease.nim.uikit.business.session.viewholder.MsgViewHolderBase; +import com.netease.nim.uikit.common.ui.recyclerview.adapter.BaseMultiItemFetchLoadAdapter; +import com.netease.nimlib.sdk.NIMClient; +import com.netease.nimlib.sdk.msg.MsgService; +import com.netease.nimlib.sdk.msg.model.IMMessage; + +import java.util.HashMap; +import java.util.Map; + +/** + *

文字消息holder

+ * + * @author jiahui + * @date 2018/1/10 + */ +public class MsgViewHolderCpRelationalConfirm extends MsgViewHolderBase { + + private TextView mContent; + private TextView mConfirm; + private TextView mCancel; + private View mSpace; + + public MsgViewHolderCpRelationalConfirm(BaseMultiItemFetchLoadAdapter adapter) { + super(adapter); + } + + @Override + protected boolean isShowBubble() { + return false; + } + + @Override + protected int getContentResId() { + return R.layout.im_customer_msg_cp_relational_confirm; + } + + @Override + protected void inflateContentView() { + mContent = findViewById(R.id.content); + mConfirm = findViewById(R.id.confirm); + mCancel = findViewById(R.id.cancel); + mSpace = findViewById(R.id.space1); + } + + @Override + protected void bindContentView() { + + IMMessage imMessage = IMNetEaseManager.get().queryMessageByUuid(message.getUuid()); + if (imMessage == null || imMessage.getAttachment() == null) { + return; + } + if (!(imMessage.getAttachment() instanceof MsgCpRelationalChangeConfirmAttachment)) { + return; + } + MsgCpRelationalChangeConfirmAttachment attachment = (MsgCpRelationalChangeConfirmAttachment) imMessage.getAttachment(); + MsgCpRelationalChangeEntity data = attachment.getMsgData(); + if (data == null) { + return; + } + + Boolean handleApply; + if (message.getLocalExtension() != null) { + Map localExtension = message.getLocalExtension(); + if (localExtension.containsKey("handleApply")){ + Object handleApplyValue = localExtension.get("handleApply"); + if (handleApplyValue instanceof Boolean) { + handleApply = (boolean) handleApplyValue; + } else { + handleApply = null; + } + } else { + handleApply = null; + } + } else { + handleApply = null; + } + + if (data != null) { + + StringBuffer contentStr = new StringBuffer(); + contentStr.append(ResourcesKtxKt.getString(R.string.v26_the_other_invites_you_to_change_the_relationship_to_s)); + contentStr.append(CpUtils.INSTANCE.getCpRelationalNames(data.relationNameType)); + mContent.setText(contentStr.toString()); + + + mCancel.setText(ResourcesKtxKt.getString(R.string.Reject)); + + + + if (handleApply != null){ + OtherExtKt.setVis(mConfirm,false,false); + OtherExtKt.setVis(mCancel,true,false); + mCancel.setText(handleApply ? ResourcesKtxKt.getString(R.string.v26_accepted) : ResourcesKtxKt.getString(R.string.v26_rejected)); + mConfirm.setEnabled(false); + mCancel.setEnabled(false); + }else { + if (AuthModel.get().isMy(data.uid)) { + OtherExtKt.setVis(mConfirm,false,false); + OtherExtKt.setVis(mCancel,false,false); + mConfirm.setEnabled(false); + mCancel.setEnabled(false); + } else { + OtherExtKt.setVis(mConfirm,true,false); + OtherExtKt.setVis(mCancel,true,false); + + mConfirm.setEnabled(true); + mCancel.setEnabled(true); + + mConfirm.setOnClickListener(v -> { + handleApply(true,data); + }); + mCancel.setOnClickListener(v -> { + handleApply(false, data); + }); + } + } + + + + OtherExtKt.postSafe(mSpace, () -> { + OtherExtKt.setViewWH(mConfirm,mSpace.getWidth(), null,false); + OtherExtKt.setViewWH(mCancel,mSpace.getWidth(), null,false); + return null; + }); + + } + } + + + + private void handleApply(boolean isConfirm, MsgCpRelationalChangeEntity data) { + + NetViewModel.get().changeCpRelationType(data.recordId,isConfirm? 1 : 2) + .doOnSuccess(s -> { + + Map localExtension = new HashMap<>(); + localExtension.put("handleApply",isConfirm); + + message.setLocalExtension(localExtension); + IMMessage msg = IMNetEaseManager.get().queryMessageByUuid(message.getUuid()); + if (msg != null) { + msg.setLocalExtension(localExtension); + NIMClient.getService(MsgService.class).updateIMMessage(msg); + } + + bindContentView(); + }) + .doOnError(throwable -> { + if (throwable != null && throwable.getMessage() != null) { + SingleToastUtil.showToast(throwable.getMessage()); + } + }) + .subscribe(); + + } + + +} diff --git a/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderCpRelationalNotify.java b/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderCpRelationalNotify.java new file mode 100644 index 0000000..fa79297 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderCpRelationalNotify.java @@ -0,0 +1,82 @@ +package com.chwl.app.ui.im.chat; + +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import com.chwl.app.R; +import com.chwl.app.ui.utils.CpUtils; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.gift.bean.MsgCpRelationalNotifyEntity; +import com.chwl.core.im.custom.bean.MsgCpRelationalChangeNotifyAttachment; +import com.chwl.library.common.util.OtherExtKt; +import com.example.lib_utils.ktx.ResourcesKtxKt; +import com.netease.nim.uikit.business.session.viewholder.MsgViewHolderBase; +import com.netease.nim.uikit.common.ui.recyclerview.adapter.BaseMultiItemFetchLoadAdapter; + +/** + *

文字消息holder

+ * + * @author jiahui + * @date 2018/1/10 + */ +public class MsgViewHolderCpRelationalNotify extends MsgViewHolderBase { + + private ImageView icon; + private ImageView avatar; + private ImageView avatar2; + private TextView text; + private FrameLayout avatarLayout; + + public MsgViewHolderCpRelationalNotify(BaseMultiItemFetchLoadAdapter adapter) { + super(adapter); + } + @Override + protected boolean isShowBubble() { + return false; + } + + + @Override + protected int getContentResId() { + return R.layout.im_customer_msg_cp_relational_notify; + } + + @Override + protected void inflateContentView() { + icon = findViewById(R.id.icon); + avatar = findViewById(R.id.avatar); + avatar2 = findViewById(R.id.avatar2); + text = findViewById(R.id.text); + avatarLayout = findViewById(R.id.avatarLayout); + } + + @Override + protected void bindContentView() { + + MsgCpRelationalChangeNotifyAttachment attachment = (MsgCpRelationalChangeNotifyAttachment) message.getAttachment(); + MsgCpRelationalNotifyEntity data = attachment.getMsgData(); + if (data == null) { + return; + } + + OtherExtKt.setRL(icon); + + ImageLoadUtils.loadAvatar(avatar.getContext(), data.avatar, avatar); + ImageLoadUtils.loadAvatar(avatar2.getContext(), data.loverAvatar, avatar2); + + if (data.getStatus() == 1) { + StringBuffer str = new StringBuffer(); + str.append(ResourcesKtxKt.getString(R.string.v26_your_relationship_has_been_changed_to_s)); + str.append(CpUtils.INSTANCE.getCpRelationalNames(data.relationNameType)); + text.setText(str.toString()); + }else { + text.setText(ResourcesKtxKt.getString(R.string.v26_cp_change_relationships_rejects)); + } + OtherExtKt.setVis(avatarLayout,data.getStatus() == 1,false); + OtherExtKt.setVis(icon,data.getStatus() == 1,false); + } + + + +} diff --git a/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderEventStartNotify.java b/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderEventStartNotify.java new file mode 100644 index 0000000..a08c067 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderEventStartNotify.java @@ -0,0 +1,110 @@ +package com.chwl.app.ui.im.chat; + +import android.widget.ImageView; +import android.widget.TextView; + +import com.chwl.app.R; +import com.chwl.app.avroom.activity.AVRoomActivity; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.app.ui.utils.ImageLoadKt; +import com.chwl.core.gift.bean.MsgEventStartNotifyEntity; +import com.chwl.core.im.custom.bean.MsgEventStartNotifyAttachment; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.widget.text.DrawableTextView; +import com.example.lib_utils.ktx.ResourcesKtxKt; +import com.netease.nim.uikit.business.session.viewholder.MsgViewHolderBase; +import com.netease.nim.uikit.common.ui.recyclerview.adapter.BaseMultiItemFetchLoadAdapter; + +/** + *

文字消息holder

+ * + * @author jiahui + * @date 2018/1/10 + */ +public class MsgViewHolderEventStartNotify extends MsgViewHolderBase { + + private ImageView mPic; + private TextView mRoomId; + private TextView mTitle; + private DrawableTextView mNext; + + public MsgViewHolderEventStartNotify(BaseMultiItemFetchLoadAdapter adapter) { + super(adapter); + } + + @Override + protected boolean isShowBubble() { + return false; + } + + @Override + protected int getContentResId() { + return R.layout.im_customer_msg_event_notify; + } + + @Override + protected void inflateContentView() { + mPic = findViewById(R.id.pic); + mRoomId = findViewById(R.id.roomId); + mTitle = findViewById(R.id.title); + mNext = findViewById(R.id.next); + } + + @Override + protected void bindContentView() { + if (message.getAttachment() instanceof MsgEventStartNotifyAttachment) { + MsgEventStartNotifyAttachment attachment = (MsgEventStartNotifyAttachment) message.getAttachment(); + if (attachment != null && attachment.getMsgData() != null) { + MsgEventStartNotifyEntity msgData = attachment.getMsgData(); + + ImageLoadKt.loadImage(mPic,msgData.eventBanner); + + mRoomId.setText(ResourcesKtxKt.getString(R.string.v_27_Room_ID_s,msgData.roomErbanNO)); + + // "type": 1,//1-发送给粉丝,2-发送给自己 + if (msgData.type == 1) { + mTitle.setText(ResourcesKtxKt.getString(R.string.v_27_Event_Start_Notify_other)); + } else { + mTitle.setText(ResourcesKtxKt.getString(R.string.v_27_Event_Start_Notify_self)); + } + + mNext.setOnClickListener(v -> { + try { + if (AvRoomDataManager.get().getRoomUid() == msgData.roomUid) { +// ToastUtils.show(R.string.erban_service_daemonservice_03); + return; + } + DialogManager mDialogManager = new DialogManager(context); + mDialogManager.showOkCancelDialog( + ResUtil.getString(R.string.changeRoomTips), + true, new DialogManager.OkCancelDialogListener() { + @Override + public void onCancel() { + mDialogManager.dismissDialog(); + } + + @Override + public void onOk() { + mDialogManager.dismissDialog(); + if (AvRoomDataManager.get().getRoomUid() != msgData.roomUid) { + AVRoomActivity.start(context, msgData.roomUid); + } + } + }); + } catch (Exception e) { + } + }); + + + } + } + + + } + + + + + +} diff --git a/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderFairy.java b/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderFairy.java new file mode 100644 index 0000000..d992f07 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderFairy.java @@ -0,0 +1,93 @@ +package com.chwl.app.ui.im.chat; + +import android.annotation.SuppressLint; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; +import com.netease.nim.uikit.business.session.viewholder.MsgViewHolderBase; +import com.netease.nim.uikit.common.ui.recyclerview.adapter.BaseMultiItemFetchLoadAdapter; +import com.chwl.app.R; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.im.custom.bean.CustomAttachment; +import com.chwl.core.im.custom.bean.FairySendAttachment; + +import java.util.Map; + +/** + * Created by chenran on 2018/1/2. + */ + +public class MsgViewHolderFairy extends MsgViewHolderBase implements View.OnClickListener { + private final static String IS_SEND = "afafagag"; + private TextView tvContent; + private ImageView ivFairyIcon; + private View flIconBg; + private View tvView; + + public MsgViewHolderFairy(BaseMultiItemFetchLoadAdapter adapter) { + super(adapter); + } + + @Override + protected int getContentResId() { + return R.layout.layout_msg_view_holder_fairy; + } + + @Override + protected void inflateContentView() { + tvContent = findViewById(R.id.tv_content); + ivFairyIcon = findViewById(R.id.iv_fairy_icon); + flIconBg = findViewById(R.id.fl_icon_bg); + tvView = findViewById(R.id.tv_view); + } + + @Override + protected void bindContentView() { + FairySendAttachment attachment = (FairySendAttachment) message.getAttachment(); + + tvContent.setText(attachment.getMsgContent()); + ImageLoadUtils.loadImage(context, attachment.getElfPicUrl(), ivFairyIcon); + if (isReceivedMessage()) { + flIconBg.setBackgroundResource(R.drawable.shape_white_8dp_round); + } else { + flIconBg.setBackgroundResource(R.drawable.shape_f5f4fa_8dp_round); + } + Map localExtension = message.getLocalExtension(); + boolean isSend = false; + if (localExtension != null && localExtension.containsKey(IS_SEND)) { + isSend = (boolean) localExtension.get(IS_SEND); + } + boolean isAskFor = attachment.getSecond() == CustomAttachment.CUSTOM_MSG_SUB_FAIRY_ASK_FOR; + + if (!isSend && isAskFor && attachment.getUid() != AuthModel.get().getCurrentUid()) { + tvView.setVisibility(View.VISIBLE); + contentContainer.setOnClickListener(this); + } else { + tvView.setVisibility(View.GONE); + contentContainer.setOnClickListener(null); + } + } + + @SuppressLint("CheckResult") + @Override + public void onClick(View v) { +// FairySendAttachment attachment = (FairySendAttachment) message.getAttachment(); +// SimpleUserInfo userInfo = new SimpleUserInfo(attachment.getNick(), attachment.getUid(), 0, "", ""); +// FairyInfo fairyInfo = new FairyInfo(attachment.getElfId(), 1, 1, attachment.getElfName(), attachment.getElfPicUrl(), 0); +// Bundle bundle = new Bundle(); +// bundle.putSerializable("userInfo", userInfo); +// bundle.putSerializable("fairyInfo", fairyInfo); +// bundle.putBoolean("isSend", true); +// MyFairySendDialog sendDialog = MyFairySendDialog.Companion.newInstance(bundle, userInfo); +// sendDialog.setOnSendListener(() -> { +// Map localExtension = message.getLocalExtension(); +// if (localExtension == null) localExtension = new HashMap<>(); +// localExtension.put(IS_SEND, true); +// message.setLocalExtension(localExtension); +// IMNetEaseManager.get().updateMessageToLocal(message); +// return null; +// }); +// sendDialog.show(context); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderGift.java b/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderGift.java new file mode 100644 index 0000000..cc7fc8e --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderGift.java @@ -0,0 +1,71 @@ +package com.chwl.app.ui.im.chat; + +import android.text.TextUtils; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.netease.nim.uikit.business.session.viewholder.MsgViewHolderBase; +import com.netease.nim.uikit.common.ui.recyclerview.adapter.BaseMultiItemFetchLoadAdapter; +import com.chwl.app.R; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.gift.GiftModel; +import com.chwl.core.gift.bean.GiftInfo; +import com.chwl.core.im.custom.bean.GiftAttachment; +import com.chwl.library.utils.ResUtil; + +/** + * Created by chenran on 2017/10/3. + */ + +public class MsgViewHolderGift extends MsgViewHolderBase { + private ImageView avatar; + private TextView number; + private TextView giftName; + private TextView tvTargetNick; + private LinearLayout container; + private FrameLayout flGiftImg; + + public MsgViewHolderGift(BaseMultiItemFetchLoadAdapter adapter) { + super(adapter); + } + + @Override + protected int getContentResId() { + return R.layout.layout_msg_view_holder_gift; + } + + @Override + protected void inflateContentView() { + avatar = findViewById(R.id.avatar); + number = findViewById(R.id.gift_number); + container = findViewById(R.id.layout_container); + giftName = findViewById(R.id.gift_name); + tvTargetNick = findViewById(R.id.tv_target_nick); + flGiftImg = findViewById(R.id.fl_gift_img); + } + + @Override + protected void bindContentView() { + GiftAttachment attachment = (GiftAttachment) message.getAttachment(); + GiftInfo giftInfo = attachment.getGiftReceiveInfo().getGift(); + giftInfo = giftInfo == null ? + GiftModel.get().findGiftInfoById(attachment.getGiftReceiveInfo().getGiftId()) : giftInfo; + + boolean isSelf = attachment.getGiftReceiveInfo().getUid() == AuthModel.get().getCurrentUid(); + flGiftImg.setBackgroundResource(isSelf ? R.drawable.bg_msg_gift_img : R.drawable.bg_msg_gift_img_normal); + + if (giftInfo != null) { + ImageLoadUtils.loadImage(avatar.getContext(), giftInfo.getGiftUrl(), avatar); + number.setText("X" + attachment.getGiftReceiveInfo().getGiftNum()); + giftName.setText(giftInfo.getGiftName()); + + String targetNick = attachment.getGiftReceiveInfo().getTargetNick(); + if (!TextUtils.isEmpty(targetNick)) { + tvTargetNick.setText(ResUtil.getString(R.string.im_chat_msgviewholdergift_01) + targetNick); + } + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderHello.java b/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderHello.java new file mode 100644 index 0000000..65632c9 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderHello.java @@ -0,0 +1,76 @@ +package com.chwl.app.ui.im.chat; + +import android.annotation.SuppressLint; +import android.view.View; +import android.widget.TextView; + +import com.netease.nim.uikit.business.session.viewholder.MsgViewHolderBase; +import com.netease.nim.uikit.common.ui.recyclerview.adapter.BaseMultiItemFetchLoadAdapter; +import com.chwl.app.R; +import com.chwl.app.avroom.activity.AVRoomActivity; +import com.chwl.core.im.custom.bean.NewbieHelloAttachment; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.core.room.model.AvRoomModel; +import com.chwl.core.utils.net.RxHelper; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; + +import io.reactivex.functions.BiConsumer; + +/** + * Created by chenran on 2018/1/2. + */ + +public class MsgViewHolderHello extends MsgViewHolderBase implements View.OnClickListener{ + private TextView content; + private long inRoomUid; + private String uid; + + public MsgViewHolderHello(BaseMultiItemFetchLoadAdapter adapter) { + super(adapter); + } + + @Override + protected int getContentResId() { + return R.layout.layout_msg_view_holder_hello; + } + + @Override + protected void inflateContentView() { + content = findViewById(R.id.content); + content.setOnClickListener(this); + } + + @Override + protected void bindContentView() { + NewbieHelloAttachment attachment = (NewbieHelloAttachment) message.getAttachment(); + inRoomUid = attachment.getNewbieHelloInfo().getInRoomUid(); + uid = attachment.getNewbieHelloInfo().getUid(); + + content.setText(attachment.getNewbieHelloInfo().getMessage()); + } + + @SuppressLint("CheckResult") + @Override + public void onClick(View v) { + if (inRoomUid == 0)return; + AvRoomModel.get() + .getUserRoom(Long.parseLong(uid)) + .compose(RxHelper.singleMainResult()) + .compose(RxHelper.handleSchAndExce()) + .subscribe(new BiConsumer() { + @Override + public void accept(RoomInfo roomInfo, Throwable throwable) throws Exception { + if (throwable == null) { + if (roomInfo != null && roomInfo.getUid() > 0 && roomInfo.getUid() == inRoomUid) { + AVRoomActivity.start(context, inRoomUid); + } else { + SingleToastUtil.showToast(ResUtil.getString(R.string.im_chat_msgviewholderhello_01)); + } + } else { + SingleToastUtil.showToast(ResUtil.getString(R.string.im_chat_msgviewholderhello_02)); + } + } + }); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderLevel.java b/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderLevel.java new file mode 100644 index 0000000..19a4274 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderLevel.java @@ -0,0 +1,55 @@ +package com.chwl.app.ui.im.chat; + +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.netease.nim.uikit.business.session.viewholder.MsgViewHolderBase; +import com.netease.nim.uikit.common.ui.recyclerview.adapter.BaseMultiItemFetchLoadAdapter; +import com.chwl.app.R; +import com.chwl.app.ui.webview.CommonWebViewActivity; +import com.chwl.core.UriProvider; +import com.chwl.core.im.custom.bean.CustomAttachment; +import com.chwl.core.im.custom.bean.LevelUpAttachment; +import com.chwl.library.utils.ResUtil; + +/** + * Created by chenran on 2017/10/3. + */ + +public class MsgViewHolderLevel extends MsgViewHolderBase { + private ImageView avatar; + private TextView giftName; + private LinearLayout container; + + public MsgViewHolderLevel(BaseMultiItemFetchLoadAdapter adapter) { + super(adapter); + } + + @Override + protected int getContentResId() { + return R.layout.layout_msg_view_holder_level; + } + + @Override + protected void inflateContentView() { + avatar = findViewById(R.id.avatar); + container = findViewById(R.id.layout_container); + giftName = findViewById(R.id.gift_name); + } + + @Override + protected void bindContentView() { + LevelUpAttachment attachment = (LevelUpAttachment) message.getAttachment(); + if (attachment.getSecond() == CustomAttachment.CUSTOM_MSG_EXPER_LEVEL_UP) { + avatar.setImageResource(R.drawable.ic_chat_user_level); + giftName.setText(ResUtil.getString(R.string.im_chat_msgviewholderlevel_01) + attachment.levelName); + container.setOnClickListener(v -> CommonWebViewActivity.start(context, UriProvider.getUserLevelUrl())); + } else if (attachment.getSecond() == CustomAttachment.CUSTOM_MSG_CHARM_LEVEL_UP) { + avatar.setImageResource(R.drawable.ic_chat_charm_level); + giftName.setText(ResUtil.getString(R.string.im_chat_msgviewholderlevel_02) + attachment.levelName); + container.setOnClickListener(v -> CommonWebViewActivity.start(context, UriProvider.getUserLevelUrl())); + } + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderLottery.java b/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderLottery.java new file mode 100644 index 0000000..7ec4de6 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderLottery.java @@ -0,0 +1,40 @@ +package com.chwl.app.ui.im.chat; + +import android.view.View; +import android.widget.TextView; + +import com.netease.nim.uikit.business.session.viewholder.MsgViewHolderBase; +import com.netease.nim.uikit.common.ui.recyclerview.adapter.BaseMultiItemFetchLoadAdapter; +import com.chwl.app.R; + +/** + * Created by chenran on 2018/1/2. + */ + +public class MsgViewHolderLottery extends MsgViewHolderBase implements View.OnClickListener{ + private TextView content; + + public MsgViewHolderLottery(BaseMultiItemFetchLoadAdapter adapter) { + super(adapter); + } + + @Override + protected int getContentResId() { + return R.layout.layout_msg_view_holder_lottery; + } + + @Override + protected void inflateContentView() { + content = findViewById(R.id.content); + content.setOnClickListener(this); + } + + @Override + protected void bindContentView() { + + } + + @Override + public void onClick(View v) { + } +} diff --git a/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderOnline.java b/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderOnline.java new file mode 100644 index 0000000..a00a7ad --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderOnline.java @@ -0,0 +1,69 @@ + +package com.chwl.app.ui.im.chat; + +import android.view.View; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.netease.nim.uikit.business.session.viewholder.MsgViewHolderBase; +import com.netease.nim.uikit.common.ui.recyclerview.adapter.BaseMultiItemFetchLoadAdapter; +import com.netease.nim.uikit.common.util.string.StringUtil; +import com.netease.nimlib.sdk.NIMClient; +import com.netease.nimlib.sdk.uinfo.UserService; +import com.netease.nimlib.sdk.uinfo.model.NimUserInfo; +import com.chwl.app.R; +import com.chwl.app.avroom.activity.AVRoomActivity; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.im.custom.bean.OpenRoomNotiAttachment; +import com.chwl.library.utils.ResUtil; + +/** + * Created by chenran on 2017/9/21. + */ + +public class MsgViewHolderOnline extends MsgViewHolderBase implements View.OnClickListener { + private ImageView avatar; + private TextView nick; + private LinearLayout container; + + public MsgViewHolderOnline(BaseMultiItemFetchLoadAdapter adapter) { + super(adapter); + } + + @Override + protected int getContentResId() { + return R.layout.layout_msg_view_holder_online; + } + + @Override + protected void inflateContentView() { + avatar = findViewById(R.id.avatar); + nick = findViewById(R.id.nick); + container = findViewById(R.id.layout_container); + } + + @Override + protected void bindContentView() { + OpenRoomNotiAttachment attachment = (OpenRoomNotiAttachment) message.getAttachment(); + if (attachment != null) { + if (!StringUtil.isEmpty(attachment.getNick())) { + nick.setText(attachment.getNick() + ResUtil.getString(R.string.im_chat_msgviewholderonline_01)); + ImageLoadUtils.loadAvatar(avatar.getContext(), attachment.getAvatar(), avatar); + } else { + NimUserInfo nimUserInfo = NIMClient.getService(UserService.class).getUserInfo(attachment.getUid() + ""); + if (nimUserInfo != null) { + nick.setText(nimUserInfo.getName() + ResUtil.getString(R.string.im_chat_msgviewholderonline_02)); + ImageLoadUtils.loadAvatar(avatar.getContext(), nimUserInfo.getAvatar(), avatar); + } + } + container.setOnClickListener(this); + } + } + + @Override + public void onClick(View v) { + OpenRoomNotiAttachment attachment = (OpenRoomNotiAttachment) message.getAttachment(); + AVRoomActivity.start(v.getContext(), attachment.getUid()); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderP2PContactRecharge.java b/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderP2PContactRecharge.java new file mode 100644 index 0000000..0953440 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderP2PContactRecharge.java @@ -0,0 +1,81 @@ + +package com.chwl.app.ui.im.chat; + +import android.text.SpannableString; +import android.text.method.LinkMovementMethod; +import android.view.View; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; + +import com.netease.nim.uikit.business.session.viewholder.MsgViewHolderBase; +import com.netease.nim.uikit.common.ui.recyclerview.adapter.BaseMultiItemFetchLoadAdapter; +import com.chwl.app.R; +import com.chwl.app.common.widget.OriginalDrawStatusClickSpan; +import com.chwl.app.utils.ClipboardUtils; +import com.chwl.core.im.custom.bean.OpenRoomNotiAttachment; +import com.chwl.core.im.custom.bean.P2PContactRechargeAttachment; +import com.chwl.library.utils.SingleToastUtil; + +/** + * Created by chenran on 2017/9/21. + */ + +public class MsgViewHolderP2PContactRecharge extends MsgViewHolderBase implements View.OnClickListener { + + + private TextView mTvInstructions; + private String mCopyText; + + public MsgViewHolderP2PContactRecharge(BaseMultiItemFetchLoadAdapter adapter) { + super(adapter); + } + + @Override + protected int getContentResId() { + return R.layout.layout_msg_view_holder_customer_service_recharge; + } + + @Override + protected void inflateContentView() { + mTvInstructions = findViewById(R.id.tv_instructions); + mTvInstructions.setMovementMethod(new LinkMovementMethod()); + mCopyText = context.getString(R.string.copy); + } + + @Override + protected int leftBackground() { + return 0; + } + + @Override + protected void bindContentView() { + P2PContactRechargeAttachment attachment = (P2PContactRechargeAttachment) message.getAttachment(); + String string = context.getString(R.string.tips_cs_recharge, attachment.getIdWeChat(), attachment.getIdLine()); + int first = string.indexOf(mCopyText); + SpannableString spannableString = new SpannableString(string); + spannableString.setSpan(new OriginalDrawStatusClickSpan(ContextCompat.getColor(context, R.color.color_9168FA)) { + @Override + public void onClick(@NonNull View widget) { + ClipboardUtils.copyText(attachment.getIdWeChat()); + SingleToastUtil.showToast(context.getString(R.string.have_copy)); + + } + }, first, first + 2, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE); + int second = string.indexOf(mCopyText, first + 2); + spannableString.setSpan(new OriginalDrawStatusClickSpan(ContextCompat.getColor(context, R.color.color_9168FA)) { + @Override + public void onClick(@NonNull View widget) { + ClipboardUtils.copyText(attachment.getIdLine()); + SingleToastUtil.showToast(context.getString(R.string.have_copy)); + } + }, second, second + 2, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE); + mTvInstructions.setText(spannableString); + } + + @Override + public void onClick(View v) { + + } +} diff --git a/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderRedPacket.java b/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderRedPacket.java new file mode 100644 index 0000000..38e9604 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderRedPacket.java @@ -0,0 +1,47 @@ +package com.chwl.app.ui.im.chat; + +import android.view.View; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.netease.nim.uikit.business.session.viewholder.MsgViewHolderBase; +import com.netease.nim.uikit.common.ui.recyclerview.adapter.BaseMultiItemFetchLoadAdapter; +import com.chwl.app.R; +import com.chwl.core.im.custom.bean.RedPacketAttachment; +import com.chwl.library.utils.ResUtil; + +/** + * Created by chenran on 2017/9/21. + */ + +public class MsgViewHolderRedPacket extends MsgViewHolderBase implements View.OnClickListener { + private TextView text; + private LinearLayout container; + + public MsgViewHolderRedPacket(BaseMultiItemFetchLoadAdapter adapter) { + super(adapter); + } + + @Override + protected int getContentResId() { + return R.layout.layout_msg_view_holder_red_packet; + } + + @Override + protected void inflateContentView() { + text = findViewById(R.id.tip_text); + container = findViewById(R.id.layout_container); + } + + @Override + protected void bindContentView() { + RedPacketAttachment attachment = (RedPacketAttachment) message.getAttachment(); + text.setText(ResUtil.getString(R.string.im_chat_msgviewholderredpacket_01) + attachment.getRedPacketInfo().getPacketName() + ResUtil.getString(R.string.im_chat_msgviewholderredpacket_02)); + container.setOnClickListener(this); + } + + @Override + public void onClick(View v) { +// context.startActivity(new Intent(context, RedBagActivity.class)); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderSkill.java b/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderSkill.java new file mode 100644 index 0000000..8a5d05f --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderSkill.java @@ -0,0 +1,53 @@ +package com.chwl.app.ui.im.chat; +import android.widget.TextView; + +import com.netease.nim.uikit.business.session.viewholder.MsgViewHolderBase; +import com.netease.nim.uikit.common.ui.recyclerview.adapter.BaseMultiItemFetchLoadAdapter; +import com.netease.nimlib.sdk.msg.attachment.MsgAttachment; +import com.chwl.app.R; +import com.chwl.core.im.custom.bean.SkillMsgAttachment; +import com.chwl.core.skill.entity.SkillNotifyEntity; + +/** + *

文字消息holder

+ * + * @author jiahui + * @date 2018/1/10 + */ +public class MsgViewHolderSkill extends MsgViewHolderBase { + private TextView mTvTitle; + private TextView mTvContent; + private SkillMsgAttachment matchAttachment; + + public MsgViewHolderSkill(BaseMultiItemFetchLoadAdapter adapter) { + super(adapter); + } + + @Override + protected int getContentResId() { + return R.layout.layout_msg_view_holder_skill; + } + + @Override + protected void inflateContentView() { + mTvTitle = findViewById(R.id.tv_title); + mTvContent = findViewById(R.id.tv_content); + } + + @Override + protected void bindContentView() { + CharSequence title = ""; + CharSequence content = ""; + MsgAttachment attachment = message.getAttachment(); + if (attachment instanceof SkillMsgAttachment) { + matchAttachment = (SkillMsgAttachment) attachment; + SkillNotifyEntity entity = matchAttachment.getEntity(); + title = entity.getLayout().getTitle().getContent(); + if (!entity.getLayout().getContents().isEmpty()) { + content = entity.getLayout().getContents().get(0).getContent(); + } + } + mTvTitle.setText(title); + mTvContent.setText(content); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderText.java b/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderText.java new file mode 100644 index 0000000..ee98c2c --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/chat/MsgViewHolderText.java @@ -0,0 +1,162 @@ +package com.chwl.app.ui.im.chat; + +import static com.chwl.core.UriProvider.IM_SERVER_URL; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MESS_SUB_CAR_EXPIRE; + +import android.text.style.ForegroundColorSpan; +import android.view.View; +import android.widget.TextView; + +import com.chwl.app.R; +import com.chwl.app.decoration.ui.activity.DressUpTabActivity; +import com.chwl.app.ui.im.RouterHandler; +import com.chwl.app.ui.webview.CommonWebViewActivity; +import com.chwl.app.utils.SpannableBuilder; +import com.chwl.core.UriProvider; +import com.chwl.core.audio.bean.VoiceBottleSayHiInfo; +import com.chwl.core.audio.event.VoiceShakeHeartEvent; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.im.custom.bean.AssistantAttachment; +import com.chwl.core.im.custom.bean.CarAttachment; +import com.chwl.core.im.custom.bean.CarveUpGoldThirdLevelAttachment; +import com.chwl.core.im.custom.bean.CpInviteAttachment; +import com.chwl.core.im.custom.bean.CustomAttachment; +import com.chwl.core.im.custom.bean.NobleAttachment; +import com.chwl.core.im.custom.bean.VoiceBottleShakeHeartAttachment; +import com.chwl.core.manager.IMNetEaseManager; +import com.chwl.library.utils.ResUtil; +import com.netease.nim.uikit.business.session.viewholder.MsgViewHolderBase; +import com.netease.nim.uikit.common.ui.recyclerview.adapter.BaseMultiItemFetchLoadAdapter; +import com.netease.nimlib.sdk.msg.attachment.MsgAttachment; + +import org.greenrobot.eventbus.EventBus; + +import java.util.HashMap; +import java.util.Map; + +/** + *

文字消息holder

+ * + * @author jiahui + * @date 2018/1/10 + */ +public class MsgViewHolderText extends MsgViewHolderBase { + private TextView mTvMsg; + private TextView mTvSee; + private NobleAttachment mNobleAttachment; + private CarAttachment mCarAttachment; + private AssistantAttachment awardAttachment; + private CpInviteAttachment cpInviteAttachment; + + public MsgViewHolderText(BaseMultiItemFetchLoadAdapter adapter) { + super(adapter); + } + + @Override + protected int getContentResId() { + return R.layout.im_customer_msg_text; + } + + @Override + protected void inflateContentView() { + mTvMsg = findViewById(R.id.tv_msg); + mTvSee = findViewById(R.id.tv_see); + } + + @Override + protected void bindContentView() { + CharSequence text = ""; + MsgAttachment attachment = message.getAttachment(); + if(attachment instanceof AssistantAttachment){ + awardAttachment = (AssistantAttachment) attachment; + if(awardAttachment.routerValue != null){ + mTvSee.setVisibility(View.VISIBLE); + } + }else { + mTvSee.setVisibility(View.GONE); + } + if (attachment instanceof CarAttachment) { + mCarAttachment = (CarAttachment) attachment; + text = mCarAttachment.msg; + } else if (attachment instanceof NobleAttachment) { + mNobleAttachment = (NobleAttachment) attachment; + text = mNobleAttachment.msg; + } else if (attachment instanceof AssistantAttachment) { + awardAttachment = (AssistantAttachment) attachment; + text = awardAttachment.msg; + } else if (attachment instanceof CarveUpGoldThirdLevelAttachment) { + //瓜分钻石 三级 + CarveUpGoldThirdLevelAttachment cuAttachment = (CarveUpGoldThirdLevelAttachment) attachment; + int appColor = context.getResources().getColor(R.color.appColor); + SpannableBuilder builder = new SpannableBuilder() + .append(ResUtil.getString(R.string.im_chat_msgviewholdertext_01)) + .append(cuAttachment.getNick() + " ", new ForegroundColorSpan(appColor)) + .append(ResUtil.getString(R.string.im_chat_msgviewholdertext_02)) + .append(cuAttachment.getGoldNum() + ResUtil.getString(R.string.avroom_widget_messageview_027), new ForegroundColorSpan(appColor)) + .append("!"); + text = builder.build(); + } else if (attachment instanceof VoiceBottleShakeHeartAttachment) { + VoiceBottleShakeHeartAttachment shakeHeartAttachment = (VoiceBottleShakeHeartAttachment) attachment; + VoiceBottleSayHiInfo sayHiInfo = shakeHeartAttachment.getSayHiInfo(); + if (sayHiInfo != null) { + text = sayHiInfo.getMessage(); + } else { + text = context.getString(R.string.voice_im_msg_text); + } + + String heartHint; + if (message.getFromAccount().equals(String.valueOf(AuthModel.get().getCurrentUid()))) { + heartHint = ResUtil.getString(R.string.im_chat_msgviewholdertext_04); + } else { + heartHint = ResUtil.getString(R.string.im_chat_msgviewholdertext_05); + } + Map localExtension = message.getLocalExtension(); + if (localExtension != null && localExtension.containsKey(VoiceBottleShakeHeartAttachment.KEY_VOICE_BOTTLE_NEED_SHAKE_HEART)) { + boolean isNeedShakeHeart = (boolean) localExtension.get(VoiceBottleShakeHeartAttachment.KEY_VOICE_BOTTLE_NEED_SHAKE_HEART); + if (isNeedShakeHeart) { + EventBus.getDefault().post(new VoiceShakeHeartEvent(heartHint));// 爱心动画 + } + } else { + EventBus.getDefault().post(new VoiceShakeHeartEvent(heartHint));// 爱心动画 + } + + if (localExtension == null) { + localExtension = new HashMap<>(); + } + localExtension.put(VoiceBottleShakeHeartAttachment.KEY_VOICE_BOTTLE_NEED_SHAKE_HEART, false); + message.setLocalExtension(localExtension); + IMNetEaseManager.get().updateMessageToLocal(message); + }else if(attachment instanceof CpInviteAttachment){ + cpInviteAttachment = (CpInviteAttachment)attachment; + text = cpInviteAttachment.msg; + } + mTvMsg.setText(text); + } + + @Override + protected void onItemClick() { + if (mNobleAttachment != null) { + switch (mNobleAttachment.mSecond) { + case CustomAttachment.CUSTOM_MSG_HEADER_TYPE_GOOD_NUMBER_INACTIVE: + CommonWebViewActivity.start(mTvMsg.getContext(), IM_SERVER_URL + "modules/nobles/numApply.html"); + break; + case CustomAttachment.CUSTOM_MSG_HEADER_TYPE_NOBLE_END: + CommonWebViewActivity.start(mTvMsg.getContext(), IM_SERVER_URL + "modules/nobles/order.html"); + break; + case CustomAttachment.CUSTOM_MESS_SUB_HADEXPIRE: + CommonWebViewActivity.start(mTvMsg.getContext(), UriProvider.getNobleIntro()); + break; + default: + } + + } else if (mCarAttachment != null) { + if (mCarAttachment.mSecond == CUSTOM_MESS_SUB_CAR_EXPIRE) { + DressUpTabActivity.Companion.start(context,true); + } + } else if (awardAttachment != null) { + RouterHandler.handle(context, awardAttachment.routerType, awardAttachment.routerValue); + }else if(cpInviteAttachment!=null){ + RouterHandler.handle(context, cpInviteAttachment.routerType, cpInviteAttachment.routerValue); + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/im/chat/SysMsgV2ViewHolder.java b/app/src/main/java/com/chwl/app/ui/im/chat/SysMsgV2ViewHolder.java new file mode 100644 index 0000000..74ae737 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/chat/SysMsgV2ViewHolder.java @@ -0,0 +1,300 @@ +package com.chwl.app.ui.im.chat; + +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_HEADER_COMMON_SYSTEM_MSG_V2; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_TYPE_COMMON_SYSTEM_MSG_V2_APPROVAL; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_TYPE_COMMON_SYSTEM_MSG_V2_TEXT; + +import android.graphics.Color; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.TextPaint; +import android.text.TextUtils; +import android.text.style.AbsoluteSizeSpan; +import android.text.style.ForegroundColorSpan; +import android.text.style.MetricAffectingSpan; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.core.content.ContextCompat; + +import com.alibaba.fastjson2.JSON; +import com.netease.nim.uikit.business.session.viewholder.MsgViewHolderBase; +import com.netease.nim.uikit.common.ui.recyclerview.adapter.BaseMultiItemFetchLoadAdapter; +import com.netease.nimlib.sdk.msg.model.IMMessage; +import com.chwl.app.R; +import com.chwl.app.sys.ErbanSysMsgViewModel; +import com.chwl.app.ui.im.RouterHandler; +import com.chwl.core.im.custom.bean.SysMsgV2Attachment; +import com.chwl.core.manager.IMNetEaseManager; +import com.chwl.core.msg.sys.bean.ApproveMsgInfo; +import com.chwl.core.msg.sysv2.bean.ErbanSysMsgV2Component; +import com.chwl.core.msg.sysv2.bean.ErbanSysMsgV2Info; +import com.chwl.core.msg.sysv2.ErbanSysMsgV2Layout; +import com.chwl.core.utils.net.RxHelper; +import com.chwl.library.utils.SingleToastUtil; +import com.chwl.library.utils.SizeUtils; + +import java.util.List; +import java.util.Objects; + +/** + * Created by lvzebiao on 2020/3/28. + */ + +public class SysMsgV2ViewHolder extends MsgViewHolderBase implements View.OnClickListener { + + private View container; + private TextView title; + private TextView timestamp; + private TextView content; + private TextView approvalState; + private TextView tvRejoinMW; + private FrameLayout flRejoin; + private RelativeLayout resultLayout; + private RelativeLayout operationLayout; + private ErbanSysMsgV2Info erbanSysMsgV2Info; + private ErbanSysMsgViewModel viewModel; + + public SysMsgV2ViewHolder(BaseMultiItemFetchLoadAdapter adapter) { + super(adapter); + } + + @Override + protected int getContentResId() { + return R.layout.layout_sys_msg_view_holder; + } + + @Override + protected void inflateContentView() { + container = findViewById(R.id.ll_container); + approvalState = findViewById(R.id.tv_result); + resultLayout = findViewById(R.id.rl_result_layout); + operationLayout = findViewById(R.id.rl_operators); + tvRejoinMW = findViewById(R.id.tv_rejoin_mw); + flRejoin = findViewById(R.id.fl_rejoin); + title = findViewById(R.id.tv_title); + timestamp = findViewById(R.id.tv_timestamp); + content = findViewById(R.id.tv_content); + viewModel = new ErbanSysMsgViewModel(); + container.setOnClickListener(this); + tvRejoinMW.setOnClickListener(this); + findViewById(R.id.btn_reject).setOnClickListener(this); + findViewById(R.id.btn_agree).setOnClickListener(this); + } + + @Override + protected void bindContentView() { + IMMessage sysMsgInfoMessage = IMNetEaseManager.get().queryMessageByUuid(message.getUuid()); + SysMsgV2Attachment sysMsgV2Attachment; + if (sysMsgInfoMessage == null) { + sysMsgV2Attachment = (SysMsgV2Attachment) message.getAttachment(); + IMNetEaseManager.get().saveMessageToLocal(message); + erbanSysMsgV2Info = sysMsgV2Attachment.getErbanSysMsgV2Info(); + if (erbanSysMsgV2Info == null) { + return; + } + message.setLocalExtension(ErbanSysMsgV2Info.convertToMap(erbanSysMsgV2Info)); + IMNetEaseManager.get().updateErbanSysMsgV2InfoMessage(message.getUuid(), erbanSysMsgV2Info); + } else { + sysMsgV2Attachment = (SysMsgV2Attachment) sysMsgInfoMessage.getAttachment(); + if (sysMsgInfoMessage.getLocalExtension() == null) { + erbanSysMsgV2Info = sysMsgV2Attachment.getErbanSysMsgV2Info(); + } else { + erbanSysMsgV2Info = ErbanSysMsgV2Info.convertMapToObject(sysMsgInfoMessage.getLocalExtension()); + } + if (erbanSysMsgV2Info == null) { + return; + } + sysMsgInfoMessage.setLocalExtension(ErbanSysMsgV2Info.convertToMap(erbanSysMsgV2Info)); + IMNetEaseManager.get().updateErbanSysMsgV2InfoMessage(sysMsgInfoMessage.getUuid(), erbanSysMsgV2Info); + } + + String layout = erbanSysMsgV2Info.getLayout(); + ErbanSysMsgV2Layout ErbanSysMsgV2Layout; + try { + ErbanSysMsgV2Layout = JSON.parseObject(layout, ErbanSysMsgV2Layout.class); + + } catch (Exception ex) { // json解析出错 + ex.printStackTrace(); + return; + } + + // title + setupView(title, ErbanSysMsgV2Layout.getTitle()); + // timestamp + setupView(timestamp, ErbanSysMsgV2Layout.getTime()); + // content + List erbanSysMsgV2LayoutContent = ErbanSysMsgV2Layout.getContents(); + if (erbanSysMsgV2LayoutContent != null) { + SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(); + for (ErbanSysMsgV2Component ErbanSysMsgV2Component : erbanSysMsgV2LayoutContent) { + int start = spannableStringBuilder.length(); + String msgBody = ErbanSysMsgV2Component.getContent(); + if (Objects.equals(msgBody, "/r/n")) { + msgBody = "\r\n"; + spannableStringBuilder.append(msgBody); + continue; + } + spannableStringBuilder.append(msgBody); + if (ErbanSysMsgV2Component.getFontColor() != null) { + spannableStringBuilder.setSpan(new ForegroundColorSpan(Color.parseColor(ErbanSysMsgV2Component.getFontColor())), + start, spannableStringBuilder.length(), + Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + } + if (ErbanSysMsgV2Component.getFontSize() > 0) { + spannableStringBuilder.setSpan(new AbsoluteSizeSpan(SizeUtils.sp2px(content.getContext(), ErbanSysMsgV2Component.getFontSize() + 0.5F)), + start, spannableStringBuilder.length(), + Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + } + spannableStringBuilder.setSpan( + new MetricAffectingSpan() { + @Override + public void updateMeasureState(TextPaint p) { + + } + + @Override + public void updateDrawState(TextPaint tp) { + tp.setFakeBoldText(ErbanSysMsgV2Component.isFontBold()); + } + }, + start, spannableStringBuilder.length(), + Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + } + content.setText(spannableStringBuilder); + } + + operationLayout.setVisibility(View.GONE); + resultLayout.setVisibility(View.GONE); + flRejoin.setVisibility(View.GONE); + + if (sysMsgV2Attachment.getFirst() == CUSTOM_MSG_HEADER_COMMON_SYSTEM_MSG_V2) { + switch (sysMsgV2Attachment.getSecond()) { + case CUSTOM_MSG_SUB_TYPE_COMMON_SYSTEM_MSG_V2_TEXT: + break; + + case CUSTOM_MSG_SUB_TYPE_COMMON_SYSTEM_MSG_V2_APPROVAL: + operationLayout.setVisibility(View.VISIBLE); + break; + } + + } + + // bottom layout + switch (erbanSysMsgV2Info.getState()) { + case ErbanSysMsgV2Info.STATE_UNTREATED: + break; + + case ErbanSysMsgV2Info.STATE_AGREE: + displayAgreedResult(); + break; + + case ErbanSysMsgV2Info.STATE_REFUSED: + displayRejectedResult(); + break; + + case ErbanSysMsgV2Info.STATE_OUT_DATE: + displayOutDateResult(); + break; + } + } + + public void setupView(TextView view, ErbanSysMsgV2Component ErbanSysMsgV2Component) { + if (ErbanSysMsgV2Component != null) { + setupComponent(view, ErbanSysMsgV2Component.getContent(), ErbanSysMsgV2Component.getFontColor(), ErbanSysMsgV2Component.getFontSize(), + ErbanSysMsgV2Component.getRouterType(), ErbanSysMsgV2Component.getRouterValue()); + } + } + + public void setupComponent(TextView view, String text, String textColor, float fontSize, int routerType, String routerValue) { + view.setText(text); + view.setTextColor(Color.parseColor(textColor)); + view.setTextSize(fontSize); + if (routerType > 0) { + view.setOnClickListener(v -> RouterHandler.handle(context, routerType, routerValue)); + } + } + + @Override + public void onClick(View v) { + if (erbanSysMsgV2Info == null) { + return; + } + switch (v.getId()) { + case R.id.ll_container: + if (erbanSysMsgV2Info.getRouterType() != 0) + RouterHandler.handle(context, erbanSysMsgV2Info.getRouterType(), erbanSysMsgV2Info.getRouterValue()); + break; + + case R.id.btn_reject: + viewModel.requestUrl(erbanSysMsgV2Info.getUrl(), 0, erbanSysMsgV2Info.getParams()) + .subscribe((approveMsgInfo, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + String tips = throwable.getMessage(); + if (!TextUtils.isEmpty(tips) && !RxHelper.ERROR_TIPS.equals(tips)) + SingleToastUtil.showToast(context, throwable.getMessage(), Toast.LENGTH_SHORT); + } else { + if (approveMsgInfo.getStatus() == ErbanSysMsgV2Info.STATE_OUT_DATE) { + displayOutDateResult(); + }else if (approveMsgInfo.getStatus() == ErbanSysMsgV2Info.STATE_REFUSED){ + displayRejectedResult(); + } + updateMessageToLocal(approveMsgInfo); + } + }); + break; + + case R.id.btn_agree: + viewModel.requestUrl(erbanSysMsgV2Info.getUrl(), 1, erbanSysMsgV2Info.getParams()) + .subscribe((approveMsgInfo, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + String tips = throwable.getMessage(); + if (!TextUtils.isEmpty(tips) && !RxHelper.ERROR_TIPS.equals(tips)) + SingleToastUtil.showToast(context, throwable.getMessage(), Toast.LENGTH_SHORT); + } else { + if (approveMsgInfo.getStatus() == ErbanSysMsgV2Info.STATE_OUT_DATE) { + displayOutDateResult(); + }else if (approveMsgInfo.getStatus() == ErbanSysMsgV2Info.STATE_AGREE){ + displayAgreedResult(); + } + updateMessageToLocal(approveMsgInfo); + } + }); + break; + + } + } + + private void updateMessageToLocal(ApproveMsgInfo approveMsgInfo) { + erbanSysMsgV2Info.setState(approveMsgInfo.getStatus()); + IMNetEaseManager.get().updateErbanSysMsgV2InfoMessage(message.getUuid(), erbanSysMsgV2Info); + } + + private void displayAgreedResult() { + resultLayout.setVisibility(View.VISIBLE); + operationLayout.setVisibility(View.GONE); + approvalState.setCompoundDrawablesWithIntrinsicBounds(R.drawable.icon_state_agreed, 0, 0, 0); + approvalState.setText(R.string.text_erban_sys_msg_state_agreed); + approvalState.setTextColor(ContextCompat.getColor(context, R.color.green_color_light)); + } + + private void displayRejectedResult() { + resultLayout.setVisibility(View.VISIBLE); + operationLayout.setVisibility(View.GONE); + approvalState.setCompoundDrawablesWithIntrinsicBounds(R.drawable.icon_state_rejected, 0, 0, 0); + approvalState.setText(R.string.text_erban_sys_msg_state_rejected); + approvalState.setTextColor(ContextCompat.getColor(context, R.color.color_ff6565)); + } + + private void displayOutDateResult() { + resultLayout.setVisibility(View.VISIBLE); + operationLayout.setVisibility(View.GONE); + approvalState.setText(R.string.text_erban_sys_msg_state_out_date); + approvalState.setTextColor(ContextCompat.getColor(context, R.color.color_ff6565)); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/im/chat/SysMsgViewHolder.java b/app/src/main/java/com/chwl/app/ui/im/chat/SysMsgViewHolder.java new file mode 100644 index 0000000..41d3522 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/chat/SysMsgViewHolder.java @@ -0,0 +1,310 @@ +package com.chwl.app.ui.im.chat; + +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_HEADER_COMMON_SYSTEM_MSG; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_HEAD_SHIFT_OUT; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SHIFT_OUT; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_TYPE_COMMON_SYSTEM_MSG_APPROVAL; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_TYPE_COMMON_SYSTEM_MSG_TEXT; + +import android.graphics.Color; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.TextPaint; +import android.text.TextUtils; +import android.text.style.AbsoluteSizeSpan; +import android.text.style.ForegroundColorSpan; +import android.text.style.MetricAffectingSpan; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.core.content.ContextCompat; + +import com.alibaba.fastjson2.JSON; +import com.netease.nim.uikit.business.session.viewholder.MsgViewHolderBase; +import com.netease.nim.uikit.common.ui.recyclerview.adapter.BaseMultiItemFetchLoadAdapter; +import com.netease.nimlib.sdk.msg.model.IMMessage; +import com.chwl.app.R; +import com.chwl.app.sys.ErbanSysMsgViewModel; +import com.chwl.app.ui.im.RouterHandler; +import com.chwl.core.im.custom.bean.SysMsgAttachment; +import com.chwl.core.manager.IMNetEaseManager; +import com.chwl.core.msg.sys.bean.ApproveMsgInfo; +import com.chwl.core.msg.sys.bean.ErbanSysMsgComponent; +import com.chwl.core.msg.sys.bean.ErbanSysMsgInfo; +import com.chwl.core.msg.sys.ErbanSysMsgLayout; +import com.chwl.core.utils.net.RxHelper; +import com.chwl.library.utils.SingleToastUtil; +import com.chwl.library.utils.SizeUtils; + +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * Created by MadisonRong on 17/06/2018. + */ + +public class SysMsgViewHolder extends MsgViewHolderBase implements View.OnClickListener { + + private View container; + private TextView title; + private TextView timestamp; + private TextView content; + private TextView approvalState; + private TextView tvRejoinMW; + private FrameLayout flRejoin; + private RelativeLayout resultLayout; + private RelativeLayout operationLayout; + private ErbanSysMsgInfo erbanSysMsgInfo; + private ErbanSysMsgViewModel viewModel; + + public SysMsgViewHolder(BaseMultiItemFetchLoadAdapter adapter) { + super(adapter); + } + + @Override + protected int getContentResId() { + return R.layout.layout_sys_msg_view_holder; + } + + @Override + protected void inflateContentView() { + container = findViewById(R.id.ll_container); + approvalState = findViewById(R.id.tv_result); + resultLayout = findViewById(R.id.rl_result_layout); + operationLayout = findViewById(R.id.rl_operators); + tvRejoinMW = findViewById(R.id.tv_rejoin_mw); + flRejoin = findViewById(R.id.fl_rejoin); + title = findViewById(R.id.tv_title); + timestamp = findViewById(R.id.tv_timestamp); + content = findViewById(R.id.tv_content); + viewModel = new ErbanSysMsgViewModel(); + container.setOnClickListener(this); + tvRejoinMW.setOnClickListener(this); + findViewById(R.id.btn_reject).setOnClickListener(this); + findViewById(R.id.btn_agree).setOnClickListener(this); + } + + @Override + protected void bindContentView() { + IMMessage sysMsgInfoMessage = IMNetEaseManager.get().queryMessageByUuid(message.getUuid()); + SysMsgAttachment sysMsgAttachment; + if (sysMsgInfoMessage == null) { + sysMsgAttachment = (SysMsgAttachment) message.getAttachment(); + IMNetEaseManager.get().saveMessageToLocal(message); + erbanSysMsgInfo = sysMsgAttachment.getErbanSysMsgInfo(); + message.setLocalExtension(ErbanSysMsgInfo.convertToMap(erbanSysMsgInfo)); + IMNetEaseManager.get().updateErbanSysMsgInfoMessage(message.getUuid(), erbanSysMsgInfo); + } else { + sysMsgAttachment = (SysMsgAttachment) sysMsgInfoMessage.getAttachment(); + if (sysMsgInfoMessage.getLocalExtension() == null) { + erbanSysMsgInfo = sysMsgAttachment.getErbanSysMsgInfo(); + } else { + erbanSysMsgInfo = ErbanSysMsgInfo.convertMapToObject(sysMsgInfoMessage.getLocalExtension()); + } + sysMsgInfoMessage.setLocalExtension(ErbanSysMsgInfo.convertToMap(erbanSysMsgInfo)); + IMNetEaseManager.get().updateErbanSysMsgInfoMessage(sysMsgInfoMessage.getUuid(), erbanSysMsgInfo); + } + + String layout = erbanSysMsgInfo.getLayout(); + ErbanSysMsgLayout erbanSysMsgLayout; + try { + erbanSysMsgLayout = JSON.parseObject(layout, ErbanSysMsgLayout.class); + + } catch (Exception ex) { // json解析出错 + ex.printStackTrace(); + return; + } + + // title + setupView(title, erbanSysMsgLayout.getTitle()); + // timestamp + setupView(timestamp, erbanSysMsgLayout.getTime()); + // content + List erbanSysMsgLayoutContent = erbanSysMsgLayout.getContents(); + if (erbanSysMsgLayoutContent != null) { + SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(); + for (ErbanSysMsgComponent erbanSysMsgComponent : erbanSysMsgLayoutContent) { + int start = spannableStringBuilder.length(); + String msgBody = erbanSysMsgComponent.getContent(); + if (Objects.equals(msgBody, "/r/n")) { + msgBody = "\r\n"; + spannableStringBuilder.append(msgBody); + continue; + } + spannableStringBuilder.append(msgBody); + if (erbanSysMsgComponent.getFontColor() != null) { + spannableStringBuilder.setSpan(new ForegroundColorSpan(Color.parseColor(erbanSysMsgComponent.getFontColor())), + start, spannableStringBuilder.length(), + Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + } + if (erbanSysMsgComponent.getFontSize() > 0) { + spannableStringBuilder.setSpan(new AbsoluteSizeSpan(SizeUtils.sp2px(content.getContext(), erbanSysMsgComponent.getFontSize() + 0.5F)), + start, spannableStringBuilder.length(), + Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + } + spannableStringBuilder.setSpan( + new MetricAffectingSpan() { + @Override + public void updateMeasureState(TextPaint p) { + + } + + @Override + public void updateDrawState(TextPaint tp) { + tp.setFakeBoldText(erbanSysMsgComponent.isFontBold()); + } + }, + start, spannableStringBuilder.length(), + Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + } + content.setText(spannableStringBuilder); + } + + operationLayout.setVisibility(View.GONE); + resultLayout.setVisibility(View.GONE); + flRejoin.setVisibility(View.GONE); + + if (sysMsgAttachment.getFirst() == CUSTOM_MSG_HEADER_COMMON_SYSTEM_MSG) { + switch (sysMsgAttachment.getSecond()) { + case CUSTOM_MSG_SUB_TYPE_COMMON_SYSTEM_MSG_TEXT: + break; + + case CUSTOM_MSG_SUB_TYPE_COMMON_SYSTEM_MSG_APPROVAL: + operationLayout.setVisibility(View.VISIBLE); + break; + } + + } else if (sysMsgAttachment.getFirst() == CUSTOM_MSG_HEAD_SHIFT_OUT) { + switch (sysMsgAttachment.getSecond()) { + case CUSTOM_MSG_SHIFT_OUT: + flRejoin.setVisibility(View.VISIBLE); + break; + } + } + + // bottom layout + switch (erbanSysMsgInfo.getState()) { + case ErbanSysMsgInfo.STATE_UNTREATED: + break; + + case ErbanSysMsgInfo.STATE_AGREE: + displayAgreedResult(); + break; + + case ErbanSysMsgInfo.STATE_REFUSED: + displayRejectedResult(); + break; + + case ErbanSysMsgInfo.STATE_OUT_DATE: + displayOutDateResult(); + break; + } + } + + public void setupView(TextView view, ErbanSysMsgComponent erbanSysMsgComponent) { + if (erbanSysMsgComponent != null) { + setupComponent(view, erbanSysMsgComponent.getContent(), erbanSysMsgComponent.getFontColor(), erbanSysMsgComponent.getFontSize(), + erbanSysMsgComponent.getRouterType(), erbanSysMsgComponent.getRouterValue()); + } + } + + public void setupComponent(TextView view, String text, String textColor, float fontSize, int routerType, int routerValue) { + view.setText(text); + view.setTextColor(Color.parseColor(textColor)); + view.setTextSize(fontSize); + if (routerType > 0) { + view.setOnClickListener(v -> RouterHandler.handle(context, routerType, String.valueOf(routerValue))); + } + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.ll_container: + if (erbanSysMsgInfo.getRouterType() != 0) + RouterHandler.handle(context, erbanSysMsgInfo.getRouterType(), String.valueOf(erbanSysMsgInfo.getRouterValue())); + break; + + case R.id.btn_reject: + viewModel.requestUrl(erbanSysMsgInfo.getUrl(), 0, erbanSysMsgInfo.getParams()) + .subscribe((approveMsgInfo, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + String tips = throwable.getMessage(); + if (!TextUtils.isEmpty(tips) && !RxHelper.ERROR_TIPS.equals(tips)) + SingleToastUtil.showToast(context, throwable.getMessage(), Toast.LENGTH_SHORT); + } else { + if (approveMsgInfo.getStatus() == ErbanSysMsgInfo.STATE_OUT_DATE) { + displayOutDateResult(); + }else if (approveMsgInfo.getStatus() == ErbanSysMsgInfo.STATE_REFUSED){ + displayRejectedResult(); + } + updateMessageToLocal(approveMsgInfo); + } + }); + break; + + case R.id.btn_agree: + viewModel.requestUrl(erbanSysMsgInfo.getUrl(), 1, erbanSysMsgInfo.getParams()) + .subscribe((approveMsgInfo, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + String tips = throwable.getMessage(); + if (!TextUtils.isEmpty(tips) && !RxHelper.ERROR_TIPS.equals(tips)) + SingleToastUtil.showToast(context, throwable.getMessage(), Toast.LENGTH_SHORT); + } else { + if (approveMsgInfo.getStatus() == ErbanSysMsgInfo.STATE_OUT_DATE) { + displayOutDateResult(); + }else if (approveMsgInfo.getStatus() == ErbanSysMsgInfo.STATE_AGREE){ + displayAgreedResult(); + } + updateMessageToLocal(approveMsgInfo); + } + }); + break; + + case R.id.tv_rejoin_mw: + if (erbanSysMsgInfo != null) { + Map map = erbanSysMsgInfo.getParams(); + if (map != null) { + String worldId = map.get("worldId"); + if (!TextUtils.isEmpty(worldId)) { + } + } + } + break; + } + } + + private void updateMessageToLocal(ApproveMsgInfo approveMsgInfo) { + erbanSysMsgInfo.setState(approveMsgInfo.getStatus()); + IMNetEaseManager.get().updateErbanSysMsgInfoMessage(message.getUuid(), erbanSysMsgInfo); + } + + private void displayAgreedResult() { + resultLayout.setVisibility(View.VISIBLE); + operationLayout.setVisibility(View.GONE); + approvalState.setCompoundDrawablesWithIntrinsicBounds(R.drawable.icon_state_agreed, 0, 0, 0); + approvalState.setText(R.string.text_erban_sys_msg_state_agreed); + approvalState.setTextColor(ContextCompat.getColor(context, R.color.green_color_light)); + } + + private void displayRejectedResult() { + resultLayout.setVisibility(View.VISIBLE); + operationLayout.setVisibility(View.GONE); + approvalState.setCompoundDrawablesWithIntrinsicBounds(R.drawable.icon_state_rejected, 0, 0, 0); + approvalState.setText(R.string.text_erban_sys_msg_state_rejected); + approvalState.setTextColor(ContextCompat.getColor(context, R.color.color_ff6565)); + } + + private void displayOutDateResult() { + resultLayout.setVisibility(View.VISIBLE); + operationLayout.setVisibility(View.GONE); + approvalState.setText(R.string.text_erban_sys_msg_state_out_date); + approvalState.setTextColor(ContextCompat.getColor(context, R.color.color_ff6565)); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/im/fragment/MessageFragment.java b/app/src/main/java/com/chwl/app/ui/im/fragment/MessageFragment.java new file mode 100644 index 0000000..9a7bdb8 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/fragment/MessageFragment.java @@ -0,0 +1,745 @@ +package com.chwl.app.ui.im.fragment; + +import android.Manifest; +import android.annotation.SuppressLint; +import android.content.Intent; +import android.graphics.Color; +import android.media.AudioManager; +import android.net.Uri; +import android.os.Bundle; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.TextUtils; +import android.text.method.LinkMovementMethod; +import android.text.style.ForegroundColorSpan; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; + +import com.chwl.app.R; +import com.chwl.app.common.widget.OriginalDrawStatusClickSpan; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.app.ui.im.GreetPresenter; +import com.chwl.app.ui.im.MessageListPanelEx; +import com.chwl.app.ui.im.chat.MVHChatterBoxStart; +import com.chwl.app.ui.im.model.IMCustomModel; +import com.chwl.app.ui.webview.CommonWebViewActivity; +import com.chwl.app.utils.PushMessageHandler; +import com.chwl.app.vip.VipCenterActivity; +import com.chwl.core.UriProvider; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.im.chatterbox.ChatterBoxHelper; +import com.chwl.core.im.chatterbox.HideInputEvent; +import com.chwl.core.im.custom.bean.CustomAttachment; +import com.chwl.core.im.custom.bean.ImTipAttachment; +import com.chwl.core.room.event.MessageSizeEvent; +import com.chwl.library.common.util.OtherExtKt; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; +import com.chwl.library.utils.config.BasicConfig; +import com.netease.nim.uikit.api.UIKitOptions; +import com.netease.nim.uikit.api.model.main.CustomPushContentProvider; +import com.netease.nim.uikit.api.model.session.SessionCustomization; +import com.netease.nim.uikit.business.ait.AitManager; +import com.netease.nim.uikit.business.session.actions.BaseAction; +import com.netease.nim.uikit.business.session.constant.Extras; +import com.netease.nim.uikit.business.session.module.Container; +import com.netease.nim.uikit.business.session.module.ModuleProxy; +import com.netease.nim.uikit.business.session.module.input.InputPanel; +import com.netease.nim.uikit.business.session.module.input.NimImageActionEvent; +import com.netease.nim.uikit.common.fragment.TFragment; +import com.netease.nim.uikit.impl.NimUIKitImpl; +import com.netease.nimlib.sdk.NIMClient; +import com.netease.nimlib.sdk.Observer; +import com.netease.nimlib.sdk.RequestCallback; +import com.netease.nimlib.sdk.ResponseCode; +import com.netease.nimlib.sdk.msg.MessageBuilder; +import com.netease.nimlib.sdk.msg.MsgService; +import com.netease.nimlib.sdk.msg.MsgServiceObserve; +import com.netease.nimlib.sdk.msg.constant.MsgStatusEnum; +import com.netease.nimlib.sdk.msg.constant.MsgTypeEnum; +import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum; +import com.netease.nimlib.sdk.msg.model.CustomMessageConfig; +import com.netease.nimlib.sdk.msg.model.IMMessage; +import com.netease.nimlib.sdk.msg.model.MemberPushOption; +import com.netease.nimlib.sdk.msg.model.MessageReceipt; +import com.netease.nimlib.sdk.robot.model.NimRobotInfo; +import com.netease.nimlib.sdk.robot.model.RobotAttachment; +import com.netease.nimlib.sdk.robot.model.RobotMsgType; +import com.tbruyelle.rxpermissions2.RxPermissions; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import io.reactivex.Observable; +import io.reactivex.disposables.Disposable; +import io.reactivex.functions.Consumer; + + +/** + * 聊天界面基类 + *

+ * Created by huangjun on 2015/2/1. + */ +public class MessageFragment extends TFragment implements ModuleProxy, MessageListPanelEx.OnMessageFilterListener { + + public static final String IN_ROOM = "inRoom"; + protected static final String TAG = "MessageActivity"; + // 聊天对象 + protected String sessionId; // p2p对方Account或者群id + protected SessionTypeEnum sessionType; + // modules + protected InputPanel inputPanel; + protected MessageListPanelEx messageListPanel; + protected AitManager aitManager; + protected String recordId = ""; + + /** + * 消息接收观察者 + */ + Observer> incomingMessageObserver = new Observer>() { + @Override + public void onEvent(List messages) { + if (messages == null || messages.isEmpty()) { + return; + } + + messageListPanel.onIncomingMessage(filterLoadedMessage(messages)); + sendMsgReceipt(); // 发送已读回执 + } + }; + private View rootView; + private TextView tvChatLimit; + private SessionCustomization customization; + private Disposable greetDisposable; + private RxPermissions rxPermissions; + private boolean isChat; + private String hintText; + private Observer> messageReceiptObserver = new Observer>() { + @Override + public void onEvent(List messageReceipts) { + receiveReceipt(); + } + }; + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + rxPermissions = new RxPermissions(this); + parseIntent(); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + rootView = inflater.inflate(R.layout.nim_msg_fragment, container, false); + EventBus.getDefault().register(this); + tvChatLimit = rootView.findViewById(R.id.tv_chat_limit); + return rootView; + } + + /** + * ***************************** life cycle ******************************* + */ + + @Override + public void onPause() { + super.onPause(); + + NIMClient.getService(MsgService.class).setChattingAccount(MsgService.MSG_CHATTING_ACCOUNT_NONE, + SessionTypeEnum.None); + inputPanel.onPause(); + messageListPanel.onPause(); + } + + @Override + public void onResume() { + super.onResume(); + messageListPanel.onResume(); + NIMClient.getService(MsgService.class).setChattingAccount(sessionId, sessionType); + getActivity().setVolumeControlStream(AudioManager.STREAM_VOICE_CALL); // 默认使用听筒播放 + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + OtherExtKt.clearSpans(tvChatLimit); + EventBus.getDefault().unregister(this); + } + + @Override + public void onDestroy() { + super.onDestroy(); + messageListPanel.onDestroy(); + registerObservers(false); + if (greetDisposable != null) { + greetDisposable.dispose(); + } + if (inputPanel != null) { + inputPanel.onDestroy(); + } + if (aitManager != null) { + aitManager.reset(); + } + } + + /** + * 发送提示信息 + * + * @param msg + */ + public void sendTipMessage(String msg, int second) { + ImTipAttachment attachment = new ImTipAttachment(CustomAttachment.CUSTOM_MSG_IM_TIP, second); + attachment.setMsg(msg); + IMMessage message = MessageBuilder.createCustomMessage(sessionId, SessionTypeEnum.P2P, attachment); + sendMessage(message); + } + + public boolean onBackPressed() { + if (inputPanel.collapse(true)) { + return true; + } + + if (messageListPanel.onBackPressed()) { + return true; + } + return false; + } + + public void refreshMessageList() { + messageListPanel.refreshMessageList(); + } + + private void parseIntent() { + recordId = getArguments() != null ? getArguments().getString(Extras.EXTRA_RECORDID) : ""; + sessionId = getArguments().getString(Extras.EXTRA_ACCOUNT); + ChatterBoxHelper.reset(); + ChatterBoxHelper.sessionId = sessionId; + sessionType = (SessionTypeEnum) getArguments().getSerializable(Extras.EXTRA_TYPE); + IMMessage anchor = (IMMessage) getArguments().getSerializable(Extras.EXTRA_ANCHOR); + + customization = (SessionCustomization) getArguments().getSerializable(Extras.EXTRA_CUSTOMIZATION); + Container container = new Container(getActivity(), sessionId, sessionType, this); + + if (messageListPanel == null) { + if (!TextUtils.isEmpty(recordId)) { + messageListPanel = new MessageListPanelEx(container, rootView, anchor, false, false, recordId); + } else { + messageListPanel = new MessageListPanelEx(container, rootView, anchor, false, false); + } + } else { + messageListPanel.reload(container, anchor); + } + + if (inputPanel == null) { + inputPanel = new InputPanel(container, rootView, getActionList()); + inputPanel.setCustomization(customization); + inputPanel.setLimitLevel(isChat, hintText); + } else { + inputPanel.reload(container, customization); + } + + initAitManager(); + + inputPanel.switchRobotMode(NimUIKitImpl.getRobotInfoProvider().getRobotByAccount(sessionId) != null); + + registerObservers(true); + + if (customization != null) { + messageListPanel.setChattingBackground(customization.backgroundUri, customization.backgroundColor); + } + + // 首页进来的直接打开话匣子游戏 + boolean startWithChatterBox = getArguments().getBoolean(Extras.EXTRA_CHATTER_BOX, false); + MVHChatterBoxStart.isFromHome = startWithChatterBox; + if (startWithChatterBox) { + ChatterBoxHelper.sendInitTips(sessionId); + } + + boolean accost = getArguments().getBoolean(Extras.EXTRA_ACCOST, false); + if (accost) { + long toUid; + try { + toUid = Long.valueOf(sessionId); + + } catch (Exception ex) { + ex.printStackTrace(); + toUid = 0; + } + if (toUid > 0) { + GreetPresenter greetPresenter = new GreetPresenter(sessionId); + if (greetPresenter.isCanSendGreet()) { + greetDisposable = greetPresenter.greetMsgGetOne(AuthModel.get().getCurrentUid(), toUid) + .subscribe(new Consumer() { + @Override + public void accept(String s) throws Exception { + if (!TextUtils.isEmpty(s)) { + sendMessage(MessageBuilder.createTextMessage(container.account, + container.sessionType, s)); + } + } + }); + } + + } + } + + } + + private void initAitManager() { + UIKitOptions options = NimUIKitImpl.getOptions(); + if (options.aitEnable) { + aitManager = new AitManager(getContext(), options.aitTeamMember && sessionType == SessionTypeEnum.Team ? sessionId : null, options.aitIMRobot); + inputPanel.addAitTextWatcher(aitManager); + aitManager.setTextChangeListener(inputPanel); + } + } + + /** + * ************************* 消息收发 ********************************** + */ + // 是否允许发送消息 + protected boolean isAllowSendMessage(final IMMessage message) { + return true; + } + + /** + * ****************** 观察者 ********************** + */ + + private void registerObservers(boolean register) { + MsgServiceObserve service = NIMClient.getService(MsgServiceObserve.class); + service.observeReceiveMessage(incomingMessageObserver, register); + // 已读回执监听 + if (NimUIKitImpl.getOptions().shouldHandleReceipt) { + service.observeMessageReceipt(messageReceiptObserver, register); + } + + } + + /** + * ********************** implements ModuleProxy ********************* + */ + @Override + public boolean sendMessage(IMMessage imMessage) { + if (!isAllowSendMessage(imMessage)) { + return false; + } + inputPanel.setInputViewEnabled(false); + //xxx 消息防打扰, 发送消息前 请求接口 + IMCustomModel.get().getPrivateChatLimitV2(imMessage.getSessionId()) + .doOnSuccess(s -> { + try { + if (!s.isChat()) { + //isChat = false , 彈窗阻止聊天 + DialogManager dialog = new DialogManager(requireActivity()); + if (s.getNextVipLevel() == -1 && s.getNextUserCountLimit() == -1) { + //最高等級 + dialog.showOkDialog(ResUtil.getString(R.string.chat_limit_tip3)); + } else if (s.getNextVipLevel() != -1 && s.getNextUserCountLimit() == -1) { + //未達到最小等級 + dialog.showOkCancelDialog(ResUtil.getString(R.string.chat_limit_tip_title), + ResUtil.getString(R.string.chat_limit_tip1, "VIP" + s.getNextVipLevel()), ResUtil.getString(R.string.getsVip, s.getNextVipLevel()), ResUtil.getString(R.string.cancel), true, new DialogManager.OkCancelDialogListener() { + @Override + public void onOk() { + if (s.getNextVipLevel() > 0) { + VipCenterActivity.start(requireActivity(), s.getNextVipLevel()); + } + } + } + ); + } else { + //其他 + dialog.showOkCancelDialog(ResUtil.getString(R.string.chat_limit_tip_title), + ResUtil.getString(R.string.chat_limit_tip2, "VIP" + s.getNextVipLevel(), s.getNextUserCountLimit()), ResUtil.getString(R.string.getsVip, s.getNextVipLevel()), ResUtil.getString(R.string.cancel), true, new DialogManager.OkCancelDialogListener() { + @Override + public void onOk() { + if (s.getNextVipLevel() > 0) { + VipCenterActivity.start(requireActivity(), s.getNextVipLevel()); + } + } + } + ); + } + inputPanel.setInputViewEnabled(true); + return; + } + } catch (Exception e) { + inputPanel.setInputViewEnabled(true); + return; + } + + + appendTeamMemberPush(imMessage); + IMMessage message = changeToRobotMsg(imMessage); + Map payload = new HashMap<>(); + payload.put("skiptype", PushMessageHandler.PAYLOAD_SKIPTYPE_PRIVATE_MSG); + try { + JSONObject dataObj = new JSONObject(); + dataObj.putOpt("uid", message.getFromAccount()).putOpt("content", message.getContent()); + payload.put("data", dataObj); + } catch (JSONException e) { + e.printStackTrace(); + } + + payload.put("vivoField", vivoField()); + payload.put("hwField", hwField(message)); + message.setPushPayload(payload); + + final IMMessage msg = message; + appendPushConfig(message); + // send message to server and save to db + IMMessage finalMessage = message; + NIMClient.getService(MsgService.class).sendMessage(message, false).setCallback(new RequestCallback() { + @Override + public void onSuccess(Void param) { + + } + + @Override + public void onFailed(int code) { + sendFailWithBlackList(code, msg); + } + + @Override + public void onException(Throwable exception) { + + } + }); + + messageListPanel.onMsgSend(message); + + if (aitManager != null) { + aitManager.reset(); + } + inputPanel.setInputViewEnabled(true); + }) + .doOnError(throwable -> { + inputPanel.setInputViewEnabled(true); + SingleToastUtil.showToast(throwable.getMessage()); + }) + .subscribe(); + + + return true; + } + + /** + * vivo推送payload + * + * @return + */ + private Map vivoField() { + //vivo开启系统推送 + int classification = 1; + Map vivoField = new HashMap<>(); + vivoField.put("classification", classification); + return vivoField; + } + + /** + * 华为推送payload + * + * @return + */ + private JSONObject hwField(IMMessage message) { + Intent hwIntent = new Intent(Intent.ACTION_VIEW); + String intentStr = String.format( + "molistarpushscheme://com.huawei.codelabpush/deeplink?sessionID=%s&sessionType=%s", + sessionId, sessionType + ); + hwIntent.putExtra("skiptype", PushMessageHandler.PAYLOAD_SKIPTYPE_PRIVATE_MSG); + hwIntent.putExtra("uid", message.getFromAccount()); + hwIntent.setData(Uri.parse(intentStr)); + hwIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + String intentUri = hwIntent.toUri(Intent.URI_INTENT_SCHEME); +//点击事件的内容 + JSONObject clickAction = new JSONObject(); +//通知的内容 + JSONObject notification = new JSONObject(); + + try { + clickAction.putOpt("type", 1) + .putOpt("intent", intentUri); + notification.putOpt("click_action", clickAction); + } catch (JSONException e) { + e.printStackTrace(); + } + return notification; + } + + // 被对方拉入黑名单后,发消息失败的交互处理 + private void sendFailWithBlackList(int code, IMMessage msg) { + if (code == ResponseCode.RES_IN_BLACK_LIST) { + // 如果被对方拉入黑名单,发送的消息前不显示重发红点 + msg.setStatus(MsgStatusEnum.success); + NIMClient.getService(MsgService.class).updateIMMessageStatus(msg); + messageListPanel.refreshMessageList(); + // 同时,本地插入被对方拒收的tip消息 + IMMessage tip = MessageBuilder.createTipMessage(msg.getSessionId(), msg.getSessionType()); + tip.setContent(BasicConfig.INSTANCE.getAppContext().getString(R.string.black_list_send_tip)); + tip.setStatus(MsgStatusEnum.success); + CustomMessageConfig config = new CustomMessageConfig(); + config.enableUnreadCount = false; + tip.setConfig(config); + NIMClient.getService(MsgService.class).saveMessageToLocal(tip, true); + } + } + + private void appendTeamMemberPush(IMMessage message) { + if (aitManager == null) { + return; + } + if (sessionType == SessionTypeEnum.Team) { + List pushList = aitManager.getAitTeamMember(); + if (pushList == null || pushList.isEmpty()) { + return; + } + MemberPushOption memberPushOption = new MemberPushOption(); + memberPushOption.setForcePush(true); + memberPushOption.setForcePushContent(message.getContent()); + memberPushOption.setForcePushList(pushList); + message.setMemberPushOption(memberPushOption); + } + } + + private IMMessage changeToRobotMsg(IMMessage message) { + if (aitManager == null) { + return message; + } + if (message.getMsgType() == MsgTypeEnum.robot) { + return message; + } + if (isChatWithRobot()) { + if (message.getMsgType() == MsgTypeEnum.text && message.getContent() != null) { + String content = message.getContent().equals("") ? " " : message.getContent(); + message = MessageBuilder.createRobotMessage(message.getSessionId(), message.getSessionType(), message.getSessionId(), content, RobotMsgType.TEXT, content, null, null); + } + } else { + String robotAccount = aitManager.getAitRobot(); + if (TextUtils.isEmpty(robotAccount)) { + return message; + } + String text = message.getContent(); + String content = aitManager.removeRobotAitString(text, robotAccount); + content = content.equals("") ? " " : content; + message = MessageBuilder.createRobotMessage(message.getSessionId(), message.getSessionType(), robotAccount, text, RobotMsgType.TEXT, content, null, null); + + } + return message; + } + + private boolean isChatWithRobot() { + return NimUIKitImpl.getRobotInfoProvider().getRobotByAccount(sessionId) != null; + } + + private void appendPushConfig(IMMessage message) { + CustomPushContentProvider customConfig = NimUIKitImpl.getCustomPushContentProvider(); + if (customConfig != null) { + String content = customConfig.getPushContent(message); + Map payload = customConfig.getPushPayload(message); + if (!TextUtils.isEmpty(content)) { + message.setPushContent(content); + } + if (payload != null) { + message.setPushPayload(payload); + } + } + } + + @Override + public void onInputPanelExpand() { + messageListPanel.scrollToBottom(); + } + + @Override + public void shouldCollapseInputPanel() { + inputPanel.collapse(false); + } + + @Override + public boolean isLongClickEnabled() { + return !inputPanel.isRecording(); + } + + @Override + public void onItemFooterClick(IMMessage message) { + if (aitManager == null) { + return; + } + if (messageListPanel.isSessionMode()) { + RobotAttachment attachment = (RobotAttachment) message.getAttachment(); + NimRobotInfo robot = NimUIKitImpl.getRobotInfoProvider().getRobotByAccount(attachment.getFromRobotAccount()); + aitManager.insertAitRobot(robot.getAccount(), robot.getName(), inputPanel.getEditSelectionStart()); + } + } + + @Override + public List filterLoadedMessage(List messageList) { + return filterMessage(messageList); + } + + @SuppressLint("CheckResult") + @Override + public void onAudioClick(Runnable runnable) { + checkPermission(Manifest.permission.RECORD_AUDIO) + .subscribe(result -> { + if (result) { + runnable.run(); + } else { + SingleToastUtil.showToast(getString(R.string.ask_again)); + } + }); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (aitManager != null) { + aitManager.onActivityResult(requestCode, resultCode, data); + } + inputPanel.onActivityResult(requestCode, resultCode, data); + messageListPanel.onActivityResult(requestCode, resultCode, data); + } + + // 操作面板集合 + protected List getActionList() { + List actions = new ArrayList<>(); +// actions.add(new ImageAction()); +// actions.add(new VideoAction()); +// actions.add(new LocationAction()); + + if (customization != null && customization.actions != null) { + actions.addAll(customization.actions); + } + return actions; + } + + /** + * 发送已读回执 + */ + private void sendMsgReceipt() { + messageListPanel.sendReceipt(); + } + + /** + * 收到已读回执 + */ + public void receiveReceipt() { + messageListPanel.receiveReceipt(); + } + + /** + * 重新加载 输入面板 + * + * @param sessionCustomization + */ + public void reloadInputPanel(SessionCustomization sessionCustomization) { + this.customization = sessionCustomization; + Container container = new Container(getActivity(), sessionId, sessionType, this); + inputPanel.reload(container, customization); + inputPanel.reloadActions(sessionCustomization.actions); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onHideInput(HideInputEvent event) { + if (inputPanel != null) { + inputPanel.hideInputMethod(); + inputPanel.collapse(true); + } + } + + @SuppressLint("CheckResult") + @Subscribe(threadMode = ThreadMode.MAIN) + public void onReloadInputPanel(MessageSizeEvent event) { + if (inputPanel != null) { + if (event.getSize() > 0) { + tvChatLimit.setVisibility(View.GONE); + inputPanel.setLimitLevel(true, ""); + } else { + IMCustomModel.get().getPrivateChatLimit(sessionId) + .subscribe(((privateChatLimitInfo, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + } else { + isChat = privateChatLimitInfo.isChat(); + hintText = ResUtil.getString(R.string.im_fragment_messagefragment_02); + inputPanel.setLimitLevel(privateChatLimitInfo.isChat(), privateChatLimitInfo.getMessage()); + + String experLevel = ResUtil.getString(R.string.im_fragment_messagefragment_03) + privateChatLimitInfo.getWealthLevel(); + String charmLevel = ResUtil.getString(R.string.im_fragment_messagefragment_04) + privateChatLimitInfo.getCharmLevel(); + String privacyAgreementDescTip = getContext().getString(R.string.text_chat_limit, experLevel, charmLevel); + SpannableString ss = new SpannableString(privacyAgreementDescTip); + int experLevelIndex = privacyAgreementDescTip.indexOf(experLevel); + int charmLevelIndex = privacyAgreementDescTip.indexOf(charmLevel); + + + ss.setSpan(new ForegroundColorSpan(ContextCompat.getColor(getContext(), R.color.color_9168FA)), experLevelIndex, experLevelIndex + experLevel.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + ss.setSpan(new OriginalDrawStatusClickSpan(ContextCompat.getColor(getContext(), R.color.color_9168FA)) { + @Override + public void onClick(@NonNull View widget) { + if (widget instanceof TextView) + ((TextView) widget).setHighlightColor(getResources().getColor(android.R.color.transparent)); + + CommonWebViewActivity.start(getContext(), UriProvider.getUserLevelUrl()); + } + }, experLevelIndex, experLevelIndex + experLevel.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + ss.setSpan(new ForegroundColorSpan(ContextCompat.getColor(getContext(), R.color.color_9168FA)), charmLevelIndex, charmLevelIndex + charmLevel.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + ss.setSpan(new OriginalDrawStatusClickSpan(ContextCompat.getColor(getContext(), R.color.color_9168FA)) { + @Override + public void onClick(@NonNull View widget) { + if (widget instanceof TextView) + ((TextView) widget).setHighlightColor(getResources().getColor(android.R.color.transparent)); + + CommonWebViewActivity.start(getContext(), UriProvider.getUserLevelUrl()); + } + }, charmLevelIndex, charmLevelIndex + experLevel.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + + tvChatLimit.setText(ss); + tvChatLimit.setHighlightColor(Color.TRANSPARENT); + tvChatLimit.setMovementMethod(new LinkMovementMethod()); + tvChatLimit.setVisibility(isChat ? View.GONE : View.VISIBLE); + } + })); + } + } + } + + @SuppressLint("CheckResult") + public Observable checkPermission(String... mPerms) { + return rxPermissions.request(mPerms); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + @SuppressLint("CheckResult") + public void onNimImageActionEvent(NimImageActionEvent event) { +// checkPermission(Manifest.permission.CAMERA) +// .subscribe(result -> { +// if (result) { +// event.getSuccess().accept(result); +// } else { +// SingleToastUtil.showToast(getString(R.string.ask_again)); +// } +// }); + } + + public void setLimitLevel(int limitLevel) { + } + + // +// + public void setCurrentLevel(int currentLevel) { + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/im/friend/ActFriendList.java b/app/src/main/java/com/chwl/app/ui/im/friend/ActFriendList.java new file mode 100644 index 0000000..4a33f64 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/friend/ActFriendList.java @@ -0,0 +1,36 @@ +package com.chwl.app.ui.im.friend; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; + +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; + +import com.chwl.app.R; +import com.chwl.app.base.BaseMvpActivity; +import com.chwl.app.base.BaseMvpPresenter; +import com.chwl.app.home.fragment.ContactsListFragment; +import com.chwl.library.base.IMvpBaseView; +import com.chwl.library.base.factory.CreatePresenter; + +@CreatePresenter(BaseMvpPresenter.class) +public class ActFriendList extends BaseMvpActivity> implements IMvpBaseView{ + + public static void start(Context context) { + Intent starter = new Intent(context, ActFriendList.class); + context.startActivity(starter); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.act_friend_list); + initTitleBar(getString(R.string.message_contact)); + Fragment fragment = ContactsListFragment.newInstance(); + FragmentManager manager = getSupportFragmentManager(); + manager.beginTransaction().add(R.id.fl_friend_list, fragment).commit(); + + } +} diff --git a/app/src/main/java/com/chwl/app/ui/im/friend/FriendFragmentCpDelegate.kt b/app/src/main/java/com/chwl/app/ui/im/friend/FriendFragmentCpDelegate.kt new file mode 100644 index 0000000..9a57b07 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/friend/FriendFragmentCpDelegate.kt @@ -0,0 +1,108 @@ +package com.chwl.app.ui.im.friend + +import android.text.TextUtils +import androidx.fragment.app.viewModels +import com.chwl.app.R +import com.chwl.app.base.BaseFragment +import com.chwl.app.common.widget.dialog.DialogManager +import com.chwl.app.relation.cp.CpViewHelper +import com.chwl.app.relation.cp.dialog.CpInvitePageDialog +import com.chwl.app.relation.cp.viewmodel.CpViewModel +import com.chwl.app.ui.pay.ChargeActivity +import com.chwl.app.ui.webview.CommonWebViewActivity +import com.chwl.core.Constants +import com.chwl.core.UriProvider +import com.chwl.core.relation.cp.bean.CpInvitePageEntity +import com.chwl.core.utils.extension.toast +import com.chwl.library.common.util.DeviceUtil +import com.chwl.library.utils.AppMetaDataUtil + +class FriendFragmentCpDelegate(private val fragment: BaseFragment) { + private val cpViewModel: CpViewModel by fragment.viewModels() + private val cpInviteDialog by lazy { + CpInvitePageDialog(fragment.requireContext()) + .apply { listener = inviteDialogListener } + } + + init { + val manager = DialogManager(fragment.requireContext()) + cpViewModel.loadingLiveData.observe(fragment) { aBoolean: Boolean -> + if (aBoolean) { + manager.showProgressDialog(fragment.context) + } else manager.dismissDialog() + } + cpViewModel.cpInvitePageData.observe(fragment) { + showInvitePageDialog(it) + } + } + + /** + * 邀請好友組隊 + */ + fun inviteCp(uid: Long) { + cpViewModel.getCpInvitePageData(uid) + } + + /** + * 顯示邀請彈窗 ,填寫邀請CP所需的信息 + */ + + private fun showInvitePageDialog(info: CpInvitePageEntity) { + with(cpInviteDialog) { + invitePageEntity = info + if (isShowing) closeDialog() + openDialog() + } + } + + /** + * 顯示發送邀請確認彈窗 + */ + private fun showSentTipDialog( + cpInvitePageEntity: CpInvitePageEntity, + declaration: String, + ) { + CpViewHelper.showInviteTipDialog( + fragment.requireContext(), + "確定送出${cpInvitePageEntity.propsName}禮物與Ta結成CP關系嗎?", + "(若對方拒接或24小時未同意,鉆石將會返還)" + ) { + cpViewModel.makeCpInvite( + cpInvitePageEntity.acceptUid, + declaration, + cpInvitePageEntity.propsId + ) { + DialogManager(fragment.context).showOkCancelDialog( + "鉆石余額不足,請前去充值!" + ) { +// if (AppMetaDataUtil.getChannelID() == Constants.GOOGLE) { + ChargeActivity.start(fragment.requireContext()) +// } else { +// CommonWebViewActivity.start( +// fragment.requireContext(), UriProvider.getOfficialPay( +// 4, +// DeviceUtil.getDeviceId(fragment.requireContext()) +// ) +// ) +// } + } + } + } + } + + private val inviteDialogListener = + object : CpInvitePageDialog.DialogClickListener { + override fun onSentClick( + cpInvitePageEntity: CpInvitePageEntity, + declaration: String + ) { + if (TextUtils.isEmpty(declaration)) { + fragment.context?.resources?.getString( + R.string.invite_cp_empty_declaration_tip + ).toast() + return + } + showSentTipDialog(cpInvitePageEntity, declaration) + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/im/friend/FriendListAdapter.java b/app/src/main/java/com/chwl/app/ui/im/friend/FriendListAdapter.java new file mode 100644 index 0000000..4ef759c --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/friend/FriendListAdapter.java @@ -0,0 +1,191 @@ +package com.chwl.app.ui.im.friend; + +import android.app.Activity; +import android.text.TextUtils; +import android.view.View; +import android.widget.TextView; + +import androidx.appcompat.widget.AppCompatImageView; +import androidx.core.content.ContextCompat; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.app.friend.action.AbstractSelectFriendAction; +import com.chwl.app.room_chat.activity.NimRoomP2PMessageActivity; +import com.chwl.app.ui.im.avtivity.NimP2PMessageActivity; +import com.chwl.app.ui.user.activity.UserInfoActivity; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.app.ui.widget.NobleAvatarView; +import com.chwl.app.vip.util.VipHelper; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.library.common.util.OtherExtKt; +import com.chwl.library.utils.ResUtil; + +/** + * @author chenran + * @date 2017/10/3 + */ + +public class FriendListAdapter extends BaseQuickAdapter { + + private Activity context; + private int type = AbstractSelectFriendAction.TYPE_NORMAL; + private OnItemClickListener onItemClickListener; + + public FriendListAdapter(Activity context) { + super(R.layout.list_item_friend_new); + this.context = context; + } + + public void setType(int type) { + this.type = type; + } + + public void setRylListener(OnItemClickListener onClickListener) { + onItemClickListener = onClickListener; + } + + @Override + protected void convert(BaseViewHolder helper, UserInfo item) { + if (item == null) return; + + helper.setText(R.id.tv_userName, item.getNick()) + .setText(R.id.tv_user_desc, item.getUserDesc() != null ? + item.getUserDesc() + : helper.itemView.getContext().getResources().getString(R.string.msg_no_user_desc)); + + View vipIcon = helper.getView(R.id.iv_vip_icon); + VipHelper.loadVipNameplate(helper.getView(R.id.iv_vip_icon), item.getUserVipInfoVO()); + VipHelper.loadVipNickColor(helper.getView(R.id.tv_userName), item.getUserVipInfoVO(), "#FF333333"); + NobleAvatarView nobleAvatarView = helper.getView(R.id.noble_avatar_view); + nobleAvatarView.setSize(47, 65, 15); + nobleAvatarView.setData(item.getAvatar(), item.getNobleUsers()); + nobleAvatarView.setOnClickListener(v -> { + if (type == AbstractSelectFriendAction.TYPE_NORMAL + || type == AbstractSelectFriendAction.TYPE_CP + || type == AbstractSelectFriendAction.TYPE_SEND_DECORATION) { + UserInfoActivity.Companion.start(context, item.getUid()); + } + }); + +// GenderAgeTextView tvGenderAge = helper.getView(R.id.tv_gender_age); +// tvGenderAge.setGender(item.getGender()); +// tvGenderAge.setBirthDay(item.getBirth()); + + // 官字 icon +// helper.getView(R.id.iv_user_official).setVisibility(item.isOfficial() ? View.VISIBLE : View.GONE); + +// AppCompatImageView ivNobleLevel = helper.getView(R.id.iv_noble_level); +// if (ivNobleLevel != null) { +// if (item.getNobleUsers() != null) { +// ivNobleLevel.setVisibility(View.VISIBLE); +// String badgeByLevel = NobleUtil.getBadgeByLevel(item.getNobleUsers().getLevel()); +// if (!TextUtils.isEmpty(badgeByLevel)) { +// NobleUtil.loadResource(badgeByLevel, ivNobleLevel); +// } else { +// ivNobleLevel.setVisibility(View.GONE); +// } +// } else { +// ivNobleLevel.setVisibility(View.GONE); +// } +// } + + + AppCompatImageView ivUserLevel = helper.getView(R.id.iv_user_level); + ivUserLevel.setVisibility(View.GONE); + if (item.getUserLevelVo() != null && !TextUtils.isEmpty(item.getUserLevelVo().getExperUrl())) { + ivUserLevel.setVisibility(View.VISIBLE); + ImageLoadUtils.loadImage(mContext, item.getUserLevelVo().getExperUrl(), ivUserLevel); + } + + AppCompatImageView ivCharmLevel = helper.getView(R.id.iv_charm_level); + ivCharmLevel.setVisibility(View.GONE); + if (item.getUserLevelVo() != null && !TextUtils.isEmpty(item.getUserLevelVo().getCharmUrl())) { + ivCharmLevel.setVisibility(View.VISIBLE); + ImageLoadUtils.loadImage(mContext, item.getUserLevelVo().getCharmUrl(), ivCharmLevel); + } + + helper.getView(R.id.container).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + switch (type) { + case AbstractSelectFriendAction.TYPE_NORMAL: + String account = String.valueOf(item.getUid()); + NimP2PMessageActivity.start(context, account); + break; + + case AbstractSelectFriendAction.TYPE_SHARE: + case AbstractSelectFriendAction.TYPE_WORLD_DYNAMIC: + if (onItemClickListener != null) { + onItemClickListener.sendListener(item); + } + break; + + case AbstractSelectFriendAction.ROOM_MSG: + NimRoomP2PMessageActivity.start(context, String.valueOf(item.getUid())); + break; + case AbstractSelectFriendAction.TYPE_CP: + case AbstractSelectFriendAction.TYPE_SEND_DECORATION: + UserInfoActivity.Companion.start(context, item.getUid()); + break; + } + } + }); + + switch (type) { + case AbstractSelectFriendAction.TYPE_CAR: + case AbstractSelectFriendAction.TYPE_WEAR: + case AbstractSelectFriendAction.TYPE_SEND_DECORATION: + helper.getView(R.id.tv_send).setVisibility(View.VISIBLE); + helper.getView(R.id.tv_send).setOnClickListener(v -> { + if (onItemClickListener != null) { + onItemClickListener.sendListener(item); + } + }); + break; + case AbstractSelectFriendAction.TYPE_CP: + TextView tvInvite = helper.getView(R.id.tv_invite_cp); + tvInvite.setVisibility(View.VISIBLE); + //1-邀请中,2-已有CP,3-可邀请 + final int cpState = item.getCpState(); + tvInvite.setEnabled(cpState != 1 && cpState != 2); + tvInvite.setText( + cpState == 1 ? context.getResources().getString(R.string.invite_cp_state_invited) : + cpState == 2 ? context.getResources().getString(R.string.has_cp) : + context.getResources().getString(R.string.invite_cp) + ); + tvInvite.setOnClickListener(v -> { + if (onItemClickListener != null) { + onItemClickListener.sendListener(item); + } + }); + TextView tvDesc = helper.getView(R.id.tv_user_desc); + tvDesc.setText(ResUtil.getString(R.string.im_friend_friendlistadapter_01) + item.getErbanNo()); + tvDesc.setTextColor(ContextCompat.getColor(context, R.color.color_999999)); + tvDesc.setTextSize(12f); + break; + } + + View view = helper.getView(R.id.userInfoLayout); + if (view != null) { + view.post(() -> { + int iconNum = 0; + if (vipIcon.getVisibility() == View.VISIBLE) iconNum++; + if (ivUserLevel.getVisibility() == View.VISIBLE) iconNum++; + if (ivCharmLevel.getVisibility() == View.VISIBLE) iconNum++; + + int width = view.getWidth(); + int i = width - OtherExtKt.toDP(42) * iconNum; + TextView textView = helper.getView(R.id.tv_userName); + textView.setMaxWidth(i); + }); + } + + } + + public interface OnItemClickListener { + void sendListener(UserInfo attentionInfo); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/im/friend/FriendListFragment.java b/app/src/main/java/com/chwl/app/ui/im/friend/FriendListFragment.java new file mode 100644 index 0000000..c94761d --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/friend/FriendListFragment.java @@ -0,0 +1,264 @@ +package com.chwl.app.ui.im.friend; + +import static com.chwl.core.Constants.IS_SEND; + +import android.app.Activity; +import android.os.Bundle; + +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.chwl.app.R; +import com.chwl.app.base.BaseFragment; +import com.chwl.app.common.EmptyViewHelper; +import com.chwl.app.decoration.helper.DecorationHelper; +import com.chwl.app.friend.action.AbstractSelectFriendAction; +import com.chwl.app.friend.view.SelectFriendActivity; +import com.chwl.core.bean.response.ServiceResult; +import com.chwl.core.manager.IMNetEaseManager; +import com.chwl.core.manager.RelationShipEvent; +import com.chwl.core.relation.cp.CpBindUnbindEvent; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.core.user.event.LoginUserInfoUpdateEvent; +import com.chwl.core.utils.net.RxHelper; +import com.chwl.library.net.rxnet.RxNet; +import com.chwl.library.utils.ResUtil; +import com.orhanobut.logger.Logger; +import com.scwang.smart.refresh.layout.SmartRefreshLayout; +import com.scwang.smart.refresh.layout.api.RefreshLayout; +import com.scwang.smart.refresh.layout.listener.OnRefreshLoadMoreListener; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.ArrayList; +import java.util.List; + +import io.reactivex.Single; +import io.reactivex.disposables.Disposable; +import retrofit2.http.GET; +import retrofit2.http.Query; + +; +; + +/** + * @description: 好友列表界面 + * @author: hewenhao + * @date: 2018/9/6 14:57 + */ +public class FriendListFragment extends BaseFragment { + + private FriendListAdapter adapter = null; + private SelectFriendActivity selectFriendActivity; + private int type = AbstractSelectFriendAction.TYPE_NORMAL; + private SmartRefreshLayout mSwipeRefresh; + private RecyclerView mRecyclerView; + private List infoList; + private boolean send; + private FriendFragmentCpDelegate cpDelegate; + private int mPageNum = 1; + + public static FriendListFragment newInstance(boolean b, int type) { + FriendListFragment friendListFragment = new FriendListFragment(); + Bundle bundle = new Bundle(); + bundle.putBoolean(IS_SEND, b); + bundle.putInt(AbstractSelectFriendAction.KEY_TYPE, type); + friendListFragment.setArguments(bundle); + return friendListFragment; + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + if (activity instanceof SelectFriendActivity) { + selectFriendActivity = (SelectFriendActivity) activity; + } + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + EventBus.getDefault().register(this); + } + + @Override + public void onDestroyView() { + EventBus.getDefault().unregister(this); + super.onDestroyView(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + } + + @Override + public void onFindViews() { + mSwipeRefresh = mView.findViewById(R.id.swipe_refresh); + mRecyclerView = mView.findViewById(R.id.recycler_view); + } + + @Override + public void onSetListener() { + } + + @Override + public void initiate() { + mSwipeRefresh.setOnRefreshLoadMoreListener(new OnRefreshLoadMoreListener() { + @Override + public void onLoadMore(RefreshLayout refreshLayout) { + onFriendListUpdate(false); + } + + @Override + public void onRefresh(RefreshLayout refreshLayout) { + onFriendListUpdate(true); + } + }); + + adapter = new FriendListAdapter(getActivity()); + adapter.setEmptyView(EmptyViewHelper.createEmptyView(getContext(),R.drawable.icon_common_failure,getString(R.string.no_frenids_text))); + if (getArguments() != null) { + send = getArguments().getBoolean(IS_SEND); + adapter.setType(type = getArguments().getInt(AbstractSelectFriendAction.KEY_TYPE, + AbstractSelectFriendAction.TYPE_NORMAL)); + } + switch (type) { + case AbstractSelectFriendAction.TYPE_CP: + adapter.setRylListener(attentionInfo -> { + inviteCp(attentionInfo); + }); + break; + case AbstractSelectFriendAction.TYPE_SEND_DECORATION: + adapter.setRylListener(attentionInfo -> + DecorationHelper.showBuyDialog(mContext, + getDialogManager(), + attentionInfo.getNick(), + attentionInfo.getUid())); + break; + default: + adapter.setRylListener((attentionInfo) -> { + if (selectFriendActivity != null && attentionInfo != null) { + selectFriendActivity.showSureDialog(String.valueOf(attentionInfo.getUid()), + attentionInfo.getAvatar(), attentionInfo.getNick()); + } + }); + break; + } + mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); + mRecyclerView.setAdapter(adapter); + + onFriendListUpdate(true); + + Disposable d = IMNetEaseManager.get().getRelationShipEventObservable().subscribe(this::onGetRelationShipEvent); + mCompositeDisposable.add(d); + } + + private void onGetRelationShipEvent(RelationShipEvent event) { + if (event.event == RelationShipEvent.EVENT_FRIEND_UPDATE) { + onFriendListUpdate(true); + } + } + + + @Override + public int getRootLayoutId() { + return R.layout.fragment_friend_list; + } + + private void onFriendListUpdate(boolean isRefresh) { + if (isRefresh) { + mPageNum = 1; + mSwipeRefresh.setEnableLoadMore(true); + } + getFriendList(mPageNum).compose(bindToLifecycle()) + .doOnSuccess(userInfos -> { + hideStatus(); + + if (userInfos != null && !userInfos.isEmpty()) { + if (mPageNum == 1) { + infoList = userInfos; + hideStatus(); + adapter.setNewData(userInfos); + } else { + infoList = userInfos; + hideStatus(); + adapter.addData(userInfos); + } + mSwipeRefresh.setEnableLoadMore(userInfos.size() == 20); + + if (userInfos.size() == 20) { + mPageNum++; + } + + } else { + if (mPageNum == 1) { + infoList = new ArrayList<>(); + adapter.setNewData(infoList); + } + mSwipeRefresh.setEnableLoadMore(false); + } + mSwipeRefresh.finishLoadMore(); + mSwipeRefresh.finishRefresh(); + + }).doOnError(throwable -> { + if (throwable != null) { + toast(throwable.getMessage()); + } + showNetworkErr(); + mSwipeRefresh.finishLoadMore(); + mSwipeRefresh.finishRefresh(); + }).subscribe(); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onLoginUserInfoUpdateEvent(LoginUserInfoUpdateEvent event) { + mRecyclerView.postDelayed(() -> { + if (getActivity() == null || getActivity().isFinishing()) { + Logger.i(ResUtil.getString(R.string.im_friend_friendlistfragment_01)); + return; + } + FriendListFragment.this.onFriendListUpdate(true); + }, 250); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onCpEvent(CpBindUnbindEvent event) { + onFriendListUpdate(true); + } + + + @Override + public void onReloadData() { + super.onReloadData(); + hideStatus(); + showLoading(); + onFriendListUpdate(true); + } + + + private void inviteCp(UserInfo cpInfo) { + if (cpDelegate == null) { + cpDelegate = new FriendFragmentCpDelegate(this); + } + cpDelegate.inviteCp(cpInfo.getUid()); + } + + + public Single> getFriendList(int pageNum) { + return api.getFriendList(pageNum, 20) + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()); + } + + private Api api = RxNet.create(Api.class); + + public interface Api { + @GET("fans/friend/list") + Single>> getFriendList(@Query("pageNum") int pageNum, + @Query("pageSize") int pageSize); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/im/friend/FriendListFragmentKotlin.kt b/app/src/main/java/com/chwl/app/ui/im/friend/FriendListFragmentKotlin.kt new file mode 100644 index 0000000..93454b5 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/friend/FriendListFragmentKotlin.kt @@ -0,0 +1,157 @@ +//package com.chwl.app.ui.im.friend +// +//import android.app.Activity +//import android.os.Bundle +//import android.support.v7.widget.LinearLayoutManager +//import com.chwl.app.R +//import com.chwl.app.base.BaseFragment +//import com.chwl.app.friend.action.AbstractSelectFriendAction +//import com.chwl.app.friend.view.SelectFriendActivity +//import com.chwl.core.Constants.IS_SEND +//import com.chwl.core.im.friend.IMFriendModel +//import com.chwl.core.manager.IMNetEaseManager +//import com.chwl.core.manager.RelationShipEvent +//import com.chwl.core.user.UserModel +//import com.chwl.core.user.bean.UserInfo +//import com.chwl.library.utils.ListUtils +//import kotlinx.android.synthetic.main.fragment_fans_list.* +//import org.greenrobot.eventbus.EventBus +//import org.greenrobot.eventbus.Subscribe +//import org.greenrobot.eventbus.ThreadMode +//import java.util.* +// +///** +// * 好友列表界面 +// * +// * @author chenran +// * @date 2017/9/18 +// */ +//class FriendListFragmentKotlin : BaseFragment() { +// private var adapter: PublicChatHallFriendListAdapter? = null +// private var selectFriendActivity: SelectFriendActivity? = null +// private var type: Int = AbstractSelectFriendAction.TYPE_NORMAL +// +// companion object { +// fun newInstance(boolean: Boolean, type: Int): FriendListFragmentKotlin { +// val friendListFragment = FriendListFragmentKotlin() +// var bundle = Bundle() +// bundle.putBoolean(IS_SEND, boolean) +// bundle.putInt(AbstractSelectFriendAction.KEY_TYPE, type) +// friendListFragment.setArguments(bundle) +// return friendListFragment +// } +// } +// +// override fun onAttach(activity: Activity?) { +// super.onAttach(activity) +// if (activity is SelectFriendActivity) { +// selectFriendActivity = activity +// } +// } +// +// override fun onCreate(savedInstanceState: Bundle?) { +// super.onCreate(savedInstanceState) +// EventBus.getDefault().register(this) +// } +// +// override fun onDestroy() { +// super.onDestroy() +// EventBus.getDefault().unregister(this) +// } +// +// override fun onFindViews() { +// } +// +// override fun onSetListener() { +// +// } +// +// override fun initiate() { +// +// +// swipe_refresh!!.setOnRefreshListener { +// swipe_refresh!!.isRefreshing = true +// loadFriends() +// swipe_refresh!!.isRefreshing = false +// } +// +// adapter = PublicChatHallFriendListAdapter(activity) +// if (arguments != null) { +// adapter!!.setType(arguments?.getInt(AbstractSelectFriendAction.KEY_TYPE, +// AbstractSelectFriendAction.TYPE_NORMAL)!!) +// } +// adapter!!.setRylListener(object : PublicChatHallFriendListAdapter.OnItemClickListener { +// override fun sendListener(attentionInfo: UserInfo?) { +// if (selectFriendActivity != null) { +// selectFriendActivity!!.showSureDialog(attentionInfo!!.uid.toString(), attentionInfo!!.avatar, attentionInfo!!.nick) +// } +// } +// +// }) +// recycler_view!!.layoutManager = LinearLayoutManager(activity) +// recycler_view!!.adapter = adapter +// +// loadFriends() +// +// val d = IMNetEaseManager.get().relationShipEventObservable.subscribe(this::onGetRelationShipEvent) +// mCompositeDisposable.add(d) +// +// } +// +// private fun onGetRelationShipEvent(event: RelationShipEvent) { +// if (event.event == RelationShipEvent.EVENT_FRIEND_UPDATE) { +// onFriendListUpdate(event.accounts) +// } +// } +// +// private fun loadFriends() { +// onFriendListUpdate(IMFriendModel.get().myFriendsAccounts) +// } +// +// override fun getRootLayoutId(): Int { +// return R.layout.fragment_fans_list +// } +// +// //@CoreEvent(coreClientClass = IIMFriendCoreClient::class) +// private fun onFriendListUpdate(accounts: List?) { +// if (ListUtils.isListEmpty(accounts)) { +// showNoData(getString(R.string.no_frenids_text)) +// return +// } +// val ids = ArrayList(accounts!!.size) +// accounts.mapTo(destination = ids) { java.lang.Long.valueOf(it) } +// val mapByUidList = UserModel.get().getCacheThenServerUserInfoMapByUidList(ids) +// onRequestUserInfoMap(mapByUidList) +// } +// +// private fun setData(userInfos: List?) { +// if (userInfos != null && userInfos.isNotEmpty()) { +// hideStatus() +// adapter!!.friendList = userInfos +// adapter!!.notifyDataSetChanged() +// } else { +// showNoData(getString(R.string.no_frenids_text)) +// } +// } +// +// @Subscribe(threadMode = ThreadMode.MAIN) +// fun onCurrentUserInfoUpdate(userInfo: UserInfo) { +// recycler_view!!.postDelayed({ +// onFriendListUpdate(IMFriendModel.get().myFriendsAccounts) +// }, 250) +// } +// +// @Subscribe(threadMode = ThreadMode.MAIN) +// fun onRequestUserInfoMap(userInfoLinkedHashMap: LinkedHashMap?) { +// hideStatus() +// var userInfos: MutableList? = if (adapter == null) null else adapter!!.friendList +// if (userInfoLinkedHashMap != null && userInfoLinkedHashMap.size > 0) { +// userInfos = ArrayList(userInfoLinkedHashMap.size) +// val entries = userInfoLinkedHashMap.entries +// for ((_, value) in entries) { +// userInfos.add(value) +// } +// } +// setData(userInfos) +// } +//} diff --git a/app/src/main/java/com/chwl/app/ui/im/model/IMCustomModel.java b/app/src/main/java/com/chwl/app/ui/im/model/IMCustomModel.java new file mode 100644 index 0000000..6769aca --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/model/IMCustomModel.java @@ -0,0 +1,55 @@ +package com.chwl.app.ui.im.model; + +import com.chwl.core.bean.PrivateChatLimitInfo; +import com.chwl.core.bean.response.ServiceResult; +import com.chwl.core.manager.BaseMvpModel; +import com.chwl.core.utils.net.RxHelper; +import com.chwl.library.net.rxnet.RxNet; + +import io.reactivex.Single; +import retrofit2.http.GET; +import retrofit2.http.Query; + +public class IMCustomModel extends BaseMvpModel { + + private static IMCustomModel model; + private IMCustomModel.Api api = RxNet.create(IMCustomModel.Api.class); + public static IMCustomModel get() { + if (model == null) { + synchronized (IMCustomModel.class) { + if (model == null) { + model = new IMCustomModel(); + } + } + } + return model; + } + + public Single getPrivateChatLimit(String receiverUid) { + return api.getPrivateChatLimit(receiverUid) + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()); + } + public Single getPrivateChatLimitV2(String receiverUid) { + return api.getPrivateChatLimitV2(receiverUid) + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()); + } + + private interface Api { + /** + * 获取是否可以发送私聊 + * @return + */ + @GET("/privateChat/limit") + Single> getPrivateChatLimit(@Query("receiverUid") String receiverUid); + + + /** + * 获取是否可以发送私聊 + * @return + */ + @GET("/privateChat/limitV2") + Single> getPrivateChatLimitV2(@Query("receiverUid") String receiverUid); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/im/recent/RecentContactsFragment.java b/app/src/main/java/com/chwl/app/ui/im/recent/RecentContactsFragment.java new file mode 100644 index 0000000..1cb9bf5 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/recent/RecentContactsFragment.java @@ -0,0 +1,734 @@ +package com.chwl.app.ui.im.recent; + +import static com.netease.nim.uikit.common.ui.dialog.CustomAlertDialog.onSeparateItemClickListener; + +import android.os.Bundle; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.chwl.app.R; +import com.chwl.app.home.event.ContactTrashEvent; +import com.chwl.app.ui.im.recent.adapter.RecentContactAdapter; +import com.chwl.core.utils.CheckUtils; +import com.chwl.core.utils.SystemUidUtil; +import com.chwl.library.utils.ResUtil; +import com.netease.nim.uikit.api.NimUIKit; +import com.netease.nim.uikit.api.model.contact.ContactChangedObserver; +import com.netease.nim.uikit.api.model.main.OnlineStateChangeObserver; +import com.netease.nim.uikit.api.model.team.TeamDataChangedObserver; +import com.netease.nim.uikit.api.model.team.TeamMemberDataChangedObserver; +import com.netease.nim.uikit.api.model.user.UserInfoObserver; +import com.netease.nim.uikit.business.recent.RecentContactsCallback; +import com.netease.nim.uikit.business.recent.TeamMemberAitHelper; +import com.netease.nim.uikit.business.uinfo.UserInfoHelper; +import com.netease.nim.uikit.common.badger.Badger; +import com.netease.nim.uikit.common.fragment.TFragment; +import com.netease.nim.uikit.common.ui.dialog.CustomAlertDialog; +import com.netease.nim.uikit.common.ui.drop.DropCover; +import com.netease.nim.uikit.common.ui.drop.DropManager; +import com.netease.nim.uikit.common.ui.recyclerview.listener.SimpleClickListener; +import com.netease.nim.uikit.impl.NimUIKitImpl; +import com.netease.nimlib.sdk.NIMClient; +import com.netease.nimlib.sdk.Observer; +import com.netease.nimlib.sdk.RequestCallbackWrapper; +import com.netease.nimlib.sdk.ResponseCode; +import com.netease.nimlib.sdk.msg.MsgService; +import com.netease.nimlib.sdk.msg.MsgServiceObserve; +import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum; +import com.netease.nimlib.sdk.msg.model.IMMessage; +import com.netease.nimlib.sdk.msg.model.QueryDirectionEnum; +import com.netease.nimlib.sdk.msg.model.RecentContact; +import com.netease.nimlib.sdk.team.model.Team; +import com.netease.nimlib.sdk.team.model.TeamMember; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import me.everything.android.ui.overscroll.OverScrollDecoratorHelper; + +/** + * 最近联系人列表(会话列表) + *

+ * Created by huangjun on 2015/2/1. + */ +public class RecentContactsFragment extends TFragment { + + // 置顶功能可直接使用,也可作为思路,供开发者充分利用RecentContact的tag字段 + public static final long RECENT_TAG_STICKY = 1; // 联系人置顶tag + + // view + private RecyclerView recyclerView; + + private View emptyBg; + + private TextView emptyHint; + + // data + private List items; + + private Map cached; // 暂缓刷上列表的数据(未读数红点拖拽动画运行时用) + + private RecentContactAdapter adapter; + + private boolean msgLoaded = false; + + private RecentContactsCallback callback; + + private UserInfoObserver userInfoObserver; + + private boolean isInRoom; + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + findViews(); + initMessageList(); + requestMessages(true); + registerObservers(true); + registerDropCompletedListener(true); + registerOnlineStateChangeListener(true); + EventBus.getDefault().register(this); + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (getArguments() != null) { + isInRoom = getArguments().getBoolean("isInRoom", false); + } + } + + public static RecentContactsFragment newInstance(boolean isInRoom) { + Bundle args = new Bundle(); + args.putBoolean("isInRoom", isInRoom); + RecentContactsFragment fragment = new RecentContactsFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_recent_contacts, container, false); + } + + private void notifyDataSetChanged() { + adapter.notifyDataSetChanged(); + boolean empty = items.isEmpty() && msgLoaded; + emptyBg.setVisibility(empty ? View.VISIBLE : View.GONE); + emptyHint.setText(ResUtil.getString(R.string.im_recent_recentcontactsfragment_01)); + } + + @Override + public void onDestroy() { + super.onDestroy(); + EventBus.getDefault().unregister(this); + registerObservers(false); + registerDropCompletedListener(false); + registerOnlineStateChangeListener(false); + DropManager.getInstance().setDropListener(null); + } + + /** + * 查找页面控件 + */ + private void findViews() { + recyclerView = findView(R.id.recycler_view); + emptyBg = findView(R.id.emptyBg); + emptyHint = findView(R.id.message_list_empty_hint); + } + + /** + * 初始化消息列表 + */ + private void initMessageList() { + items = new ArrayList<>(); + cached = new HashMap<>(3); + + // adapter + adapter = new RecentContactAdapter(recyclerView, items); + initCallBack(); + adapter.setCallback(callback); + // recyclerView + recyclerView.setAdapter(adapter); + recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); + recyclerView.addOnItemTouchListener(touchListener); + // ios style + OverScrollDecoratorHelper.setUpOverScroll(recyclerView, OverScrollDecoratorHelper.ORIENTATION_VERTICAL); + + // drop listener + DropManager.getInstance().setDropListener(new DropManager.IDropListener() { + @Override + public void onDropBegin() { + touchListener.setShouldDetectGesture(false); + } + + @Override + public void onDropEnd() { + touchListener.setShouldDetectGesture(true); + } + }); + } + + private void initCallBack() { + if (callback != null) { + return; + } + callback = new RecentContactsCallback() { + @Override + public void onRecentContactsLoaded() { + + } + + @Override + public void onUnreadCountChange(int unreadCount) { + + } + + @Override + public void onItemClick(RecentContact recent) { + if (recent.getSessionType() == SessionTypeEnum.Team) { + NimUIKit.startTeamSession(getActivity(), recent.getContactId()); + } else if (recent.getSessionType() == SessionTypeEnum.P2P) { + NimUIKit.startP2PSession(getActivity(), recent.getContactId()); + } + } + + }; + } + + private SimpleClickListener touchListener = new SimpleClickListener() { + @Override + public void onItemClick(RecentContactAdapter adapter, View view, int position) { + if (callback != null) { + RecentContact recent = adapter.getItem(position); + callback.onItemClick(recent); + } + } + + @Override + public void onItemLongClick(RecentContactAdapter adapter, View view, int position) { + showLongClickMenu(adapter.getItem(position), position); + } + + @Override + public void onItemChildClick(RecentContactAdapter adapter, View view, int position) { + + } + + @Override + public void onItemChildLongClick(RecentContactAdapter adapter, View view, int position) { + + } + }; + + OnlineStateChangeObserver onlineStateChangeObserver = new OnlineStateChangeObserver() { + @Override + public void onlineStateChange(Set accounts) { + notifyDataSetChanged(); + } + }; + + private void registerOnlineStateChangeListener(boolean register) { + if (!NimUIKitImpl.enableOnlineState()) { + return; + } + NimUIKitImpl.getOnlineStateChangeObservable().registerOnlineStateChangeListeners(onlineStateChangeObserver, register); + } + + private void showLongClickMenu(final RecentContact recent, final int position) { + CustomAlertDialog alertDialog = new CustomAlertDialog(getActivity()); + alertDialog.setTitle(UserInfoHelper.getUserTitleName(recent.getContactId(), recent.getSessionType())); + String title = getString(R.string.main_msg_list_delete_chatting); + alertDialog.addItem(title, new onSeparateItemClickListener() { + @Override + public void onClick() { + // 删除会话,删除后,消息历史被一起删除 + NIMClient.getService(MsgService.class).deleteRecentContact2(recent.getContactId(), recent.getSessionType()); + NIMClient.getService(MsgService.class).clearChattingHistory(recent.getContactId(), recent.getSessionType()); + } + }); + + title = (isTagSet(recent, RECENT_TAG_STICKY) ? getString(R.string.main_msg_list_clear_sticky_on_top) : getString(R.string.main_msg_list_sticky_on_top)); + alertDialog.addItem(title, new onSeparateItemClickListener() { + @Override + public void onClick() { + if (isTagSet(recent, RECENT_TAG_STICKY)) { + removeTag(recent, RECENT_TAG_STICKY); + } else { + addTag(recent, RECENT_TAG_STICKY); + } + NIMClient.getService(MsgService.class).updateRecent(recent); + + refreshMessages(false); + } + }); + +// alertDialog.addItem(ResUtil.getString(R.string.im_recent_recentcontactsfragment_02), new onSeparateItemClickListener() { +// @Override +// public void onClick() { +// NIMClient.getService(MsgService.class) +// .deleteRoamingRecentContact(recent.getContactId(), recent.getSessionType()) +// .setCallback(new RequestCallback() { +// @Override +// public void onSuccess(Void param) { +// SingleToastUtil.showToastShort("delete success"); +// } +// +// @Override +// public void onFailed(int code) { +// SingleToastUtil.showToastShort("delete failed, code:" + code); +// } +// +// @Override +// public void onException(Throwable exception) { +// +// } +// }); +// } +// }); + alertDialog.show(); + } + + private void addTag(RecentContact recent, long tag) { + tag = recent.getTag() | tag; + recent.setTag(tag); + } + + private void removeTag(RecentContact recent, long tag) { + tag = recent.getTag() & ~tag; + recent.setTag(tag); + } + + private boolean isTagSet(RecentContact recent, long tag) { + return (recent.getTag() & tag) == tag; + } + + private List loadedRecents; + + public void requestMessages(boolean delay) { + getHandler().postDelayed(new Runnable() { + + @Override + public void run() { + // 查询最近联系人列表数据 + NIMClient.getService(MsgService.class).queryRecentContacts().setCallback(new RequestCallbackWrapper>() { + + @Override + public void onResult(int code, List recents, Throwable exception) { + if (code != ResponseCode.RES_SUCCESS || recents == null) { + return; + } + loadedRecents = recents; + // 初次加载,更新离线的消息中是否有@我的消息 + for (RecentContact loadedRecent : loadedRecents) { + if (loadedRecent.getSessionType() == SessionTypeEnum.Team) { + updateOfflineContactAited(loadedRecent); + } + } + // 此处如果是界面刚初始化,为了防止界面卡顿,可先在后台把需要显示的用户资料和群组资料在后台加载好,然后再刷新界面 + // + msgLoaded = true; + if (isAdded()) { + onRecentContactsLoaded(); + } + } + }); + } + }, delay ? 250 : 0); + } + + private void onRecentContactsLoaded() { + items.clear(); + if (loadedRecents != null) { + items.addAll(loadedRecents); + loadedRecents = null; + } + refreshMessages(true); + + if (callback != null) { + callback.onRecentContactsLoaded(); + } + } + + private void refreshMessages(boolean unreadChanged) { + + if (CheckUtils.isCheckUser()) { + Iterator iterator = items.iterator(); + while (iterator.hasNext()) { + RecentContact recentContact = iterator.next(); + if (!SystemUidUtil.isSystemUid(recentContact.getContactId()) ) { + iterator.remove(); + } + } + } + sortRecentContacts(items); + notifyDataSetChanged(); + + if (unreadChanged) { + + // 方式一:累加每个最近联系人的未读(快) + + int unreadNum = 0; + for (RecentContact r : items) { + unreadNum += r.getUnreadCount(); + } + + // 方式二:直接从SDK读取(相对慢) + //int unreadNum = NIMClient.getService(MsgService.class).getTotalUnreadCount(); + + if (callback != null) { + callback.onUnreadCountChange(unreadNum); + } + + Badger.updateBadgerCount(unreadNum); + } + } + + /** + * **************************** 排序 *********************************** + */ + private void sortRecentContacts(List list) { + if (list.size() == 0) { + return; + } + Collections.sort(list, comp); + } + + private static Comparator comp = new Comparator() { + + @Override + public int compare(RecentContact o1, RecentContact o2) { + // 先比较置顶tag + long sticky = (o1.getTag() & RECENT_TAG_STICKY) - (o2.getTag() & RECENT_TAG_STICKY); + if (sticky != 0) { + return sticky > 0 ? -1 : 1; + } else { + long time = o1.getTime() - o2.getTime(); + return time == 0 ? 0 : (time > 0 ? -1 : 1); + } + } + }; + + /** + * ********************** 收消息,处理状态变化 ************************ + */ + private void registerObservers(boolean register) { + MsgServiceObserve service = NIMClient.getService(MsgServiceObserve.class); + service.observeReceiveMessage(messageReceiverObserver, register); + service.observeRecentContact(messageObserver, register); + service.observeMsgStatus(statusObserver, register); + service.observeRecentContactDeleted(deleteObserver, register); + + registerTeamUpdateObserver(register); + registerTeamMemberUpdateObserver(register); + NimUIKit.getContactChangedObservable().registerObserver(friendDataChangedObserver, register); + if (register) { + registerUserInfoObserver(); + } else { + unregisterUserInfoObserver(); + } + } + + /** + * 注册群信息&群成员更新监听 + */ + private void registerTeamUpdateObserver(boolean register) { + NimUIKit.getTeamChangedObservable().registerTeamDataChangedObserver(teamDataChangedObserver, register); + } + + private void registerTeamMemberUpdateObserver(boolean register) { + NimUIKit.getTeamChangedObservable().registerTeamMemberDataChangedObserver(teamMemberDataChangedObserver, register); + } + + private void registerDropCompletedListener(boolean register) { + if (register) { + DropManager.getInstance().addDropCompletedListener(dropCompletedListener); + } else { + DropManager.getInstance().removeDropCompletedListener(dropCompletedListener); + } + } + + // 暂存消息,当RecentContact 监听回来时使用,结束后清掉 + private Map> cacheMessages = new HashMap<>(); + + //监听在线消息中是否有@我 + private Observer> messageReceiverObserver = new Observer>() { + @Override + public void onEvent(List imMessages) { + if (imMessages != null) { + for (IMMessage imMessage : imMessages) { + if (!TeamMemberAitHelper.isAitMessage(imMessage)) { + continue; + } + Set cacheMessageSet = cacheMessages.get(imMessage.getSessionId()); + if (cacheMessageSet == null) { + cacheMessageSet = new HashSet<>(); + cacheMessages.put(imMessage.getSessionId(), cacheMessageSet); + } + cacheMessageSet.add(imMessage); + } + } + } + }; + + Observer> messageObserver = new Observer>() { + @Override + public void onEvent(List recentContacts) { + if (!DropManager.getInstance().isTouchable()) { + // 正在拖拽红点,缓存数据 + for (RecentContact r : recentContacts) { + cached.put(r.getContactId(), r); + } + + return; + } + + onRecentContactChanged(recentContacts); + } + }; + + private void onRecentContactChanged(List recentContacts) { + int index; + for (RecentContact r : recentContacts) { + index = -1; + for (int i = 0; i < items.size(); i++) { + if (r.getContactId().equals(items.get(i).getContactId()) + && r.getSessionType() == (items.get(i).getSessionType())) { + index = i; + break; + } + } + + if (index >= 0) { + items.remove(index); + } + + items.add(r); + if (r.getSessionType() == SessionTypeEnum.Team && cacheMessages.get(r.getContactId()) != null) { + TeamMemberAitHelper.setRecentContactAited(r, cacheMessages.get(r.getContactId())); + } + } + + cacheMessages.clear(); + + refreshMessages(true); + } + + DropCover.IDropCompletedListener dropCompletedListener = new DropCover.IDropCompletedListener() { + @Override + public void onCompleted(Object id, boolean explosive) { + if (cached != null && !cached.isEmpty()) { + // 红点爆裂,已经要清除未读,不需要再刷cached + if (explosive) { + if (id instanceof RecentContact) { + RecentContact r = (RecentContact) id; + cached.remove(r.getContactId()); + } else if (id instanceof String && ((String) id).contentEquals("0")) { + cached.clear(); + } + } + + // 刷cached + if (!cached.isEmpty()) { + List recentContacts = new ArrayList<>(cached.size()); + recentContacts.addAll(cached.values()); + cached.clear(); + + onRecentContactChanged(recentContacts); + } + } + if (id instanceof RecentContact) { + RecentContact recentContact = (RecentContact) id; + NIMClient.getService(MsgService.class).clearUnreadCount(recentContact.getContactId(), recentContact.getSessionType()); + } + } + }; + + Observer statusObserver = new Observer() { + @Override + public void onEvent(IMMessage message) { + int index = getItemIndex(message.getUuid()); + if (index >= 0 && index < items.size()) { + RecentContact item = items.get(index); + item.setMsgStatus(message.getStatus()); + refreshViewHolderByIndex(index); + } + } + }; + + Observer deleteObserver = new Observer() { + @Override + public void onEvent(RecentContact recentContact) { + if (recentContact != null) { + for (RecentContact item : items) { + if (TextUtils.equals(item.getContactId(), recentContact.getContactId()) + && item.getSessionType() == recentContact.getSessionType()) { + items.remove(item); + refreshMessages(true); + break; + } + } + } else { + items.clear(); + refreshMessages(true); + } + } + }; + + TeamDataChangedObserver teamDataChangedObserver = new TeamDataChangedObserver() { + + @Override + public void onUpdateTeams(List teams) { + adapter.notifyDataSetChanged(); + } + + @Override + public void onRemoveTeam(Team team) { + + } + }; + + TeamMemberDataChangedObserver teamMemberDataChangedObserver = new TeamMemberDataChangedObserver() { + @Override + public void onUpdateTeamMember(List members) { + adapter.notifyDataSetChanged(); + } + + @Override + public void onRemoveTeamMember(List member) { + + } + }; + + private int getItemIndex(String uuid) { + for (int i = 0; i < items.size(); i++) { + RecentContact item = items.get(i); + if (TextUtils.equals(item.getRecentMessageId(), uuid)) { + return i; + } + } + + return -1; + } + + protected void refreshViewHolderByIndex(final int index) { + if (recyclerView == null) return; + recyclerView.post(() -> adapter.notifyItemChanged(index)); + } + + public void setCallback(RecentContactsCallback callback) { + this.callback = callback; + } + + private void registerUserInfoObserver() { + if (userInfoObserver == null) { + userInfoObserver = new UserInfoObserver() { + @Override + public void onUserInfoChanged(List accounts) { + refreshMessages(false); + } + }; + } + NimUIKit.getUserInfoObservable().registerObserver(userInfoObserver, true); + } + + private void unregisterUserInfoObserver() { + if (userInfoObserver != null) { + NimUIKit.getUserInfoObservable().registerObserver(userInfoObserver, false); + } + } + + ContactChangedObserver friendDataChangedObserver = new ContactChangedObserver() { + @Override + public void onAddedOrUpdatedFriends(List accounts) { + refreshMessages(false); + } + + @Override + public void onDeletedFriends(List accounts) { + refreshMessages(false); + } + + @Override + public void onAddUserToBlackList(List account) { + refreshMessages(false); + } + + @Override + public void onRemoveUserFromBlackList(List account) { + refreshMessages(false); + } + }; + + private void updateOfflineContactAited(final RecentContact recentContact) { + if (recentContact == null || recentContact.getSessionType() != SessionTypeEnum.Team + || recentContact.getUnreadCount() <= 0) { + return; + } + + // 锚点 + List uuid = new ArrayList<>(1); + uuid.add(recentContact.getRecentMessageId()); + + List messages = NIMClient.getService(MsgService.class).queryMessageListByUuidBlock(uuid); + + if (messages == null || messages.size() < 1) { + return; + } + final IMMessage anchor = messages.get(0); + + // 查未读消息 + NIMClient.getService(MsgService.class).queryMessageListEx(anchor, QueryDirectionEnum.QUERY_OLD, + recentContact.getUnreadCount() - 1, false).setCallback(new RequestCallbackWrapper>() { + + @Override + public void onResult(int code, List result, Throwable exception) { + if (code == ResponseCode.RES_SUCCESS && result != null) { + result.add(0, anchor); + Set messages = null; + // 过滤存在的@我的消息 + for (IMMessage msg : result) { + if (TeamMemberAitHelper.isAitMessage(msg)) { + if (messages == null) { + messages = new HashSet<>(); + } + messages.add(msg); + } + } + + // 更新并展示 + if (messages != null) { + TeamMemberAitHelper.setRecentContactAited(recentContact, messages); + notifyDataSetChanged(); + } + } + } + }); + + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onContactTrashEvent(ContactTrashEvent event) { + NIMClient.getService(MsgService.class).clearAllUnreadCount(); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/im/recent/RecentListFragment.java b/app/src/main/java/com/chwl/app/ui/im/recent/RecentListFragment.java new file mode 100644 index 0000000..64e9089 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/recent/RecentListFragment.java @@ -0,0 +1,273 @@ +package com.chwl.app.ui.im.recent; + +import android.annotation.SuppressLint; +import android.os.Bundle; +import android.text.TextUtils; + +import androidx.annotation.Nullable; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; + +import com.google.gson.Gson; +import com.netease.nim.uikit.business.recent.RecentContactsCallback; +import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum; +import com.netease.nimlib.sdk.msg.model.RecentContact; +import com.chwl.app.R; +import com.chwl.app.base.BaseFragment; +import com.chwl.app.module_hall.im.NimHelper; +import com.chwl.app.module_hall.team.activity.HallTeamMessageActivity; +import com.chwl.app.team.view.NimTeamMessageActivity; +import com.chwl.app.ui.im.avtivity.NimP2PMessageActivity; +import com.chwl.app.room_chat.activity.NimHallTeamRoomMessageActivity; +import com.chwl.app.room_chat.activity.NimRoomP2PMessageActivity; +import com.chwl.app.room_chat.activity.NimTeamRoomMessageActivity; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.auth.event.LoginEvent; +import com.chwl.core.im.RefreshInRoomListEvent; +import com.chwl.core.user.AttentionModel; +import com.chwl.core.user.bean.AttentionInfo; +import com.chwl.core.user.bean.AttentionItem; +import com.chwl.core.user.event.LoadLoginUserInfoEvent; +import com.chwl.core.utils.net.BeanObserver; +import com.chwl.library.utils.CommonUtils; +import com.chwl.library.utils.ResUtil; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import io.reactivex.Single; +import io.reactivex.functions.BiConsumer; + +/** + * 最近聊天列表 + * + * @author chenran + * @date 2017/9/18 + */ +public class RecentListFragment extends BaseFragment { + private RecentContactsFragment recentContactsFragment; + private boolean isInRoom; + + public static RecentListFragment newInstance(boolean isInRoom) { + + Bundle args = new Bundle(); + args.putBoolean("isInRoom", isInRoom); + RecentListFragment fragment = new RecentListFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + EventBus.getDefault().register(this); + if (getArguments() != null) { + isInRoom = getArguments().getBoolean("isInRoom", false); + } + } + + @SuppressLint("CheckResult") + @Override + public void onFindViews() { + recentContactsFragment = RecentContactsFragment.newInstance(isInRoom); + FragmentManager fragmentManager = getChildFragmentManager(); + FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); + fragmentTransaction.replace(R.id.recent_container, recentContactsFragment).commitAllowingStateLoss(); + // 等级限制 + setFindNewbieView(); + } + + @SuppressLint("CheckResult") + private void setFindNewbieView() { + } + + @SuppressLint("CheckResult") + @Override + public void onStart() { + super.onStart(); + } + + @Override + public void onSetListener() { + } + + @Override + public void initiate() { + recentContactsFragment.setCallback(new RecentContactsCallback() { + @Override + public void onRecentContactsLoaded() { + + } + + @Override + public void onUnreadCountChange(int unreadCount) { + + } + + @Override + public void onItemClick(RecentContact recent) { + if (CommonUtils.isFastDoubleClick(800)) return; + if (recent.getSessionType() == SessionTypeEnum.Team) { + //判断群类型 + NimHelper.getTeamById(RecentListFragment.this, recent.getContactId()) + .flatMap(team -> { + int type = 0; + String ext = team.getExtServer(); + if (!TextUtils.isEmpty(ext)) { + TeamExt teamExt = new Gson().fromJson(ext, TeamExt.class); + if (teamExt != null) { + type = teamExt.getType(); + } + } + return Single.just(type); + }) + .subscribe(new BeanObserver() { + @Override + public void onErrorMsg(String error) { + toast(error); + } + + @Override + public void onSuccess(Integer type) { + if (type == null) { + return; + } + if (type == 0) {//家族群 + if (isInRoom) { + NimTeamRoomMessageActivity.start(getActivity(), recent.getContactId()); + } else { + NimTeamMessageActivity.start(getActivity(), recent.getContactId()); + } + } else if (type == 1) {//厅群 + if (isInRoom) { + NimHallTeamRoomMessageActivity.start(mContext, recent.getContactId()); + } else { + HallTeamMessageActivity.start(mContext, recent.getContactId()); + } + } else { + toast(ResUtil.getString(R.string.im_recent_recentlistfragment_05)); + } + } + }); + } else if (recent.getSessionType() == SessionTypeEnum.P2P) { + if (isInRoom) { + NimRoomP2PMessageActivity.start(mContext, recent.getContactId()); + } else { + NimP2PMessageActivity.start(mContext, recent.getContactId()); + } + } + } + + }); + } + + @Override + public int getRootLayoutId() { + return R.layout.fragment_recent_list; + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onLoginUserInfoUpdateEvent(LoadLoginUserInfoEvent event) { + recentContactsFragment.requestMessages(true); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void refreshInRoomList(RefreshInRoomListEvent event) { + loadAttentionList(); + } + + @Override + public void setUserVisibleHint(boolean isVisibleToUser) { + super.setUserVisibleHint(isVisibleToUser); + if (isVisibleToUser) { // viewpager切换刷新 关注用户在房间内 数据 + loadAttentionList(); + } + } + + /** + * 返回当前页,实时刷新数据 + * 1、其他activity返回msgfragment; + * 2、首页底部tab点击切换返回msgfragment; + * 3、msgfragment viewpager 左右切换 + */ + @SuppressLint("CheckResult") + private void loadAttentionList() { + AttentionModel.get().getAttentionList( + AuthModel.get().getCurrentUid(), + 1, + 200) + .flatMap(attentionInfos -> { + if (attentionInfos != null) { + Iterator iterator = attentionInfos.iterator(); + while (iterator.hasNext()) { + if (iterator.next().getUserInRoom() == null) { + iterator.remove(); + } + } + } + return Single.just(attentionInfos); + }) + .compose(bindToLifecycle()) + .subscribe(new BiConsumer, Throwable>() { + @Override + public void accept(List attentionInfos, Throwable throwable) throws Exception { + + if (attentionInfos != null && attentionInfos.size() > 0) { + + List attentionItems = new ArrayList<>(); + AttentionItem attentionItem = new AttentionItem(AttentionItem.TYPE_PLAY_TOGETHER, null); + //一起玩 +// attentionItems.add(attentionItem); + +// int count = 0; + for (AttentionInfo attentionInfo : attentionInfos) { +// if (count >= 20) { // 最多展示20个 +// break; +// } + attentionItem = new AttentionItem(AttentionItem.TYPE_ATTENTION, attentionInfo); + attentionItems.add(attentionItem); +// count++; + } + + // 超过20,提供进入关注列表页入口 +// if (attentionInfos.size() > 20) { +// attentionItem = new AttentionItem(AttentionItem.TYPE_ATTENTION_MORE, null); +// attentionItems.add(attentionItem); +// } + +// if (rvAttentionOnline != null) { +// rvAttentionOnline.setVisibility(View.VISIBLE); +// } +// +// if (mAttentionInRoomAdapter != null) { +// mAttentionInRoomAdapter.setNewData(attentionItems); +// } + + } else { +// if (rvAttentionOnline != null) { +// rvAttentionOnline.setVisibility(View.GONE); +// } + } + + } + }); + + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onLoginEvent(LoginEvent event) { + //登录成功刷新消息页萌新 + setFindNewbieView(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + EventBus.getDefault().unregister(this); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/im/recent/TeamExt.java b/app/src/main/java/com/chwl/app/ui/im/recent/TeamExt.java new file mode 100644 index 0000000..16b5c06 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/recent/TeamExt.java @@ -0,0 +1,21 @@ +package com.chwl.app.ui.im.recent; + +import java.io.Serializable; + +/** + * 群的拓展信息 + * Created by lvzebiao on 2019/1/14. + */ + +public class TeamExt implements Serializable { + + private int type; + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/im/recent/adapter/AttentionInRoomAdapter.java b/app/src/main/java/com/chwl/app/ui/im/recent/adapter/AttentionInRoomAdapter.java new file mode 100644 index 0000000..4f7e6f8 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/recent/adapter/AttentionInRoomAdapter.java @@ -0,0 +1,63 @@ +package com.chwl.app.ui.im.recent.adapter; + +import com.chad.library.adapter.base.BaseMultiItemQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.app.common.widget.CircleImageView; +import com.chwl.app.ui.utils.ImageLoadUtilsV2; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.core.user.bean.AttentionInfo; +import com.chwl.core.user.bean.AttentionItem; + +import java.util.ArrayList; + +public class AttentionInRoomAdapter extends BaseMultiItemQuickAdapter { + + public AttentionInRoomAdapter() { + super(new ArrayList<>()); + addItemType(AttentionItem.TYPE_PLAY_TOGETHER, R.layout.item_play_together); + addItemType(AttentionItem.TYPE_ATTENTION, R.layout.item_attention_in_room); + addItemType(AttentionItem.TYPE_ATTENTION_MORE, R.layout.item_attention_more); + } + + @Override + protected void convert(BaseViewHolder helper, AttentionItem item) { + + if (item == null) { + return; + } + + switch (item.getItemType()) { + case AttentionItem.TYPE_PLAY_TOGETHER: + helper.addOnClickListener(R.id.ll_play_together); + break; + + case AttentionItem.TYPE_ATTENTION: + helper.addOnClickListener(R.id.ll_attention_in_room); + setAttentionInRoom(helper, item); + break; + + case AttentionItem.TYPE_ATTENTION_MORE: + helper.addOnClickListener(R.id.cl_attention_more); + break; + } + + } + + private void setAttentionInRoom(BaseViewHolder helper, AttentionItem item) { + try { + AttentionInfo attentionInfo = (AttentionInfo) item.getData(); + if (attentionInfo != null) { + helper.setText(R.id.tv_name_attention_in_room, attentionInfo.nick); + + CircleImageView imageView = helper.getView(R.id.civ_attention_in_room); + imageView.setBorderWidth(UIUtil.dip2px(mContext,1)); + imageView.setBorderColor(mContext.getResources().getColor(R.color.appColor)); + ImageLoadUtilsV2.loadImage(imageView, attentionInfo.avatar); + } + + } catch (Exception ex) { + ex.printStackTrace(); + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/im/recent/adapter/RecentContactAdapter.java b/app/src/main/java/com/chwl/app/ui/im/recent/adapter/RecentContactAdapter.java new file mode 100644 index 0000000..c77b39b --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/recent/adapter/RecentContactAdapter.java @@ -0,0 +1,52 @@ +package com.chwl.app.ui.im.recent.adapter; + +import androidx.recyclerview.widget.RecyclerView; + +import com.netease.nim.uikit.business.recent.RecentContactsCallback; +import com.netease.nim.uikit.common.ui.recyclerview.adapter.BaseMultiItemQuickAdapter; +import com.netease.nim.uikit.common.ui.recyclerview.holder.NIMBaseViewHolder; +import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum; +import com.netease.nimlib.sdk.msg.model.RecentContact; +import com.chwl.app.R; +import com.chwl.app.ui.im.recent.holder.CommonRecentViewHolder; +import com.chwl.app.ui.im.recent.holder.TeamRecentViewHolder; + +import java.util.List; + +/** + * @author huangjun + * @date 2016/12/11 + */ +public class RecentContactAdapter extends BaseMultiItemQuickAdapter { + + interface ViewType { + int VIEW_TYPE_COMMON = 1; + int VIEW_TYPE_TEAM = 2; + } + + private RecentContactsCallback callback; + + public RecentContactAdapter(RecyclerView recyclerView, List data) { + super(recyclerView, data); + addItemType(ViewType.VIEW_TYPE_COMMON, R.layout.nim_recent_contact_list_item_new, CommonRecentViewHolder.class); + addItemType(ViewType.VIEW_TYPE_TEAM, R.layout.nim_recent_contact_team_list_item, TeamRecentViewHolder.class); + } + + @Override + protected int getViewType(RecentContact item) { + return item.getSessionType() == SessionTypeEnum.Team ? ViewType.VIEW_TYPE_TEAM : ViewType.VIEW_TYPE_COMMON; + } + + @Override + protected String getItemKey(RecentContact item) { + return String.valueOf(item.getSessionType().getValue()) + "_" + item.getContactId(); + } + + public RecentContactsCallback getCallback() { + return callback; + } + + public void setCallback(RecentContactsCallback callback) { + this.callback = callback; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/im/recent/holder/CommonRecentViewHolder.java b/app/src/main/java/com/chwl/app/ui/im/recent/holder/CommonRecentViewHolder.java new file mode 100644 index 0000000..fa7b3f5 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/recent/holder/CommonRecentViewHolder.java @@ -0,0 +1,172 @@ +package com.chwl.app.ui.im.recent.holder; + +import static android.view.View.GONE; +import static android.view.View.INVISIBLE; +import static android.view.View.VISIBLE; + +import android.annotation.SuppressLint; +import android.graphics.drawable.AnimationDrawable; +import android.os.Handler; +import android.text.TextUtils; +import android.view.View; + +import com.chwl.app.R; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.app.vip.util.VipHelper; +import com.chwl.core.level.UserLevelVo; +import com.chwl.core.user.UserModel; +import com.chwl.core.utils.SystemUidUtil; +import com.netease.nim.uikit.api.NimUIKit; +import com.netease.nim.uikit.common.ui.draggablebubbles.BubbleMessageTouchListener; +import com.netease.nim.uikit.common.ui.draggablebubbles.MessageBubbleView; +import com.netease.nim.uikit.common.ui.drop.DropManager; +import com.netease.nim.uikit.common.ui.recyclerview.adapter.BaseQuickAdapter; +import com.netease.nim.uikit.common.ui.recyclerview.holder.NIMBaseViewHolder; +import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum; +import com.netease.nimlib.sdk.msg.model.RecentContact; + +/** + * @author Administrator + */ +public class CommonRecentViewHolder extends RecentViewHolder { + + public CommonRecentViewHolder(BaseQuickAdapter adapter) { + super(adapter); + } + + @Override + protected String getContent(RecentContact recent) { + return descOfMsg(recent); + } + + @Override + protected String getOnlineStateContent(RecentContact recent) { + if (recent.getSessionType() == SessionTypeEnum.P2P && NimUIKit.enableOnlineState()) { + return NimUIKit.getOnlineStateContentProvider().getSimpleDisplay(recent.getContactId()); + } else { + return super.getOnlineStateContent(recent); + } + } + + @Override + public void inflate(NIMBaseViewHolder holder, final RecentContact recent) { + this.imgHead = holder.getView(R.id.img_head); + this.tvNickname = holder.getView(R.id.tv_nickname); + this.tvMessage = holder.getView(R.id.tv_message); + this.tvUnread = holder.getView(R.id.unread_number_tip); + this.imgUnreadExplosion = holder.getView(R.id.unread_number_explosion); + this.tvDatetime = holder.getView(R.id.tv_date_time); + this.imgMsgStatus = holder.getView(R.id.img_msg_status); + this.tvOnlineState = holder.getView(R.id.tv_online_state); + this.ivCharmLevel = holder.getView(R.id.iv_charm_level); + this.tvGenderAge = holder.getView(R.id.tv_gender_age); + mIvNobleHeadWear = holder.getView(R.id.noble_head_wear); + mIvNobleLevel = holder.getView(R.id.iv_noble_level); + mIvNobleBadge = holder.getView(R.id.iv_user_badge); + ivVipIcon = holder.getView(R.id.iv_vip_icon); + + MessageBubbleView.attach(this.tvUnread, new BubbleMessageTouchListener.BubbleDisappearListener() { + @Override + public void dragStart(View view) { + DropManager.getInstance().setTouchable(false); + } + + @Override + public void dismiss(View view) { + DropManager.getInstance().setCurrentId(recent); + DropManager.getInstance().down(tvUnread, tvUnread.getText().toString()); + DropManager.getInstance().dropCompleted(recent); + } + + @Override + public void dragFinish(View view) { + DropManager.getInstance().setTouchable(true); + } + + }); + + } + + @Override + public void refresh(NIMBaseViewHolder holder, RecentContact recent, final int position) { + + + // unread count animation + boolean shouldBoom = lastUnreadCount > 0 && recent.getUnreadCount() == 0; // 未读数从N->0执行爆裂动画; + lastUnreadCount = recent.getUnreadCount(); + + updateBackground(holder, recent, position); + + loadNoble(recent); + + loadPortrait(recent); + + updateNickLabel(recent); + + updateOnlineState(recent); + + updateMsgLabel(holder, recent); + + updateNewIndicator(recent); + + if (shouldBoom) { + Object o = DropManager.getInstance().getCurrentId(); + if (o instanceof String && o.equals("0")) { + imgUnreadExplosion.setImageResource(R.drawable.explosion); + imgUnreadExplosion.setVisibility(VISIBLE); + new Handler().post(new Runnable() { + @Override + public void run() { + ((AnimationDrawable) imgUnreadExplosion.getDrawable()).start(); + // 解决部分手机动画无法播放的问题(例如华为荣耀) + getAdapter().notifyItemChanged(getAdapter().getViewHolderPosition(position)); + } + }); + } + } else { + imgUnreadExplosion.setVisibility(GONE); + } + +// if (getAdapter().isLastDataItem(position)) { +// topLine.setVisibility(GONE); +// } + } + + @SuppressLint("CheckResult") + private void loadNoble(RecentContact recent) { + mIvNobleHeadWear.setVisibility(INVISIBLE); + mIvNobleLevel.setVisibility(GONE); + mIvNobleBadge.setVisibility(GONE); + if (recent == null) return; + String contactId = recent.getContactId(); + //去除小秘书,系统消息 + if (SystemUidUtil.isSystemUid(contactId) ) { + return; + } + + UserModel.get() + .getUserInfo(Long.valueOf(contactId)) + .subscribe(userInfo -> { + UserLevelVo userLevelVo = userInfo.getUserLevelVo(); + if (userLevelVo != null && !TextUtils.isEmpty(userLevelVo.getExperUrl())) { + mIvNobleLevel.setVisibility(VISIBLE); + ImageLoadUtils.loadImage(mIvNobleLevel.getContext(), userLevelVo.getExperUrl(), mIvNobleLevel); + } + if (userLevelVo != null && !TextUtils.isEmpty(userLevelVo.getCharmUrl())) { + ivCharmLevel.setVisibility(VISIBLE); + ImageLoadUtils.loadImage(ivCharmLevel.getContext(), userLevelVo.getCharmUrl(), ivCharmLevel); + } + + if (tvGenderAge != null) { + tvGenderAge.setBirthDay(userInfo.getBirth()); + tvGenderAge.setGender(userInfo.getGender()); + } + + + VipHelper.loadVipNameplate(ivVipIcon,userInfo.getUserVipInfoVO()); + VipHelper.loadVipNickColor(tvNickname, userInfo.getUserVipInfoVO(),"#FF333333"); + }); + } + + +} diff --git a/app/src/main/java/com/chwl/app/ui/im/recent/holder/RecentViewHolder.java b/app/src/main/java/com/chwl/app/ui/im/recent/holder/RecentViewHolder.java new file mode 100644 index 0000000..9bd3841 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/recent/holder/RecentViewHolder.java @@ -0,0 +1,186 @@ +package com.chwl.app.ui.im.recent.holder; + +import static android.view.View.GONE; +import static android.view.View.VISIBLE; + +import android.text.TextUtils; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.appcompat.widget.AppCompatImageView; + +import com.chwl.app.R; +import com.chwl.app.ui.im.recent.RecentContactsFragment; +import com.chwl.app.ui.im.recent.adapter.RecentContactAdapter; +import com.chwl.app.view.GenderAgeTextView; +import com.chwl.core.helper.ImHelperUtils; +import com.netease.nim.uikit.business.recent.RecentContactsCallback; +import com.netease.nim.uikit.business.session.emoji.MoonUtil; +import com.netease.nim.uikit.business.uinfo.UserInfoHelper; +import com.netease.nim.uikit.common.ui.draggablebubbles.BubbleView; +import com.netease.nim.uikit.common.ui.imageview.HeadImageView; +import com.netease.nim.uikit.common.ui.recyclerview.adapter.BaseQuickAdapter; +import com.netease.nim.uikit.common.ui.recyclerview.holder.NIMBaseViewHolder; +import com.netease.nim.uikit.common.ui.recyclerview.holder.RecyclerViewHolder; +import com.netease.nim.uikit.common.util.sys.TimeUtil; +import com.netease.nim.uikit.impl.cache.TeamDataCache; +import com.netease.nimlib.sdk.msg.constant.MsgStatusEnum; +import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum; +import com.netease.nimlib.sdk.msg.model.RecentContact; +import com.netease.nimlib.sdk.team.model.Team; + +public abstract class RecentViewHolder extends RecyclerViewHolder { + + public RecentViewHolder(BaseQuickAdapter adapter) { + super(adapter); + } + + protected int lastUnreadCount = 0; + + protected HeadImageView imgHead; + protected AppCompatImageView mIvNobleHeadWear; + protected AppCompatImageView mIvNobleLevel; + protected AppCompatImageView mIvNobleBadge; + protected AppCompatImageView ivCharmLevel; + protected GenderAgeTextView tvGenderAge; + protected ImageView ivVipIcon; + + protected TextView tvNickname; + + protected TextView tvMessage; + + protected TextView tvDatetime; + + // 消息发送错误状态标记,目前没有逻辑处理 + protected ImageView imgMsgStatus; + + // 未读红点(一个占坑,一个全屏动画) + protected BubbleView tvUnread; + + protected ImageView imgUnreadExplosion; + + protected TextView tvOnlineState; + + protected ImageView msgNotifyIcon; + + // 子类覆写 + protected abstract String getContent(RecentContact recent); + + @Override + public void convert(NIMBaseViewHolder holder, RecentContact data, int position, boolean isScrolling) { + inflate(holder, data); + refresh(holder, data, position); + } + + protected abstract void inflate(NIMBaseViewHolder holder, RecentContact data); + + protected abstract void refresh(NIMBaseViewHolder holder, RecentContact data, int position); + + + protected void updateBackground(NIMBaseViewHolder holder, RecentContact recent, int position) { + //xxx 聊天置顶背景 + View view = holder.getView(R.id.root); + if ((recent.getTag() & RecentContactsFragment.RECENT_TAG_STICKY) == 0) { +// view.setBackgroundResource(R.drawable.shape_white_10dp_round); + } else { +// view.setBackgroundResource(R.drawable.shape_white_10dp_round); + } + } + + protected void loadPortrait(RecentContact recent) { + // 设置头像 todo do im头像处 + if (recent.getSessionType() == SessionTypeEnum.P2P) { + imgHead.loadBuddyAvatar(recent.getContactId()); + } else if (recent.getSessionType() == SessionTypeEnum.Team) { + Team team = TeamDataCache.getInstance().getTeamById(recent.getContactId()); + imgHead.loadTeamIconByTeam(team); + } + } + + protected void updateNewIndicator(RecentContact recent) { + int unreadNum = recent.getUnreadCount(); + setUnRead(unreadNum); + } + + protected void setUnRead(int count) { + tvUnread.setNumText(count); + } + + protected void updateMsgNotifyIcon(RecentContact recentContact) { + // + } + + protected void updateMsgLabel(NIMBaseViewHolder holder, RecentContact recent) { + + // 显示消息具体内容 + MoonUtil.identifyRecentVHFaceExpressionAndTags(holder.getContext(), tvMessage, getContent(recent), -1, 0.45f); + + if (imgMsgStatus != null) { + MsgStatusEnum status = recent.getMsgStatus(); + switch (status) { + case fail: + imgMsgStatus.setImageResource(R.drawable.nim_g_ic_failed_small); + imgMsgStatus.setVisibility(VISIBLE); + break; + case sending: + imgMsgStatus.setImageResource(R.drawable.nim_recent_contact_ic_sending); + imgMsgStatus.setVisibility(VISIBLE); + break; + default: + imgMsgStatus.setVisibility(GONE); + break; + } + } + + + String timeString = TimeUtil.getTimeShowStringToMsg(recent.getTime()); + tvDatetime.setText(timeString); + } + + protected String getOnlineStateContent(RecentContact recent) { + return ""; + } + + protected void updateOnlineState(RecentContact recent) { + if (tvOnlineState != null) { + if (recent.getSessionType() == SessionTypeEnum.Team) { + tvOnlineState.setVisibility(GONE); + } else { + String onlineStateContent = getOnlineStateContent(recent); + if (TextUtils.isEmpty(onlineStateContent)) { + tvOnlineState.setVisibility(GONE); + } else { + tvOnlineState.setVisibility(VISIBLE); + tvOnlineState.setText(getOnlineStateContent(recent)); + } + } + } + } + + protected void updateNickLabel(RecentContact recent) { + switch (recent.getSessionType()) { + case Team: + Team team = TeamDataCache.getInstance().getTeamById(recent.getContactId()); + if (team != null) { + tvNickname.setText(team.getName()); + } + break; + + default: + case P2P: + String nick = UserInfoHelper.getUserTitleName(recent.getContactId(), recent.getSessionType()); + tvNickname.setText(nick); + break; + } + } + + protected RecentContactsCallback getCallback() { + return ((RecentContactAdapter) getAdapter()).getCallback(); + } + + protected String descOfMsg(RecentContact recent) { + return ImHelperUtils.getMsgDigest(recent); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/im/recent/holder/TeamRecentViewHolder.java b/app/src/main/java/com/chwl/app/ui/im/recent/holder/TeamRecentViewHolder.java new file mode 100644 index 0000000..3d91076 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/im/recent/holder/TeamRecentViewHolder.java @@ -0,0 +1,221 @@ +package com.chwl.app.ui.im.recent.holder; + +import static android.view.View.GONE; +import static android.view.View.VISIBLE; + +import android.graphics.drawable.AnimationDrawable; +import android.os.Handler; +import android.text.TextUtils; +import android.view.View; +import android.widget.ImageView; + +import com.google.gson.Gson; +import com.netease.nim.uikit.api.NimUIKit; +import com.netease.nim.uikit.business.recent.TeamMemberAitHelper; +import com.netease.nim.uikit.business.team.helper.TeamHelper; +import com.netease.nim.uikit.common.ui.draggablebubbles.BubbleMessageTouchListener; +import com.netease.nim.uikit.common.ui.draggablebubbles.MessageBubbleView; +import com.netease.nim.uikit.common.ui.drop.DropManager; +import com.netease.nim.uikit.common.ui.recyclerview.adapter.BaseQuickAdapter; +import com.netease.nim.uikit.common.ui.recyclerview.holder.NIMBaseViewHolder; +import com.netease.nimlib.sdk.NIMClient; +import com.netease.nimlib.sdk.msg.attachment.MsgAttachment; +import com.netease.nimlib.sdk.msg.attachment.NotificationAttachment; +import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum; +import com.netease.nimlib.sdk.msg.model.RecentContact; +import com.netease.nimlib.sdk.team.TeamService; +import com.netease.nimlib.sdk.team.constant.TeamMessageNotifyTypeEnum; +import com.netease.nimlib.sdk.team.model.Team; +import com.chwl.app.R; +import com.chwl.app.ui.im.recent.TeamExt; +import com.chwl.core.im.custom.bean.LuckyMoneyAttachment; +import com.chwl.core.im.custom.bean.LuckyMoneyTipsAttachment; + +public class TeamRecentViewHolder extends RecentViewHolder { + + private Team team; + private ImageView ivMiniWorld; + + public TeamRecentViewHolder(BaseQuickAdapter adapter) { + super(adapter); + } + + @Override + public void inflate(NIMBaseViewHolder holder, final RecentContact recent) { + this.imgHead = holder.getView(R.id.img_head); + this.tvNickname = holder.getView(R.id.tv_nickname); + this.tvMessage = holder.getView(R.id.tv_message); + this.tvUnread = holder.getView(R.id.unread_number_tip); + this.imgUnreadExplosion = holder.getView(R.id.unread_number_explosion); + this.tvDatetime = holder.getView(R.id.tv_date_time); + this.imgMsgStatus = holder.getView(R.id.img_msg_status); + this.tvOnlineState = holder.getView(R.id.tv_online_state); + this.msgNotifyIcon = holder.getView(R.id.iv_mute_notification); + this.ivMiniWorld = holder.getView(R.id.iv_mini_world_img); +// topLine = holder.getView(R.id.top_line); + +// holder.addOnClickListener(R.id.unread_number_tip); + + MessageBubbleView.attach(this.tvUnread, new BubbleMessageTouchListener.BubbleDisappearListener() { + @Override + public void dragStart(View view) { + DropManager.getInstance().setTouchable(false); + } + + @Override + public void dismiss(View view) { + DropManager.getInstance().setCurrentId(recent); + DropManager.getInstance().down(tvUnread, tvUnread.getText().toString()); + } + + @Override + public void dragFinish(View view) { + DropManager.getInstance().setTouchable(true); + } + + }); +// this.tvUnread.setTouchListener(new DropFake.ITouchListener() { +// @Override +// public void onDown() { +// DropManager.getInstance().setCurrentId(recent); +// DropManager.getInstance().down(tvUnread, tvUnread.getText()); +// } +// +// @Override +// public void onMove(float curX, float curY) { +// DropManager.getInstance().move(curX, curY); +// } +// +// @Override +// public void onUp() { +// DropManager.getInstance().up(); +// } +// }); + + team = NIMClient.getService(TeamService.class).queryTeamBlock(recent.getContactId()); + } + + @Override + public void refresh(NIMBaseViewHolder holder, RecentContact recent, final int position) { + + // unread count animation + boolean shouldBoom = lastUnreadCount > 0 && recent.getUnreadCount() == 0; // 未读数从N->0执行爆裂动画; + lastUnreadCount = recent.getUnreadCount(); + + updateBackground(holder, recent, position); + + loadPortrait(recent); + + updateOnlineState(recent); + + updateNickLabel(recent); + + updateMsgLabel(holder, recent); + + if (!isNotifyIconShow(recent)) + updateNewIndicator(recent); + else + setUnRead(0);// 关闭消息提醒不显示未读数量 + + updateMsgNotifyIcon(recent); + + if (shouldBoom) { + Object o = DropManager.getInstance().getCurrentId(); + if (o instanceof String && o.equals("0")) { + imgUnreadExplosion.setImageResource(R.drawable.explosion); + imgUnreadExplosion.setVisibility(VISIBLE); + new Handler().post(new Runnable() { + @Override + public void run() { + ((AnimationDrawable) imgUnreadExplosion.getDrawable()).start(); + // 解决部分手机动画无法播放的问题(例如华为荣耀) + getAdapter().notifyItemChanged(getAdapter().getViewHolderPosition(position)); + } + }); + } + } else { + imgUnreadExplosion.setVisibility(GONE); + } + + if (ivMiniWorld != null) { + if (team != null) { + + int type = 0; + String ext = team.getExtServer(); + if (!TextUtils.isEmpty(ext)) { + TeamExt teamExt = new Gson().fromJson(ext, TeamExt.class); + if (teamExt != null) { + type = teamExt.getType(); + } + } + + if (type == 2) { + ivMiniWorld.setVisibility(VISIBLE); + + } else { + ivMiniWorld.setVisibility(GONE); + + } + } else { + ivMiniWorld.setVisibility(GONE); + } + + } + +// if (getAdapter().isLastDataItem(position)) { +// topLine.setVisibility(GONE); +// } + } + + @Override + protected String getContent(RecentContact recent) { + String content = descOfMsg(recent); + + String fromId = recent.getFromAccount(); + MsgAttachment attachment = recent.getAttachment(); + if (!TextUtils.isEmpty(fromId) + && !fromId.equals(NimUIKit.getAccount()) + && !(attachment instanceof NotificationAttachment) + && !(attachment instanceof LuckyMoneyAttachment) + && !(attachment instanceof LuckyMoneyTipsAttachment)) { + String tid = recent.getContactId(); + String teamNick = getTeamUserDisplayName(tid, fromId); + content = teamNick + ": " + content; + + if (TeamMemberAitHelper.hasAitExtension(recent)) { + if (recent.getUnreadCount() == 0) { + TeamMemberAitHelper.clearRecentContactAited(recent); + } else { + content = TeamMemberAitHelper.getAitAlertString(content); + } + } + } + + return content; + } + + private String getTeamUserDisplayName(String tid, String account) { + return TeamHelper.getTeamMemberDisplayName(tid, account); + } + +// @Override +// protected void updateNewIndicator(RecentContact recent) { +// if (team != null && team.getMessageNotifyType() == TeamMessageNotifyTypeEnum.Mute) { +//// NIMClient.getService(MsgService.class).clearUnreadCount(recent.getContactId(), SessionTypeEnum.Team); +// tvUnread.setVisibility(GONE); +// } else { +// super.updateNewIndicator(recent); +// } +// } + + @Override + protected void updateMsgNotifyIcon(RecentContact recentContact) { + super.updateMsgNotifyIcon(recentContact); + msgNotifyIcon.setVisibility(isNotifyIconShow(recentContact) ? VISIBLE : GONE); + } + + private boolean isNotifyIconShow(RecentContact recentContact) { + return recentContact.getSessionType() == SessionTypeEnum.Team + && team != null && team.getMessageNotifyType() == TeamMessageNotifyTypeEnum.Mute; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/indicator_impl/IndicatorHelper.java b/app/src/main/java/com/chwl/app/ui/indicator_impl/IndicatorHelper.java new file mode 100644 index 0000000..a31560e --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/indicator_impl/IndicatorHelper.java @@ -0,0 +1,38 @@ +package com.chwl.app.ui.indicator_impl; + +import android.content.Context; +import android.widget.LinearLayout; + +import androidx.viewpager.widget.ViewPager; + +import com.chwl.app.ui.widget.magicindicator.MagicIndicator; +import com.chwl.app.ui.widget.magicindicator.ViewPagerHelper; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.CommonNavigator; + +import java.util.List; + +/** + * create by lvzebiao @2020/1/7 + */ +public class IndicatorHelper { + + public static void handle(Context context, ViewPager viewPager, MagicIndicator magicIndicator, + List list, OnItemSelectListener listener) { + CommonNavigator commonNavigator = new CommonNavigator(context); + JustColorIndicatorAdapter magicIndicatorAdapter = new JustColorIndicatorAdapter(context, list); + if (listener == null) { + listener = (position, view) -> viewPager.setCurrentItem(position); + } + magicIndicatorAdapter.setOnItemSelectListener(listener); + commonNavigator.setAdapter(magicIndicatorAdapter); + magicIndicator.setNavigator(commonNavigator); + commonNavigator.getTitleContainer().setShowDividers(LinearLayout.SHOW_DIVIDER_MIDDLE); + ViewPagerHelper.bind(magicIndicator, viewPager); + } + + public static void handle(Context context, ViewPager viewPager, MagicIndicator magicIndicator, + List list) { + handle(context, viewPager, magicIndicator, list, null); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/indicator_impl/JustColorIndicatorAdapter.java b/app/src/main/java/com/chwl/app/ui/indicator_impl/JustColorIndicatorAdapter.java new file mode 100644 index 0000000..2ebfa0a --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/indicator_impl/JustColorIndicatorAdapter.java @@ -0,0 +1,79 @@ +package com.chwl.app.ui.indicator_impl; + +import android.content.Context; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import androidx.core.content.ContextCompat; + +import com.chwl.app.R; +import com.chwl.app.ui.widget.XRecyclerView.ScaleTransitionPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.CommonNavigatorAdapter; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.indicators.LinePagerIndicator; + +import java.util.List; + +/** + * create by lvzebiao @2020/1/7 + */ +public class JustColorIndicatorAdapter extends CommonNavigatorAdapter { + + private final Context mContext; + private final List mTitleList; + + + + public JustColorIndicatorAdapter(Context context, List charSequences) { + this.mContext = context; + this.mTitleList = charSequences; + } + + @Override + public int getCount() { + return mTitleList == null ? 0 : mTitleList.size(); + } + + + @Override + public IPagerTitleView getTitleView(Context context, final int i) { + ScaleTransitionPagerTitleView scaleTransitionPagerTitleView = new ScaleTransitionPagerTitleView(context, false); + scaleTransitionPagerTitleView.setNormalColor(ContextCompat.getColor(mContext, R.color.color_B3B3B3)); + scaleTransitionPagerTitleView.setSelectedColor(ContextCompat.getColor(mContext, R.color.color_333333)); + scaleTransitionPagerTitleView.setAlwaysBold(); + scaleTransitionPagerTitleView.setMinScale(1.0f); + scaleTransitionPagerTitleView.setTextSize(16); + int padding = UIUtil.dip2px(context, 11); + scaleTransitionPagerTitleView.setPadding(padding, 0, padding, 0); + scaleTransitionPagerTitleView.setText(mTitleList.get(i)); + scaleTransitionPagerTitleView.setOnClickListener(view -> { + if (mOnItemSelectListener != null) { + mOnItemSelectListener.onItemSelect(i, scaleTransitionPagerTitleView); + } + }); + return scaleTransitionPagerTitleView; + } + + @Override + public IPagerIndicator getIndicator(Context context) { + LinePagerIndicator indicator = new LinePagerIndicator(context); + indicator.setMode(LinePagerIndicator.MODE_EXACTLY); + indicator.setLineHeight(UIUtil.dip2px(mContext, 3)); + indicator.setRoundRadius(UIUtil.dip2px(mContext, 22)); + indicator.setLineWidth(UIUtil.dip2px(mContext, 12)); + indicator.setColors(context.getResources().getColor(R.color.appColor)); + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + lp.bottomMargin = UIUtil.dip2px(mContext, 5); + indicator.setLayoutParams(lp); + return indicator; + } + + private OnItemSelectListener mOnItemSelectListener; + + public void setOnItemSelectListener(OnItemSelectListener onItemSelectListener) { + mOnItemSelectListener = onItemSelectListener; + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/indicator_impl/OnItemSelectListener.java b/app/src/main/java/com/chwl/app/ui/indicator_impl/OnItemSelectListener.java new file mode 100644 index 0000000..0314a86 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/indicator_impl/OnItemSelectListener.java @@ -0,0 +1,12 @@ +package com.chwl.app.ui.indicator_impl; + +import android.widget.TextView; + +/** + * create by lvzebiao @2020/1/7 + */ +public interface OnItemSelectListener { + + void onItemSelect(int position, TextView view); + +} diff --git a/app/src/main/java/com/chwl/app/ui/invite/InviteImageHelper.kt b/app/src/main/java/com/chwl/app/ui/invite/InviteImageHelper.kt new file mode 100644 index 0000000..be4f005 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/invite/InviteImageHelper.kt @@ -0,0 +1,196 @@ +package com.chwl.app.ui.invite + +import android.Manifest +import android.app.Activity +import android.content.Context +import android.graphics.Bitmap +import android.graphics.drawable.Drawable +import android.net.Uri +import android.os.Build +import android.view.LayoutInflater +import android.view.View +import androidx.core.view.drawToBitmap +import androidx.core.view.isVisible +import androidx.fragment.app.FragmentActivity +import androidx.lifecycle.LifecycleCoroutineScope +import androidx.lifecycle.lifecycleScope +import com.bumptech.glide.request.target.CustomTarget +import com.bumptech.glide.request.transition.Transition +import com.chwl.app.R +import com.chwl.app.common.widget.dialog.DialogManager +import com.chwl.app.databinding.ShareInviteImageLayoutBinding +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil +import com.chwl.library.utils.SingleToastUtil +import com.example.lib_utils.ktx.saveToAlbum +import com.netease.nim.uikit.support.glide.GlideApp +import com.tbruyelle.rxpermissions2.RxPermissions +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.suspendCancellableCoroutine +import kotlinx.coroutines.withContext +import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException +import kotlin.jvm.Throws + +/** + * Created by Max on 2024/3/11 15:57 + * Desc:邀请图片 + **/ +class InviteImageHelper { + + fun saveToAlbum( + activity: FragmentActivity, + rxPermissions: RxPermissions, + data: ShareInviteInfo, + success: (() -> Unit)? = null + ) { + checkStoragePermissions(rxPermissions) { + if (it) { + saveToAlbumImpl(activity, activity.lifecycleScope, data, success) + } else { + SingleToastUtil.showToast(activity.getString(R.string.ask_again)) + } + } + } + + private fun checkStoragePermissions(rxPermissions: RxPermissions, call: (Boolean) -> Unit) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + call.invoke(true) + } else { + val permissions = arrayOf( + Manifest.permission.READ_EXTERNAL_STORAGE, + Manifest.permission.WRITE_EXTERNAL_STORAGE + ) + val d = rxPermissions.request(*permissions)?.subscribe({ + if (it) { + call.invoke(true) + } else { + call.invoke(false) + } + }, { + it.printStackTrace() + }) + } + } + + private fun saveToAlbumImpl( + context: Activity, + lifecycleCoroutineScope: LifecycleCoroutineScope, + data: ShareInviteInfo, + success: (() -> Unit)? = null + ) { + lifecycleCoroutineScope.launch { + val dialogManager = DialogManager(context) + dialogManager.showProgressDialog(context, false) + try { + val result = saveToAlbum(context, data) + if (result) { + SingleToastUtil.showToast(R.string.community_photo_bigphotoactivity_05) + success?.invoke() + } else { + SingleToastUtil.showToast(R.string.community_photo_bigphotoactivity_06) + } + } catch (e: Exception) { + e.printStackTrace() + SingleToastUtil.showToast(e.message) + } finally { + dialogManager.dismissDialog() + } + } + } + + @Throws + suspend fun saveToAlbum(context: Context, data: ShareInviteInfo): Boolean { + val bitmap = generateBitmap(context, data) + return saveToAlbum(context, bitmap) + } + + @Throws + suspend fun generateBitmap(context: Context, data: ShareInviteInfo): Bitmap { + val qrcodeUrl = data.qrCodeUrl + if (qrcodeUrl.isNullOrEmpty()) { + throw IllegalArgumentException(context.getString(R.string.utils_net_beanobserver_05)) + } + val bitmap: Bitmap + withContext(Dispatchers.IO) { + val qrCode = loadQrcode(context, qrcodeUrl) + data.qrcodeDrawable = qrCode + val binding = createView(context) + withContext(Dispatchers.Main) { + bindView(binding, data) + } + bitmap = viewToBitmap(binding.root, UIUtil.dip2px(context, 375.0)) + } + return bitmap + } + + suspend fun saveToAlbum(context: Context, bitmap: Bitmap): Boolean { + val uri: Uri? + withContext(Dispatchers.IO) { + val fileName = "piko_invite_${System.currentTimeMillis()}.jpg" + uri = bitmap.saveToAlbum( + context = context, + fileName = fileName, + relativePath = null, + quality = 90 + ) + } + return uri != null + } + + private fun bindView( + binding: ShareInviteImageLayoutBinding, + data: ShareInviteInfo + ) { + binding.ivQrcode.setImageDrawable(data.qrcodeDrawable) + if (data.text.isNullOrEmpty()) { + binding.tvQrcodeTips.isVisible = false + } else { + binding.tvQrcodeTips.isVisible = true + binding.tvQrcodeTips.text = data.text + } + binding.tvCode.text = + binding.tvCode.context.getString(R.string.invite_code) + data.invitationCode + } + + private suspend fun loadQrcode(context: Context, url: String): Drawable? { + return suspendCancellableCoroutine { + val target = GlideApp.with(context.applicationContext).load(url) + .into(object : CustomTarget() { + override fun onResourceReady( + resource: Drawable, + transition: Transition? + ) { + it.resume(resource) + } + + override fun onLoadCleared(placeholder: Drawable?) { + } + + override fun onLoadFailed(errorDrawable: Drawable?) { + super.onLoadFailed(errorDrawable) + it.resumeWithException(Exception(context.getString(R.string.utils_net_beanobserver_03))) + } + }) + it.invokeOnCancellation { + it?.printStackTrace() + GlideApp.with(context.applicationContext).clear(target) + } + } + } + + private fun createView(context: Context): ShareInviteImageLayoutBinding { + return ShareInviteImageLayoutBinding.inflate(LayoutInflater.from(context)) + } + + private fun viewToBitmap(view: View, width: Int): Bitmap { + val widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY) + val heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED) + view.measure(widthMeasureSpec, heightMeasureSpec) + val measureWidth = view.measuredWidth + val measureHeight = view.measuredHeight + view.layout(0, 0, measureWidth, measureHeight) + return view.drawToBitmap() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/invite/ShareInviteDialog.kt b/app/src/main/java/com/chwl/app/ui/invite/ShareInviteDialog.kt new file mode 100644 index 0000000..f2dae6e --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/invite/ShareInviteDialog.kt @@ -0,0 +1,81 @@ +package com.chwl.app.ui.invite + +import android.content.ClipData +import android.content.ClipboardManager +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.chwl.app.R +import com.chwl.app.databinding.ShareInviteDialogBinding +import com.chwl.library.utils.SingleToastUtil +import com.example.lib_utils.ktx.singleClick +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import com.tbruyelle.rxpermissions2.RxPermissions + +/** + * Created by Max on 2024/3/11 15:29 + * Desc:分享邀请 + **/ +class ShareInviteDialog(val data: ShareInviteInfo) : BottomSheetDialogFragment() { + private var binding: ShareInviteDialogBinding? = null + + private var rxPermissions: RxPermissions? = null + + private val inviteImageHelper = InviteImageHelper() + + override fun onAttach(context: Context) { + super.onAttach(context) + rxPermissions = RxPermissions(this) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + initEvent() + } + + private fun initEvent() { + binding?.let { binding -> + binding.tvCancel.singleClick { + dismissAllowingStateLoss() + } + binding.tvSaveToAlbum.singleClick { + rxPermissions?.let { + inviteImageHelper.saveToAlbum(requireActivity(), it, data) { + dismissAllowingStateLoss() + } + } + } + binding.tvShareLink.singleClick { + copyLink(data.toUrl ?: "") + } + } + } + + private fun copyLink(data: String) { + try { + val cm = + requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager + cm?.setPrimaryClip(ClipData.newPlainText("text", data)) + SingleToastUtil.showToast(R.string.have_copy) + dismissAllowingStateLoss() + } catch (e: Exception) { + e.printStackTrace() + SingleToastUtil.showToast(R.string.retryTips) + } + } + + override fun getTheme(): Int { + return R.style.ErbanBottomSheetDialog + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = ShareInviteDialogBinding.inflate(inflater) + return binding?.root + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/invite/ShareInviteInfo.kt b/app/src/main/java/com/chwl/app/ui/invite/ShareInviteInfo.kt new file mode 100644 index 0000000..17689a5 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/invite/ShareInviteInfo.kt @@ -0,0 +1,31 @@ +package com.chwl.app.ui.invite + +import android.graphics.drawable.Drawable +import androidx.annotation.Keep +import java.io.Serializable + +/** + * Created by Max on 2024/3/11 18:56 + * Desc:分享邀请相关信息 + **/ +@Keep +data class ShareInviteInfo( + // 二维码图片 + val qrCodeUrl: String? = null, + // 邀请码 + val invitationCode: String? = null, + // 页面文案 + val text: String? = null, + // 分享文案 + val shareText: String? = null, + // 分享图片 + val shareImg: String? = null, + // 分享标题 + val shareTitle: String? = null, + // 跳转网页地址 + val toUrl: String? = null, + // (1分享2保存) + val type: Int? = null, + @Transient + var qrcodeDrawable: Drawable? = null +) : Serializable \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/keepalive/OnePiexlActivity.java b/app/src/main/java/com/chwl/app/ui/keepalive/OnePiexlActivity.java new file mode 100644 index 0000000..a3da40b --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/keepalive/OnePiexlActivity.java @@ -0,0 +1,71 @@ +package com.chwl.app.ui.keepalive; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Bundle; +import android.os.PowerManager; +import android.view.Gravity; +import android.view.Window; +import android.view.WindowManager; + +import com.chwl.app.base.BaseActivity; + +/** + * Created by chenran on 2017/11/16. + */ + +public class OnePiexlActivity extends BaseActivity { + + private BroadcastReceiver endReceiver; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + //设置1像素 + Window window = getWindow(); + window.setGravity(Gravity.LEFT | Gravity.TOP); + WindowManager.LayoutParams params = window.getAttributes(); + params.x = 0; + params.y = 0; + params.height = 1; + params.width = 1; + window.setAttributes(params); + + //结束该页面的广播 + endReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + finish(); + } + }; + registerReceiver(endReceiver, new IntentFilter("finish")); + //检查屏幕状态 + checkScreen(); + } + + @Override + protected void onResume() { + super.onResume(); + checkScreen(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + unregisterReceiver(endReceiver); + } + + /** + * 检查屏幕状态 isScreenOn为true 屏幕“亮”结束该Activity + */ + private void checkScreen() { + + PowerManager pm = (PowerManager) OnePiexlActivity.this.getSystemService(Context.POWER_SERVICE); + boolean isScreenOn = pm.isScreenOn(); + if (isScreenOn) { + finish(); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/language/LanguageActivity.kt b/app/src/main/java/com/chwl/app/ui/language/LanguageActivity.kt new file mode 100644 index 0000000..504de32 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/language/LanguageActivity.kt @@ -0,0 +1,84 @@ +package com.chwl.app.ui.language + +import android.content.Intent +import android.view.View +import com.chwl.app.MainActivity +import com.chwl.app.R +import com.chwl.app.application.App +import com.chwl.app.base.BaseBindingActivity +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.base.TitleBar +import com.chwl.app.databinding.LanguageActivityBinding +import com.chwl.library.annatation.ActLayoutRes +import com.chwl.library.language.LanguageHelper +import com.chwl.library.utils.ResUtil +import com.example.lib_utils.AppUtils +import com.example.lib_utils.ktx.getColorById +import com.example.lib_utils.log.ILog +import com.netease.nim.uikit.StatusBarUtil +import java.util.Locale + + +class LanguageActivity : BaseViewBindingActivity(), ILog { + + companion object { + var index = 0 + } + + override fun init() { + val adapter = LanguageAdapter() + val action: TitleBar.Action = + object : TitleBar.TextAction( + context.getString(R.string.save), + context.getColorById(R.color.color_1F1B4F) + ) { + override fun performAction(view: View) { + adapter.getSelectLocale()?.let { + changeLanguage(it) + } + } + } + initTitleBar(ResUtil.getString(R.string.language_settings), action) + adapter.selectLanguage(LanguageHelper.getCurrentLanguage()) + adapter.addData(LanguageItem(Locale.ENGLISH, "English")) + adapter.addData(LanguageItem(Locale.TRADITIONAL_CHINESE, "繁體中文")) + adapter.addData(LanguageItem(Locale("ar"), "بالعربية")) + adapter.addData(LanguageItem(Locale("tr"), "Türkçe")) + binding.recyclerView.adapter = adapter + adapter.setOnItemClickListener { _, view, position -> + adapter.getItem(position)?.locale?.let { + adapter.selectLanguage(it) + } + } + } + + private fun changeLanguage(locale: Locale) { + if (locale.language == LanguageHelper.getCurrentLanguage().language) { + return + } + LanguageHelper.changeLanguageConfig(locale) + LanguageHelper.changeLanguage(App.gContext, locale) + LanguageHelper.changeLanguage(AppUtils.getApp(), locale) + restartMain() + } + + /** + * 让页面重新执行生命周期 + */ + private fun restartMain() { + val intent = Intent() + intent.setClass(context, MainActivity::class.java) + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK) + context.startActivity(intent) + } + + override fun needSteepStateBar(): Boolean { + return true + } + + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/language/LanguageAdapter.kt b/app/src/main/java/com/chwl/app/ui/language/LanguageAdapter.kt new file mode 100644 index 0000000..05775c3 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/language/LanguageAdapter.kt @@ -0,0 +1,41 @@ +package com.chwl.app.ui.language + +import android.view.View +import androidx.core.view.isVisible +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import java.util.Locale + +class LanguageAdapter : BaseQuickAdapter(R.layout.language_item) { + + private var selectLocale: Locale? = null + + override fun convert(helper: BaseViewHolder, item: LanguageItem?) { + helper.setText(R.id.tv_text, item?.name) + convertState(helper, item) + val lineView = helper.getView(R.id.v_line) + lineView.isVisible = helper.absoluteAdapterPosition != itemCount - 1 + } + + override fun convertPayloads( + helper: BaseViewHolder, + item: LanguageItem?, + payloads: MutableList + ) { + super.convertPayloads(helper, item, payloads) + convertState(helper, item) + } + + private fun convertState(helper: BaseViewHolder, item: LanguageItem?) { + val view = helper.getView(R.id.iv_state) + view.isVisible = selectLocale?.language == item?.locale?.language + } + + fun selectLanguage(locale: Locale) { + this.selectLocale = locale + notifyItemRangeChanged(0, itemCount, true) + } + + fun getSelectLocale() = selectLocale +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/language/LanguageItem.kt b/app/src/main/java/com/chwl/app/ui/language/LanguageItem.kt new file mode 100644 index 0000000..a6ade18 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/language/LanguageItem.kt @@ -0,0 +1,7 @@ +package com.chwl.app.ui.language + +import androidx.annotation.Keep +import java.util.Locale + +@Keep +data class LanguageItem(val locale: Locale, val name: String) \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/link/LinkActivity.kt b/app/src/main/java/com/chwl/app/ui/link/LinkActivity.kt new file mode 100644 index 0000000..e919899 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/link/LinkActivity.kt @@ -0,0 +1,56 @@ +package com.chwl.app.ui.link + +import android.net.Uri +import androidx.appcompat.app.AppCompatActivity +import com.alibaba.fastjson2.JSON +import com.chwl.app.application.App +import com.chwl.app.other.activity.SplashActivity +import com.chwl.library.common.util.doLog +import com.example.lib_utils.log.ILog + +class LinkActivity : AppCompatActivity(), ILog { + + private var isProcessed = false + + override fun onStart() { + super.onStart() + logI("onStart()") + handleLink() + } + + private fun handleLink() { + logI("handleLink()") + if (isProcessed) { + return + } + isProcessed = true + // 坑 : %26 = & , 浏览器调起时要转码 encodeURIComponent , adb 调试要 \& 加转义符 + //adb shell am start -a android.intent.action.VIEW -d "molistar://app?shareId=123\&uid=3456\&targetUid=3456\&shareType=1" + //adb shell am start -a android.intent.action.VIEW -d "molistar://app?data=TEST123%26code=123" + //adb shell am start -a android.intent.action.VIEW -d "molistar://app?code=2bK" + val uri = intent.data + if (uri == null) { + finish() + return + } + "深链调起app - > handleLink() uri = $uri intent = ${JSON.toJSONString(intent)}".doLog() + handleLink(uri) + } + + private fun handleLink(uri: Uri) { + logI("handleLink() uri:$uri") + LinkHelper.setLinkIntent(LinkIntent(uri)) + if (isNewStart()) { + logI("handleLink() start SplashActivity") + SplashActivity.start(this) + } else { + logI("handleLink() handle link") + // 目前只对接邀请码功能,无需跳转处理 + } + finish() + } + + private fun isNewStart(): Boolean { + return App.gStack.activityNum == 1 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/link/LinkHelper.kt b/app/src/main/java/com/chwl/app/ui/link/LinkHelper.kt new file mode 100644 index 0000000..4203344 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/link/LinkHelper.kt @@ -0,0 +1,22 @@ +package com.chwl.app.ui.link + +import com.example.lib_utils.log.ILog + +object LinkHelper : ILog { + + private var linkIntent: LinkIntent? = null + + fun getLinkIntent(): LinkIntent? { + return linkIntent + } + + fun clearLinkIntent() { + logD("clearLinkIntent() intent:$linkIntent") + linkIntent = null + } + + fun setLinkIntent(intent: LinkIntent?) { + logD("setLinkIntent() intent:$intent") + linkIntent = intent + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/link/LinkIntent.kt b/app/src/main/java/com/chwl/app/ui/link/LinkIntent.kt new file mode 100644 index 0000000..71b97dc --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/link/LinkIntent.kt @@ -0,0 +1,17 @@ +package com.chwl.app.ui.link + +import android.net.Uri +import androidx.annotation.Keep +import java.io.Serializable + +@Keep +class LinkIntent(var uri: Uri) : Serializable { + + fun safeHandle(block: (Uri) -> Unit) { + try { + block.invoke(uri) + } catch (e: Exception) { + e.printStackTrace() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/list/BaseListAdapter.java b/app/src/main/java/com/chwl/app/ui/list/BaseListAdapter.java new file mode 100644 index 0000000..c054769 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/list/BaseListAdapter.java @@ -0,0 +1,62 @@ +package com.chwl.app.ui.list; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.ViewGroup; + +import androidx.recyclerview.widget.RecyclerView; + +import java.util.List; + +/** + * Created by ${user} on 2017/11/3. + */ +public abstract class BaseListAdapter extends RecyclerView.Adapter { + protected static final int VIEW_TYPE_ONE = 1; + protected static final int VIEW_TYPE_TWO = 2; + protected static final int VIEW_TYPE_THREE = 3; + protected static final int VIEW_TYPE_OTHER = 4; + protected Context mContext; + protected LayoutInflater mLayoutInflater; + private List mDataList; + + public BaseListAdapter(Context context) { + mContext = context; + mLayoutInflater = LayoutInflater.from(context); + } + + public void setDataList(List dataList) { + mDataList = dataList; + notifyDataSetChanged(); + } + + @Override + public int getItemCount() { + return mDataList == null ? 0 : mDataList.size(); + } + + @Override + public int getItemViewType(int position) { + if (position == 0) return VIEW_TYPE_ONE; + else if (position == 1) return VIEW_TYPE_TWO; + else if (position == 2) return VIEW_TYPE_THREE; + else return VIEW_TYPE_OTHER; + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return onCreateHolder(parent, viewType); + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + if (holder == null) + throw new IllegalArgumentException("holder is null !!!"); + onBindHolder((T) holder, position); + } + + public abstract T onCreateHolder(ViewGroup parent, int viewType); + + public abstract void onBindHolder(T holder, int position); + +} diff --git a/app/src/main/java/com/chwl/app/ui/login/AccountValidator.java b/app/src/main/java/com/chwl/app/ui/login/AccountValidator.java new file mode 100644 index 0000000..5c68b89 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/login/AccountValidator.java @@ -0,0 +1,104 @@ +package com.chwl.app.ui.login; + +import android.text.TextUtils; + +import androidx.annotation.NonNull; + +import com.chwl.app.R; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.StringUtils; + +import java.util.regex.Pattern; + +/** + * Created by zhouxiangfeng on 2017/5/3. + */ + +public class AccountValidator { + + + /** + * 正则:手机号(精确) + *

移动:134(0-8)、135、136、137、138、139、147、150、151、152、157、158、159、178、182、183、184、187、188、198

+ *

联通:130、131、132、145、155、156、175、176、185、186、166

+ *

电信:133、153、173、177、180、181、189、199

+ *

全球星:1349

+ *

虚拟运营商:170

+ */ + public static final String REGEX_MOBILE_EXACT = "^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|166|198|199|(147))\\d{8}$"; + + private String errorMessage; + + public AccountValidator() { + } + + public AccountValidator(@NonNull String errorMessage) { + this.errorMessage = errorMessage; + } + + private boolean isValidMobileNumber(String phone) { + return phone.length() > 0 && Pattern.matches(REGEX_MOBILE_EXACT, phone); + } + + private boolean isAllDigits(String str) { + if (StringUtils.isEmpty(str)) return false; + for (int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + if (c < '0' || c > '9') { + return false; + } + } + return true; + } + + public boolean isValid(@NonNull CharSequence text) { + if (!TextUtils.isEmpty(text)) { + char c = text.charAt(0); +// if (!(c == '1')) { +// errorMessage = ResUtil.getString(R.string.ui_login_accountvalidator_01); +// return false; +// } +// if(!MobileNumberUtils.isChinaInternalNumber(text) && !MobileNumberUtils.isChinaMobileNumber(text) && !MobileNumberUtils.isChinaTelecomNumber(text) && !MobileNumberUtils.isChinaUnicomNumber(text)){ +// errorMessage = ResUtil.getString(R.string.ui_login_accountvalidator_02); +// return false; +// } +// if (text.length() == 7) { +// return true; +// } + } else { + errorMessage = ResUtil.getString(R.string.ui_login_accountvalidator_03); + return false; + } + return true; + } + + public boolean isValidToRegister(@NonNull CharSequence text) { + if (!TextUtils.isEmpty(text)) { +// char c = text.charAt(0); +// if (!(c == '1')) { +// errorStr = ResUtil.getString(R.string.ui_login_accountvalidator_04); +// return false; +// } + if (text.length() != 11) { + errorMessage = ResUtil.getString(R.string.ui_login_accountvalidator_05); + return false; + } +// if(!MobileNumberUtils.isChinaInternalNumber(text) && !MobileNumberUtils.isChinaMobileNumber(text) && !MobileNumberUtils.isChinaTelecomNumber(text) && !MobileNumberUtils.isChinaUnicomNumber(text)){ +// errorStr = ResUtil.getString(R.string.ui_login_accountvalidator_06); +// return false; +// } + } else { + errorMessage = ResUtil.getString(R.string.ui_login_accountvalidator_07); + return false; + } + return true; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public String getErrorMessage() { + return errorMessage; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/login/AddUserInfoActivity.java b/app/src/main/java/com/chwl/app/ui/login/AddUserInfoActivity.java new file mode 100644 index 0000000..4a5b98b --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/login/AddUserInfoActivity.java @@ -0,0 +1,63 @@ +package com.chwl.app.ui.login; + +import android.os.Bundle; +import android.view.KeyEvent; + +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentTransaction; + +import com.netease.nim.uikit.StatusBarUtil; +import com.chwl.app.R; +import com.chwl.app.base.BaseActivity; +import com.chwl.app.ui.login.fragment.AddUserInfoFragment; + +/** + * @author zhouxiangfeng + * @date 2017/5/12 + */ + +public class AddUserInfoActivity extends BaseActivity { + + private static final String TAG = "AddUserInfoActivity"; + private AddUserInfoFragment addUserInfoFragment; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_addinfo); + + addUserInfoFragment = new AddUserInfoFragment(); + showAddUserInfo(); + initWhiteTitleBar(""); + } + + public void showAddUserInfo() { + replaceFragment(addUserInfoFragment); + } + + private void replaceFragment(Fragment fragment) { + FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction(); + fragmentTransaction.replace(R.id.fl_fragment_container, fragment, fragment.getClass().getSimpleName()); + fragmentTransaction.commit(); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + moveTaskToBack(true); + return true; + } + return super.onKeyDown(keyCode, event); + } + + @Override + protected boolean needSteepStateBar() { + return true; + } + + @Override + protected void setStatusBar() { + StatusBarUtil.transparencyBar(this); + StatusBarUtil.StatusBarLightMode(this); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/login/AreaCodeActivity.kt b/app/src/main/java/com/chwl/app/ui/login/AreaCodeActivity.kt new file mode 100644 index 0000000..70847d2 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/login/AreaCodeActivity.kt @@ -0,0 +1,100 @@ +package com.chwl.app.ui.login + +import android.app.Activity +import android.content.Intent +import android.view.View +import androidx.lifecycle.lifecycleScope +import com.chad.library.adapter.base.BaseQuickAdapter +import com.netease.nim.uikit.StatusBarUtil +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.databinding.ActivityAreaCodeBinding +import com.chwl.app.ui.widget.SideBarView +import com.example.lib_utils.UiUtils +import com.example.lib_utils.ktx.getColorById +import com.chwl.core.RegionHelper +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +/** + * 区号 + * Created by wushaocheng + * Date: 2022/11/28 + */ +class AreaCodeActivity : BaseViewBindingActivity() { + + private val regionRepository = RegionHelper() + + private val adapter = RegionListAdapter() + + companion object { + const val COUNTRY_NUMBER = "country_number" + + @JvmStatic + fun startForResult(context: Activity, requestCode: Int) { + val intent = Intent(context, AreaCodeActivity::class.java) + context.startActivityForResult( + intent, + requestCode + ) + } + } + + override fun init() { + initTitleBar(getString(R.string.select_area_code)) + initListView() + initSideBar() + loadData() + } + + private fun initSideBar() { + binding.sideBarView.setTextColor(context.getColorById(R.color.color_5caaff)) + binding.sideBarView.setTextSize(UiUtils.dip2px(12f).toFloat()) + binding.sideBarView.setListener(object : SideBarView.Listener { + override fun onSideBarScroll(word: String) { + val index = adapter.data.indexOfFirst { + it.itemType == RegionListAdapter.ITEM_TYPE_GROUP && it.groupName?.toString() == word + } + if (index >= 0) { + binding.mRecyclerView.scrollToPosition(index) + } + } + + override fun onSideBarScrollEnd() { + } + }) + } + + private fun loadData() { + lifecycleScope.launch { + val list = regionRepository.getRegionSelectorList(RegionListAdapter.ITEM_TYPE_GROUP) + withContext(Dispatchers.Main) { + adapter.setNewData(list) + } + } + } + + private fun initListView() { + binding.mRecyclerView.adapter = adapter + //返回国家 + adapter.setOnItemClickListener { adapter: BaseQuickAdapter<*, *>?, view: View?, position: Int -> + val region = this.adapter.getItem(position) + if (region?.code.isNullOrEmpty()) { + return@setOnItemClickListener + } + val intent = Intent() + intent.putExtra(COUNTRY_NUMBER, region?.fullCode) + setResult(RESULT_OK, intent) + finish() + } + } + + override fun needSteepStateBar() = true + + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/login/BindCodeActivity.java b/app/src/main/java/com/chwl/app/ui/login/BindCodeActivity.java new file mode 100644 index 0000000..147e0f3 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/login/BindCodeActivity.java @@ -0,0 +1,205 @@ +package com.chwl.app.ui.login; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.MotionEvent; +import android.view.View; +import android.view.WindowManager; +import android.widget.EditText; +import android.widget.TextView; + +import com.coorchice.library.utils.LogUtils; +import com.trello.rxlifecycle3.android.ActivityEvent; +import com.chwl.app.R; +import com.chwl.app.base.BaseActivity; +import com.chwl.app.ui.login.ui.CodeEditText; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.code.CodeType; +import com.chwl.core.user.UserModel; +import com.chwl.core.user.event.NeedCompleteInfoEvent; +import com.chwl.library.utils.ResUtil; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import io.reactivex.SingleObserver; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; + +/** + * @author zhouxiangfeng + * @date 17/2/26 + */ +public class BindCodeActivity extends BaseActivity { + + private static final String TYPE_SMS = "1"; + private CodeEditText codeEt; + private TextView tvGetCode, tvDesc, tvSecond; + private String mPhone; + private boolean isSuperAdmin = false; + private CodeDownDescTimer timer; + + public static void start(Context context, String phone) { + Intent intent = new Intent(context, BindCodeActivity.class); + intent.putExtra("phone", phone); + context.startActivity(intent); + } + + public static void startForResult(Activity context, String phone, int requestCode) { + Intent intent = new Intent(context, BindCodeActivity.class); + intent.putExtra("phone", phone); + context.startActivityForResult(intent, requestCode); // startActivityForResult会导致singletop,singletask失效 + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + EventBus.getDefault().register(this); + setContentView(R.layout.activity_login_code); + initWhiteTitleBar(""); + onFindViews(); + initData(); + onSetListener(); + getSmsCode(); + } + + @SuppressLint("SetTextI18n") + private void initData() { + mPhone = getIntent().getStringExtra("phone"); + + codeEt.setFocusable(true); + codeEt.setFocusableInTouchMode(true); + codeEt.requestFocus(); + this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE); + + } + + private void onFindViews() { + codeEt = findViewById(R.id.et_code); +// tvGetCode = findViewById(R.id.tv_get_code); + tvDesc = findViewById(R.id.tv_desc); +// tvSecond = findViewById(R.id.tv_second); + } + + private void onSetListener() { + codeEt.setOnTextFinishListener(new CodeEditText.OnTextFinishListener() { + @Override + public void onTextFinish(CharSequence text, int length) { + bindPhone(); + } + }); + + tvGetCode.setOnClickListener(v -> { + getSmsCode(); + }); + + findViewById(R.id.iv_back).setOnClickListener(v -> finish()); + + } + + + @Override + protected void onDestroy() { + codeEt = null; + super.onDestroy(); + stopCountDownTimer(); + EventBus.getDefault().unregister(this); + } + + + @Override + public boolean onTouchEvent(MotionEvent event) { + View view = getCurrentFocus(); + boolean isPressEdit = false; + if (view instanceof EditText) { + if (event.getRawX() >= view.getX() && event.getRawX() <= view.getX() + view.getWidth() && event.getRawY() >= view.getY() && event.getRawY() <= view.getY() + view.getHeight()) { + isPressEdit = true; + } + } + if (!isPressEdit) { + hideIME(); + } + return super.onTouchEvent(event); + + } + + + /** + * 获取验证码 + */ + @SuppressLint("CheckResult") + private void getSmsCode() { + if (TextUtils.isEmpty(mPhone) || mPhone.length() != 11) { + return; + } + AuthModel.get() + .sendLoginCode(mPhone, CodeType.BIND_PHONE) + .observeOn(AndroidSchedulers.mainThread()) + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onSuccess(String s) { + tvDesc.setText(getString(R.string.str_send_code_success) + mPhone); + startCountDownTimer(); + toast(s); + + } + + @Override + public void onError(Throwable e) { + toast(e.getMessage()); + LogUtils.e(ResUtil.getString(R.string.ui_login_bindcodeactivity_01)); + } + }); + } + + + private void startCountDownTimer() { + stopCountDownTimer(); + timer = new CodeDownDescTimer(tvSecond, tvGetCode, 60000, 1000); + timer.start(); + } + + private void stopCountDownTimer() { + if (timer != null) { + timer.cancel(); + timer = null; + } + } + + private void bindPhone() { + getDialogManager().showProgressDialog(BindCodeActivity.this, ResUtil.getString(R.string.ui_login_bindcodeactivity_02)); + AuthModel.get().bindPhone(mPhone, codeEt.getText().toString(),"") + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .doOnSuccess(s -> { + toast(ResUtil.getString(R.string.ui_login_bindcodeactivity_03)); + setResult(RESULT_OK); + }) + .doOnError(throwable -> toast(throwable.getMessage())) + .flatMap(s -> UserModel.get().updateCurrentUserInfo()) + .doOnSuccess(s -> { + setResult(RESULT_OK); + finish(); + }) + .doFinally(() -> getDialogManager().dismissDialog()) + .subscribe(); + } + + //在updateCurrentUserInfo里面会发出NeedCompleteInfoEvent事件 + @Subscribe(threadMode = ThreadMode.MAIN) + public void onNeedCompleteInfo(NeedCompleteInfoEvent event) { + setResult(RESULT_OK); + finish(); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/login/BindEmailActivity.kt b/app/src/main/java/com/chwl/app/ui/login/BindEmailActivity.kt new file mode 100644 index 0000000..b1be49f --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/login/BindEmailActivity.kt @@ -0,0 +1,198 @@ +package com.chwl.app.ui.login + +import android.content.Context +import android.content.Intent +import android.os.CountDownTimer +import android.text.Editable +import android.text.TextUtils +import android.text.TextWatcher +import android.view.MotionEvent +import android.view.View +import android.widget.EditText +import androidx.core.content.ContextCompat +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.databinding.ActivityBindEmailBinding +import com.chwl.core.auth.AuthModel +import com.chwl.core.code.CodeType +import com.chwl.core.user.UserModel +import com.chwl.core.user.bean.UserInfo +import com.chwl.library.utils.NetworkUtils +import com.chwl.library.utils.ResUtil +import com.coorchice.library.utils.LogUtils +import com.netease.nim.uikit.StatusBarUtil +import com.trello.rxlifecycle3.android.ActivityEvent +import io.reactivex.SingleObserver +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable + + +class BindEmailActivity : BaseViewBindingActivity(), + View.OnClickListener, TextWatcher { + + private var cdt: CountDownTimer? = null + + companion object { + private const val TAG = "BindEmailActivity" + const val REQUEST_AREA_CODE = 100 + + @JvmStatic + fun start(context: Context) { + val intent = Intent(context, BindEmailActivity::class.java) + context.startActivity(intent) + } + } + + override fun init() { + initTitleBar(getString(R.string._ver_24_text_bind_email)) + initListener() + } + + private fun initListener() { + binding.tvGetCode.setOnClickListener(this) + binding.btnNext.setOnClickListener(this) + binding.etAccount.addTextChangedListener(this) + binding.etCode.addTextChangedListener(this) + } + + override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { + + } + + override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { + + } + + override fun afterTextChanged(p0: Editable?) { + binding.btnNext.isEnabled = !TextUtils.isEmpty(binding.etAccount.text.toString()) && + !TextUtils.isEmpty(binding.etCode.text.toString()) + } + + override fun onClick(v: View) { + when (v.id) { + R.id.tv_get_code -> { + dialogManager.showProgressDialog(this) + AuthModel.get() + .getEmailCode( + binding.etAccount.text.toString(), + CodeType.BIND_PHONE + ) + .observeOn(AndroidSchedulers.mainThread()) + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .subscribe(object : SingleObserver { + override fun onSubscribe(d: Disposable) {} + override fun onSuccess(tip: String) { + dialogManager.dismissDialog() + startCounter() + toast(tip) + } + + override fun onError(e: Throwable) { + dialogManager.dismissDialog() + toast(e.message) + LogUtils.e(ResUtil.getString(R.string.ui_login_bindcodeactivity_01)) + } + }) + } + R.id.btn_next -> { + if (!NetworkUtils.isNetworkStrictlyAvailable(this)) { + checkNetToast() + return + } + dialogManager.showProgressDialog( + this, + ResUtil.getString(R.string.ui_login_bindcodeactivity_02) + ) + AuthModel.get().bindEmail( + binding.etAccount.text.toString(), + binding.etCode.text.toString() + ) + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .doOnSuccess { s: String? -> + toast(ResUtil.getString(R.string._ver_24_text_bind_email_success)) + setResult(RESULT_OK) + } + .doOnError { throwable: Throwable -> + toast( + throwable.message + ) + } + .flatMap { s: String? -> + UserModel.get().updateCurrentUserInfo() + } + .doOnSuccess { s: UserInfo? -> + setResult(RESULT_OK) + finish() + } + .doFinally { dialogManager.dismissDialog() } + .subscribe() + } + } + } + + private fun startCounter() { + stopCounter() + //开始倒计时 60s 间隔1s + binding.tvGetCode.isEnabled = false + binding.tvGetCode.setTextColor(ContextCompat.getColor(this, R.color.color_AFB1B3)) + cdt = object : CountDownTimer(60 * 1000, 100) { + override fun onTick(text: Long) { + showTextDown(text) + } + + override fun onFinish() { + resetBtn() + } + } + cdt?.start() + } + + private fun showTextDown(text: Long) { + val time = (text / 1000).toString() + "s" + binding.tvGetCode.text = time + } + + private fun stopCounter() { + cdt?.cancel() + cdt = null + } + + private fun resetBtn() { + stopCounter() + binding.tvGetCode.setTextColor(ContextCompat.getColor(this, R.color.color_ff8c03)) + binding.tvGetCode.isEnabled = true + binding.tvGetCode.text = getString(R.string.get) + } + + + + override fun onTouchEvent(event: MotionEvent): Boolean { + val view = currentFocus + var isPressEdit = false + if (view is EditText) { + if (event.rawX >= view.getX() && event.rawX <= view.getX() + view.getWidth() && event.rawY >= view.getY() && event.rawY <= view.getY() + view.getHeight()) { + isPressEdit = true + } + } + if (!isPressEdit) { + hideIME() + } + return super.onTouchEvent(event) + } + + override fun needSteepStateBar(): Boolean { + return true + } + + override fun setStatusBar() { + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } + + override fun onDestroy() { + super.onDestroy() + dialogManager.dismissDialog() + stopCounter() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/login/BindPhoneActivity.kt b/app/src/main/java/com/chwl/app/ui/login/BindPhoneActivity.kt new file mode 100644 index 0000000..2eee501 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/login/BindPhoneActivity.kt @@ -0,0 +1,219 @@ +package com.chwl.app.ui.login + +import android.content.Context +import android.content.Intent +import android.os.CountDownTimer +import android.text.Editable +import android.text.TextUtils +import android.text.TextWatcher +import android.view.MotionEvent +import android.view.View +import android.widget.EditText +import androidx.core.content.ContextCompat +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.databinding.ActivityBindPhoneBinding +import com.chwl.core.RegionHelper +import com.chwl.core.auth.AuthModel +import com.chwl.core.code.CodeType +import com.chwl.core.user.UserModel +import com.chwl.core.user.bean.UserInfo +import com.chwl.library.utils.NetworkUtils +import com.chwl.library.utils.ResUtil +import com.coorchice.library.utils.LogUtils +import com.netease.nim.uikit.StatusBarUtil +import com.trello.rxlifecycle3.android.ActivityEvent +import io.reactivex.SingleObserver +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable + +/** + * 由于所有用户都需要强制绑定手机,所以理论上这里只有MainActivity会调用到这个界面 + * 但是为了以防万一,其它调用绑定手机的地方也改为调用这个页面了 + */ +class BindPhoneActivity : BaseViewBindingActivity(), + View.OnClickListener, TextWatcher { + + private var cdt: CountDownTimer? = null + + companion object { + private const val TAG = "BindPhoneActivity" + const val REQUEST_AREA_CODE = 100 + + @JvmStatic + fun start(context: Context) { + val intent = Intent(context, BindPhoneActivity::class.java) + context.startActivity(intent) + } + } + + override fun init() { + initTitleBar(getString(R.string.text_bind_phone)) + initListener() + RegionHelper().loadRecommendRegion(lifecycle, binding.tvAreaCode) + } + + private fun initListener() { + binding.tvAreaCode.setOnClickListener(this) + binding.tvGetCode.setOnClickListener(this) + binding.btnNext.setOnClickListener(this) + binding.etAccount.addTextChangedListener(this) + binding.etCode.addTextChangedListener(this) + } + + override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { + + } + + override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { + + } + + override fun afterTextChanged(p0: Editable?) { + binding.btnNext.isEnabled = !TextUtils.isEmpty(binding.etAccount.text.toString()) && + !TextUtils.isEmpty(binding.etCode.text.toString()) + } + + override fun onClick(v: View) { + when (v.id) { + R.id.tv_area_code -> { + AreaCodeActivity.startForResult(this, REQUEST_AREA_CODE) + } + R.id.tv_get_code -> { + dialogManager.showProgressDialog(this) + AuthModel.get() + .getSmsCode( + binding.tvAreaCode.text.toString().substring(1), + binding.tvAreaCode.text.toString() + .substring(1) + binding.etAccount.text.toString(), + CodeType.BIND_PHONE + ) + .observeOn(AndroidSchedulers.mainThread()) + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .subscribe(object : SingleObserver { + override fun onSubscribe(d: Disposable) {} + override fun onSuccess(tip: String) { + dialogManager.dismissDialog() + startCounter() + toast(tip) + } + + override fun onError(e: Throwable) { + dialogManager.dismissDialog() + toast(e.message) + LogUtils.e(ResUtil.getString(R.string.ui_login_bindcodeactivity_01)) + } + }) + } + R.id.btn_next -> { + if (!NetworkUtils.isNetworkStrictlyAvailable(this)) { + checkNetToast() + return + } + dialogManager.showProgressDialog( + this, + ResUtil.getString(R.string.ui_login_bindcodeactivity_02) + ) + AuthModel.get().bindPhone( + binding.tvAreaCode.text.toString().substring(1), + binding.tvAreaCode.text.toString() + .substring(1) + binding.etAccount.text.toString(), + binding.etCode.text.toString() + ) + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .doOnSuccess { s: String? -> + toast(ResUtil.getString(R.string.ui_login_bindcodeactivity_03)) + setResult(RESULT_OK) + } + .doOnError { throwable: Throwable -> + toast( + throwable.message + ) + } + .flatMap { s: String? -> + UserModel.get().updateCurrentUserInfo() + } + .doOnSuccess { s: UserInfo? -> + setResult(RESULT_OK) + finish() + } + .doFinally { dialogManager.dismissDialog() } + .subscribe() + } + } + } + + private fun startCounter() { + stopCounter() + //开始倒计时 60s 间隔1s + binding.tvGetCode.isEnabled = false + binding.tvGetCode.setTextColor(ContextCompat.getColor(this, R.color.color_AFB1B3)) + cdt = object : CountDownTimer(60 * 1000, 100) { + override fun onTick(text: Long) { + showTextDown(text) + } + + override fun onFinish() { + resetBtn() + } + } + cdt?.start() + } + + private fun showTextDown(text: Long) { + val time = (text / 1000).toString() + "s" + binding.tvGetCode.text = time + } + + private fun stopCounter() { + cdt?.cancel() + cdt = null + } + + private fun resetBtn() { + stopCounter() + binding.tvGetCode.setTextColor(ContextCompat.getColor(this, R.color.color_ff8c03)) + binding.tvGetCode.isEnabled = true + binding.tvGetCode.text = getString(R.string.get) + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (requestCode == REQUEST_AREA_CODE && resultCode == RESULT_OK) { + val areaCode = data?.getStringExtra(AreaCodeActivity.COUNTRY_NUMBER) + if (areaCode != null) { + binding.tvAreaCode.text = areaCode + } + } + } + + override fun onTouchEvent(event: MotionEvent): Boolean { + val view = currentFocus + var isPressEdit = false + if (view is EditText) { + if (event.rawX >= view.getX() && event.rawX <= view.getX() + view.getWidth() && event.rawY >= view.getY() && event.rawY <= view.getY() + view.getHeight()) { + isPressEdit = true + } + } + if (!isPressEdit) { + hideIME() + } + return super.onTouchEvent(event) + } + + override fun needSteepStateBar(): Boolean { + return true + } + + override fun setStatusBar() { + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } + + override fun onDestroy() { + super.onDestroy() + dialogManager.dismissDialog() + stopCounter() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/login/BindSuccessDialog.java b/app/src/main/java/com/chwl/app/ui/login/BindSuccessDialog.java new file mode 100644 index 0000000..802b6bb --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/login/BindSuccessDialog.java @@ -0,0 +1,68 @@ +package com.chwl.app.ui.login; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.DialogFragment; + +import com.chwl.app.R; +import com.chwl.library.utils.SizeUtils; + +public class BindSuccessDialog extends DialogFragment implements View.OnClickListener { + + private BindSuccessDialogListener mListener; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE); + getDialog().setOnKeyListener(((dialog, keyCode, event) -> true)); + getDialog().setCanceledOnTouchOutside(false); + + View root = inflater.inflate(R.layout.dialog_bind_success, container, false); + root.findViewById(R.id.tv_dialog_close).setOnClickListener(this); + + return root; + } + + public void setmListener(BindSuccessDialogListener mListener) { + this.mListener = mListener; + } + + @Override + public void onResume() { + super.onResume(); + + getDialog().getWindow().setLayout(SizeUtils.dp2px(getContext(), 308), ViewGroup.LayoutParams.WRAP_CONTENT); + getDialog().getWindow().setBackgroundDrawableResource(R.color.transparent); + } + + @Override + public void dismiss() { + super.dismiss(); + + if (mListener != null) + mListener.close(); + + mListener = null; + + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.tv_dialog_close: + dismiss(); + break; + } + } + + public interface BindSuccessDialogListener { + void close(); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/login/CodeDownDescTimer.java b/app/src/main/java/com/chwl/app/ui/login/CodeDownDescTimer.java new file mode 100644 index 0000000..7f39848 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/login/CodeDownDescTimer.java @@ -0,0 +1,49 @@ +package com.chwl.app.ui.login; + +import android.os.CountDownTimer; +import android.view.View; +import android.widget.TextView; + +import com.chwl.app.R; +import com.chwl.library.utils.ResUtil; + + +/** + * Created by zhouxiangfeng on 2017/5/2. + */ + +public class CodeDownDescTimer extends CountDownTimer { + private TextView mTvSecond; + private TextView tvGetCode; + + /** + * @param tv_second 秒数 + * @param tv_get_code 秒数后面的字 + * @param millisInFuture The number of millis in the future from the call + * to {@link #start()} until the countdown is done and {@link #onFinish()} + * is called. + * @param countDownInterval The interval along the way to receiver + * {@link #onTick(long)} callbacks. + */ + public CodeDownDescTimer(TextView tv_second, TextView tv_get_code, long millisInFuture, long countDownInterval) { + super(millisInFuture, countDownInterval); + this.mTvSecond = tv_second; + this.tvGetCode = tv_get_code; + } + + @Override + public void onTick(long millisUntilFinished) { + mTvSecond.setVisibility(View.VISIBLE); + mTvSecond.setText(millisUntilFinished / 1000 + "s"); //设置倒计时时间 + tvGetCode.setClickable(false); //设置不可点击 + tvGetCode.setText(ResUtil.getString(R.string.ui_login_codedowndesctimer_01)); + } + + @Override + public void onFinish() { + mTvSecond.setVisibility(View.GONE); + tvGetCode.setText(ResUtil.getString(R.string.ui_login_codedowndesctimer_02)); + tvGetCode.setClickable(true);//重新获得点击 + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/login/CodeDownTimer.java b/app/src/main/java/com/chwl/app/ui/login/CodeDownTimer.java new file mode 100644 index 0000000..1d58c24 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/login/CodeDownTimer.java @@ -0,0 +1,69 @@ +package com.chwl.app.ui.login; + +import android.graphics.Color; +import android.os.CountDownTimer; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.style.ForegroundColorSpan; +import android.widget.TextView; + +import com.chwl.app.R; +import com.chwl.library.utils.ResUtil; + + +/** + * Created by zhouxiangfeng on 2017/5/2. + */ + +public class CodeDownTimer extends CountDownTimer { + private TextView mTextView; + + /** + * @param textView The TextView + * @param millisInFuture The number of millis in the future from the call + * to {@link #start()} until the countdown is done and {@link #onFinish()} + * is called. + * @param countDownInterval The interval along the way to receiver + * {@link #onTick(long)} callbacks. + */ + public CodeDownTimer(TextView textView, long millisInFuture, long countDownInterval) { + super(millisInFuture, countDownInterval); + this.mTextView = textView; + } + + @Override + public void onTick(long millisUntilFinished) { + mTextView.setClickable(false); //设置不可点击 + mTextView.setText(millisUntilFinished / 1000 + ResUtil.getString(R.string.ui_login_codedowntimer_01)); //设置倒计时时间 + mTextView.setTextColor(mTextView.getResources().getColor(R.color.color_FF3852)); //设置按钮为灰色,这时是不能点击的 + + /** + * 超链接 URLSpan + * 文字背景颜色 BackgroundColorSpan + * 文字颜色 ForegroundColorSpan + * 字体大小 AbsoluteSizeSpan + * 粗体、斜体 StyleSpan + * 删除线 StrikethroughSpan + * 下划线 UnderlineSpan + * 图片 ImageSpan + * http://blog.csdn.net/ah200614435/article/details/7914459 + */ + SpannableString spannableString = new SpannableString(mTextView.getText().toString()); //获取按钮上的文字 + ForegroundColorSpan span = new ForegroundColorSpan(Color.RED); + /** + * public void setSpan(Object what, int start, int end, int flags) { + * 主要是start跟end,start是起始位置,无论中英文,都算一个。 + * 从0开始计算起。end是结束位置,所以处理的文字,包含开始位置,但不包含结束位置。 + */ + spannableString.setSpan(span, 0, 2, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);//将倒计时的时间设置为红色 + mTextView.setText(spannableString); + } + + @Override + public void onFinish() { + mTextView.setText(ResUtil.getString(R.string.ui_login_codedowntimer_02)); + mTextView.setClickable(true);//重新获得点击 + mTextView.setTextColor(mTextView.getResources().getColor(R.color.appColor)); //还原背景色 + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/login/LoginCodeActivity.kt b/app/src/main/java/com/chwl/app/ui/login/LoginCodeActivity.kt new file mode 100644 index 0000000..7fede4e --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/login/LoginCodeActivity.kt @@ -0,0 +1,273 @@ +package com.chwl.app.ui.login + +import android.annotation.SuppressLint +import android.app.Activity +import android.content.Context +import android.content.Intent +import android.os.CountDownTimer +import android.text.Editable +import android.text.TextWatcher +import android.view.MotionEvent +import android.widget.EditText +import androidx.core.content.ContextCompat +import com.chwl.app.MainActivity +import com.chwl.app.NimMiddleActivity +import com.chwl.app.R +import com.chwl.app.application.IReportConstants +import com.chwl.app.application.ReportManager +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.databinding.ActivityLoginCodeBinding +import com.chwl.app.ui.login.helper.LogoutHelper +import com.chwl.core.DemoCache +import com.chwl.core.auth.AuthModel +import com.chwl.core.auth.event.LoginEvent +import com.chwl.core.code.CodeType +import com.chwl.library.utils.ResUtil +import com.coorchice.library.utils.LogUtils +import com.netease.nim.uikit.StatusBarUtil +import com.trello.rxlifecycle3.android.ActivityEvent +import io.reactivex.SingleObserver +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode + +/** + * 验证码页面 + * Created by wushaocheng + * Date: 2022/11/28 + */ +class LoginCodeActivity : BaseViewBindingActivity() { + + private var mPhone: String? = null + private var mAreaCode: String? = null + private var cdt: CountDownTimer? = null + + companion object { + fun start(context: Context, phone: String?, areaCode: String?) { + val intent = Intent(context, LoginCodeActivity::class.java) + intent.putExtra("phone", phone) + intent.putExtra("areaCode", areaCode) + context.startActivity(intent) + } + + fun startForResult(context: Activity, requestCode: Int) { + val intent = Intent(context, LoginCodeActivity::class.java) + context.startActivityForResult( + intent, + requestCode + ) // startActivityForResult会导致singletop,singletask失效 + } + } + + override fun init() { + EventBus.getDefault().register(this) + initData() + initListener() + startCounter() + } + + @SuppressLint("SetTextI18n") + private fun initData() { + mPhone = intent.getStringExtra("phone") + mAreaCode = intent.getStringExtra("areaCode") + } + + private fun initListener() { + binding.ivBack.setOnClickListener { + finish() + } + binding.etCode.addTextChangedListener(object : TextWatcher { + override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { + + } + + override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { + + } + + override fun afterTextChanged(p0: Editable?) { + binding.btnNext.isEnabled = p0?.isEmpty() != true + } + + }) + binding.tvRegain.setOnClickListener { getSmsCode() } + binding.btnNext.setOnClickListener { + login() + } + } + + override fun onTouchEvent(event: MotionEvent): Boolean { + val view = currentFocus + var isPressEdit = false + if (view is EditText) { + if (event.rawX >= view.getX() && event.rawX <= view.getX() + view.getWidth() && event.rawY >= view.getY() && event.rawY <= view.getY() + view.getHeight()) { + isPressEdit = true + } + } + if (!isPressEdit) { + hideIME() + } + return super.onTouchEvent(event) + } + + /** + * 获取验证码 + */ + private fun getSmsCode() { + dialogManager.showProgressDialog(this) + AuthModel.get() + .getSmsCode(mAreaCode, mPhone, CodeType.REGISTER) + .observeOn(AndroidSchedulers.mainThread()) + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .subscribe(object : SingleObserver { + override fun onSubscribe(d: Disposable) {} + + override fun onSuccess(tip: String) { + dialogManager.dismissDialog() + startCounter() + toast(tip) + } + + override fun onError(e: Throwable) { + dialogManager.dismissDialog() + toast(e.message ?: ResUtil.getString(R.string.get_code_failed)) + LogUtils.e(e.message ?: "獲取驗證碼失敗") + } + + }) + } + + private fun startCounter() { + stopCounter() + //开始倒计时 60s 间隔1s + binding.tvRegain.isEnabled = false + binding.tvRegain.setTextColor(ContextCompat.getColor(this, R.color.color_9168FA)) + cdt = object : CountDownTimer(60 * 1000, 100) { + override fun onTick(text: Long) { + showTextDown(text) + } + + override fun onFinish() { + resetBtn() + } + } + cdt?.start() + } + + private fun showTextDown(text: Long) { + val time = (text / 1000).toString() + "s" + binding.tvRegain.text = time + } + + private fun stopCounter() { + cdt?.cancel() + cdt = null + } + + private fun resetBtn() { + stopCounter() + binding.tvRegain.setTextColor(ContextCompat.getColor(this, R.color.text_title_color)) + binding.tvRegain.isEnabled = true + binding.tvRegain.text = getString(R.string.text_login_code_regain) + } + + private fun login() { + //发起登录 + ReportManager.get().reportEvent( + IReportConstants.LOGIN_REQUEST, mapOf( + Pair(IReportConstants.MODULE, IReportConstants.MOLISTAR_LOGIN), + Pair(IReportConstants.LOGIN_TYPE, IReportConstants.FOUR) + ) + ) + val smsCode = binding.etCode.text.toString() + dialogManager.showProgressDialog( + this, + ResUtil.getString(R.string.ui_login_logincodeactivity_02) + ) + AuthModel.get().login( + mAreaCode, + mPhone, + "", + "", + smsCode, + "", + "", + AuthModel.PASSWORD + ) + .subscribe(object : SingleObserver { + override fun onSubscribe(d: Disposable) { + mCompositeDisposable.add(d) + } + + override fun onSuccess(t: String) { + reportLoginResult(IReportConstants.ONE, "") + DemoCache.saveBoundAuthCode(true) + dialogManager.dismissDialog() +// val map = HashMap(2) +// map[FirebaseAnalytics.Param.METHOD] = getString(R.string.login_phone_code) +// ReportManager.get().reportEvent(FirebaseAnalytics.Event.LOGIN, map) +// ReportManager.get().reportAdjustEvent(IReportConstants.ADJUST_LOGIN) + stopCounter() + } + + override fun onError(e: Throwable) { + reportLoginResult( + IReportConstants.ZERO, + e.message.toString() + ) + dialogManager.dismissDialog() + dealWithLoginError(e) + } + }) + } + + /** + * 上报登录结果 + * @param result + * @param failDetail + */ + private fun reportLoginResult(result: Int, failDetail: String) { + val map = HashMap(6) + map[IReportConstants.LOGIN_TYPE] = IReportConstants.FOUR + map[IReportConstants.MODULE] = IReportConstants.MOLISTAR_LOGIN + map[IReportConstants.RESULT] = result + if (result == IReportConstants.ZERO) { + map[IReportConstants.FAIL_DETAIL] = failDetail + } + ReportManager.get().reportEvent(IReportConstants.LOGIN_RESULT, map) + } + + fun dealWithLoginError(e: Throwable?) { + LogoutHelper.dealWithLoginError(this, e) + } + + /** + * 注册成功后发送过来的事件 + */ + @Subscribe(threadMode = ThreadMode.MAIN) + fun onLoginEvent(event: LoginEvent?) { + dialogManager.dismissDialog() + NimMiddleActivity.delayOpenCommunity = false + MainActivity.start(this) + finish() + } + + override fun needSteepStateBar(): Boolean { + return true + } + + override fun setStatusBar() { + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } + + override fun onDestroy() { + super.onDestroy() + dialogManager.dismissDialog() + stopCounter() + EventBus.getDefault().unregister(this) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/login/LoginPasswordActivity.java b/app/src/main/java/com/chwl/app/ui/login/LoginPasswordActivity.java new file mode 100644 index 0000000..613467d --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/login/LoginPasswordActivity.java @@ -0,0 +1,756 @@ +package com.chwl.app.ui.login; + +import android.content.Context; +import android.content.Intent; +import android.graphics.Color; +import android.os.CountDownTimer; +import android.text.Editable; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.TextWatcher; +import android.text.method.LinkMovementMethod; +import android.text.style.ForegroundColorSpan; +import android.view.KeyEvent; +import android.view.View; +import android.widget.TextView; + +import androidx.activity.result.ActivityResult; +import androidx.activity.result.ActivityResultCallback; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; + +import com.chwl.app.BuildConfig; +import com.chwl.app.MainActivity; +import com.chwl.app.NimMiddleActivity; +import com.chwl.app.R; +import com.chwl.app.application.IReportConstants; +import com.chwl.app.application.ReportManager; +import com.chwl.app.base.BaseViewBindingActivity; +import com.chwl.app.common.widget.OriginalDrawStatusClickSpan; +import com.chwl.app.databinding.ActivityLoginPasswordBinding; +import com.chwl.app.ui.feedback.FeedbackActivity; +import com.chwl.app.ui.login.helper.LogoutHelper; +import com.chwl.app.ui.setting.LabActivity; +import com.chwl.app.ui.setting.ResetPasswordActivity; +import com.chwl.app.ui.webview.CommonWebViewActivity; +import com.chwl.app.utils.KeyBoardUtils; +import com.chwl.core.DemoCache; +import com.chwl.core.RegionHelper; +import com.chwl.core.UriProvider; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.auth.event.LoginEvent; +import com.chwl.core.code.CodeType; +import com.chwl.core.initial.InitialModel; +import com.chwl.core.initial.bean.InitInfo; +import com.chwl.core.utils.myutil.MyUtil; +import com.chwl.library.common.SpConstants; +import com.chwl.library.common.util.OtherExtKt; +import com.chwl.library.common.util.SPUtils; +import com.chwl.library.utils.TextWatcherWrapper; +import com.example.lib_utils.ktx.ResourcesKtxKt; +import com.example.module_base.support.login.ILoginService; +import com.netease.nim.uikit.StatusBarUtil; +import com.trello.rxlifecycle3.android.ActivityEvent; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.lang.ref.WeakReference; +import java.util.HashMap; + +import io.reactivex.SingleObserver; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; + + +public class LoginPasswordActivity extends BaseViewBindingActivity { + + private static final String NEED_CHECKED_PROTOCOL = "need_checked_protocol"; + + private int mLoginType = -1; + private final int TYPE_EMAIL = 1; + private final int TYPE_ID = 2; + private final int TYPE_PHONE = 3; + private final int TYPE_GOOGLE = 4; + + private CountDownTimer cdt = null; + + private final ActivityResultLauncher mCodeResult = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback() { + @Override + public void onActivityResult(ActivityResult ar) { + if (ar != null) { + boolean isVerify = ar.getResultCode() == RESULT_OK; + if (isVerify) { + switch (mLoginType) { + case TYPE_EMAIL: + getEmailCode(); + break; + case TYPE_PHONE: + getPhoneCode(); + break; + } + } + } + } + }); + + private final TextWatcher textWatcher = new TextWatcherWrapper() { + @Override + public void afterTextChanged(Editable s) { + checkInput(); + } + }; + + + public static void start(Context context) { + Intent intent = new Intent(context, LoginPasswordActivity.class); + context.startActivity(intent); + } + + + @Override + public void init() { + EventBus.getDefault().register(this); + initView(); + weakReference = new WeakReference<>(context); + new RegionHelper().loadRecommendRegion(getLifecycle(), binding.etPhoneAreaCode); + } + + private void initView() { + + setProtocol(); + + OtherExtKt.setRL(binding.bgInput); + + binding.etEmail.addTextChangedListener(textWatcher); + binding.etEmailCode.addTextChangedListener(textWatcher); + binding.etAccount.addTextChangedListener(textWatcher); + binding.etAccountPassword.getEditText().addTextChangedListener(textWatcher); + binding.etPhone.addTextChangedListener(textWatcher); + binding.etPhoneCode.addTextChangedListener(textWatcher); + + binding.btnForgetPassword.setOnClickListener(v -> { + ResetPasswordActivity.start(context, ResetPasswordActivity.FROM_NOT_LOGIN); + }); + + binding.feedback.setOnClickListener(v -> { + startActivity(new Intent(this, FeedbackActivity.class)); + }); + + binding.etPhoneAreaCode.setOnClickListener(v -> { + AreaCodeActivity.startForResult(this, 100); + }); + + //获取手机验证码 + binding.btnPhoneGetCode.setOnClickListener(v -> { + if (MyUtil.INSTANCE.isDoubleClick()) return; + if (!OtherExtKt.hasInput(binding.etPhone)) { + toast(getString(R.string.ui_setting_resetpasswordactivity_04)); + return; + } + InitInfo initInfo = InitialModel.get().getCacheInitInfo(); + if (initInfo != null && initInfo.isCaptchaSwitch()) { + mCodeResult.launch(new Intent(this,LoginVerifyActivity.class)); + }else { + getPhoneCode(); + } + }); + + //邮箱 + binding.btnEmailGetCode.setOnClickListener(v -> { + if (MyUtil.INSTANCE.isDoubleClick()) return; + if (!OtherExtKt.hasInput(binding.etEmail)) { + toast(getString(R.string._ver_24_input_hint_email)); + return; + } + getEmailCode(); + }); + + + + + binding.btnNext.setOnClickListener(v -> login()); + binding.loginGoogle.setOnClickListener(v -> loginByGoogle()); + + binding.loginBack.setOnClickListener(v -> { + OtherExtKt.setVis(binding.enterLayout,true,false); + OtherExtKt.setVis(binding.loginLayout,false,false); + KeyBoardUtils.hideDialogSoftInput(this); + }); + + binding.loginId.setOnClickListener(v -> { + + if (!binding.tvProtocol.isChecked()) { + binding.tvProtocolHint.setVisibility(View.VISIBLE); + return; + } + + mLoginType = TYPE_ID; + OtherExtKt.setVis(binding.enterLayout,false,false); + OtherExtKt.setVis(binding.loginLayout,true,false); + + OtherExtKt.setVis(binding.loginLayoutInAccount,true,false); + OtherExtKt.setVis(binding.loginLayoutInEmail,false,false); + OtherExtKt.setVis(binding.loginLayoutInPhone,false,false); + + }); + binding.loginEmail.setOnClickListener(v -> { + + if (!binding.tvProtocol.isChecked()) { + binding.tvProtocolHint.setVisibility(View.VISIBLE); + return; + } + + mLoginType = TYPE_EMAIL; + OtherExtKt.setVis(binding.enterLayout,false,false); + OtherExtKt.setVis(binding.loginLayout,true,false); + + OtherExtKt.setVis(binding.loginLayoutInAccount,false,false); + OtherExtKt.setVis(binding.loginLayoutInEmail,true,false); + OtherExtKt.setVis(binding.loginLayoutInPhone,false,false); + + }); + binding.loginPhone.setOnClickListener(v -> { + + if (!binding.tvProtocol.isChecked()) { + binding.tvProtocolHint.setVisibility(View.VISIBLE); + return; + } + + mLoginType = TYPE_PHONE; + OtherExtKt.setVis(binding.enterLayout,false,false); + OtherExtKt.setVis(binding.loginLayout,true,false); + + OtherExtKt.setVis(binding.loginLayoutInAccount,false,false); + OtherExtKt.setVis(binding.loginLayoutInEmail,false,false); + OtherExtKt.setVis(binding.loginLayoutInPhone,true,false); + + }); + + + if (BuildConfig.DEBUG) { + findViewById(R.id.iv_logo).setOnClickListener(v -> { + startActivity(new Intent(this, LabActivity.class)); + }); + } + + } + + private void login() { + if (MyUtil.INSTANCE.isDoubleClick()) return; + switch (mLoginType) { + case TYPE_ID: + loginByAccount(); + break; + case TYPE_EMAIL: + loginByEmail(); + break; + case TYPE_PHONE: + loginByPhone(); + break; + case TYPE_GOOGLE: + loginByGoogle(); + break; + } + } + + + + private void loginByAccount() { + if (!binding.tvProtocol.isChecked()) { + binding.tvProtocolHint.setVisibility(View.VISIBLE); + return; + } + getDialogManager().showProgressDialog(this, getString(R.string.login_is_logining)); + AuthModel.get().login( + "", + binding.etAccount.getText().toString().trim(), + "", + binding.etAccountPassword.getText().toString().trim(), + "", + "", + "",AuthModel.PASSWORD) + .subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) { + mCompositeDisposable.add(d); + } + + @Override + public void onSuccess(String result) { + reportLoginResult(IReportConstants.ONE, result); +// HashMap map = new HashMap<>(2); +// map.put(FirebaseAnalytics.Param.METHOD, getString(R.string.login_account)); +// ReportManager.get().reportEvent(FirebaseAnalytics.Event.LOGIN, map); +// ReportManager.get().reportAdjustEvent(IReportConstants.ADJUST_LOGIN); + getDialogManager().dismissDialog(); + SPUtils.putString(SpConstants.LOGIN_TYPE, ""); + } + + @Override + public void onError(Throwable e) { + reportLoginResult(IReportConstants.ZERO, e.getMessage()); + getDialogManager().dismissDialog(); + dealWithLoginError(e); + } + }); + + //发起登录 + HashMap map = new HashMap<>(3); + map.put(IReportConstants.LOGIN_TYPE, IReportConstants.FIVE); + map.put(IReportConstants.MODULE, IReportConstants.MOLISTAR_LOGIN); + ReportManager.get().reportEvent(IReportConstants.LOGIN_REQUEST, map); + + } + + private void loginByEmail() { + + + if (!binding.tvProtocol.isChecked()) { + binding.tvProtocolHint.setVisibility(View.VISIBLE); + return; + } + +// +// //发起登录 +// HashMap map = new HashMap<>(3); +// map.put(IReportConstants.LOGIN_TYPE, IReportConstants.FOUR); +// map.put(IReportConstants.MODULE, IReportConstants.MOLISTAR_LOGIN); +// ReportManager.get().reportEvent(IReportConstants.LOGIN_REQUEST, map); + + String etEmail = binding.etEmail.getText().toString(); + String etEmailCode = binding.etEmailCode.getText().toString(); + + AuthModel.get().login( + "", + "", + etEmail, + "", + etEmailCode, + "", + "", + AuthModel.EMAIL + ) + .subscribe(new SingleObserver<>() { + @Override + public void onSubscribe(Disposable d) { + mCompositeDisposable.add(d); + } + + @Override + public void onSuccess(String s) { + reportLoginResult(IReportConstants.ONE, ""); + DemoCache.saveBoundAuthCode(true); + getDialogManager().dismissDialog(); + stopCounter(); + SPUtils.putString(SpConstants.LOGIN_TYPE, ""); + } + + @Override + public void onError(Throwable e) { + reportLoginResult(IReportConstants.ZERO, e.getMessage()); + getDialogManager().dismissDialog(); + dealWithLoginError(e); + } + }); + } + + private void loginByPhone() { + + if (!binding.tvProtocol.isChecked()) { + binding.tvProtocolHint.setVisibility(View.VISIBLE); + return; + } + //发起登录 + HashMap map = new HashMap<>(3); + map.put(IReportConstants.LOGIN_TYPE, IReportConstants.FOUR); + map.put(IReportConstants.MODULE, IReportConstants.MOLISTAR_LOGIN); + ReportManager.get().reportEvent(IReportConstants.LOGIN_REQUEST, map); + String smsCode = binding.etPhoneCode.getText().toString(); + getDialogManager().showProgressDialog( + this, + getString(R.string.ui_login_logincodeactivity_02) + ); + + String areaCode = binding.etPhoneAreaCode.getText().toString().substring(1); + String phone = binding.etPhoneAreaCode.getText().toString().substring(1) + binding.etPhone.getText().toString(); + + AuthModel.get().login( + areaCode, + phone, + "", + "", + smsCode, + "", + "", + AuthModel.PASSWORD + ) + .subscribe(new SingleObserver<>() { + @Override + public void onSubscribe(Disposable d) { + mCompositeDisposable.add(d); + } + + @Override + public void onSuccess(String s) { + reportLoginResult(IReportConstants.ONE, ""); + DemoCache.saveBoundAuthCode(true); + getDialogManager().dismissDialog(); + stopCounter(); + SPUtils.putString(SpConstants.LOGIN_TYPE, ""); + } + + @Override + public void onError(Throwable e) { + reportLoginResult( + IReportConstants.ZERO, + e.getMessage() + ); + getDialogManager().dismissDialog(); + dealWithLoginError(e); + } + }); + } + + private void loginByGoogle(){ + if (MyUtil.INSTANCE.isDoubleClick()) return; + getDialogManager().showProgressDialog(this); + AuthModel.get().googleLogin(this) + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onSuccess(String result) { + getDialogManager().dismissDialog(); + } + + @Override + public void onError(Throwable e) { + getDialogManager().dismissDialog(); + dealWithLoginError(e); + e.printStackTrace(); + } + }); + } + + //获取邮箱验证码 + private void getEmailCode() { + if (!binding.tvProtocol.isChecked()) { + binding.tvProtocolHint.setVisibility(View.VISIBLE); + return; + } + hideIME(); + getDialogManager().showProgressDialog(this); + + String email = binding.etEmail.getText().toString(); + AuthModel.get() + .getEmailCode( + email, + CodeType.REGISTER + ) + .observeOn(AndroidSchedulers.mainThread()) + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) { + mCompositeDisposable.add(d); + } + + @Override + public void onSuccess(String tip) { + getDialogManager().dismissDialog(); + toast(tip); + startCounter(); + } + + @Override + public void onError(Throwable e) { + getDialogManager().dismissDialog(); + if (e.getMessage() != null) { + toast(e.getMessage()); + } + } + }); + } + + //获取手机验证码 + private void getPhoneCode() { + if (!binding.tvProtocol.isChecked()) { + binding.tvProtocolHint.setVisibility(View.VISIBLE); + return; + } + hideIME(); + getDialogManager().showProgressDialog(this); + + String areaCode = binding.etPhoneAreaCode.getText().toString().substring(1); + String phone = binding.etPhoneAreaCode.getText().toString().substring(1) + binding.etPhone.getText().toString(); + AuthModel.get() + .getSmsCode( + areaCode, + phone, + CodeType.REGISTER + ) + .observeOn(AndroidSchedulers.mainThread()) + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) { + mCompositeDisposable.add(d); + } + + @Override + public void onSuccess(String tip) { + getDialogManager().dismissDialog(); + toast(tip); + startCounter(); + } + + @Override + public void onError(Throwable e) { + getDialogManager().dismissDialog(); + if (e.getMessage() != null) { + toast(e.getMessage()); + } + } + }); + } + + + private TextView getTimeView() { + switch (mLoginType) { + case TYPE_PHONE: + return binding.btnPhoneGetCode; + default: + return binding.btnEmailGetCode; + } + } + + private void startCounter() { + stopCounter(); + resetBtn(); + //开始倒计时 60s 间隔1s + getTimeView().setEnabled(false); + cdt = new CountDownTimer(60 * 1000, 100) { + @Override + public void onTick(long text) { + showTextDown(text); + } + + @Override + public void onFinish() { + resetBtn(); + } + }; + cdt.start(); + } + + + private void showTextDown(Long text) { + String time = (text / 1000) + "s"; + getTimeView().setText(time); + getTimeView().setTextColor(ResourcesKtxKt.getColor(R.color.color_AFB1B3)); + } + + private void resetBtn() { + stopCounter(); + getTimeView().setEnabled(true); + binding.btnPhoneGetCode.setText(getString(R.string.get)); + binding.btnPhoneGetCode.setTextColor(ResourcesKtxKt.getColor(R.color.color_ff8c03)); + + binding.btnEmailGetCode.setText(getString(R.string.get)); + binding.btnEmailGetCode.setTextColor(ResourcesKtxKt.getColor(R.color.color_ff8c03)); + } + + private void stopCounter() { + if (cdt != null) { + cdt.cancel(); + cdt = null; + } + } + + @Override + public void onBackPressed() { + if (binding.loginBack.getVisibility() == View.VISIBLE) { + binding.loginBack.performClick(); + } else { + super.onBackPressed(); + } + } + + private void checkInput() { + boolean enabled = false; + + switch (mLoginType) { + case TYPE_EMAIL: + enabled = OtherExtKt.hasInput(binding.etEmail) && OtherExtKt.hasInput(binding.etEmailCode); + break; + case TYPE_ID: + enabled = OtherExtKt.hasInput(binding.etAccount) && OtherExtKt.hasInput(binding.etAccountPassword.getEditText()); + break; + case TYPE_PHONE: + enabled = OtherExtKt.hasInput(binding.etPhone) && OtherExtKt.hasInput(binding.etPhoneCode) + && binding.etPhoneAreaCode.getText() != null && !binding.etPhoneAreaCode.getText().toString().trim().isEmpty(); + break; + } + + binding.btnNext.setEnabled(enabled); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + ILoginService loginService = AuthModel.get().getGoogleLoginService(); + if (loginService != null) { + loginService.onActivityResult(requestCode, resultCode, data); + } + if (requestCode == 100 && resultCode == RESULT_OK) { + String areaCode = data.getStringExtra(AreaCodeActivity.COUNTRY_NUMBER); + if (areaCode != null) { + binding.etPhoneAreaCode.setText(areaCode); + } + } + } + + @Override + protected void setStatusBar() { + super.setStatusBar(); + StatusBarUtil.transparencyBar(this); + StatusBarUtil.StatusBarLightMode(this); + } + + @Override + protected boolean needSteepStateBar() { + return true; + } + + @Override + protected void onDestroy() { + OtherExtKt.clearSpans(binding.tvProtocol); + super.onDestroy(); + getDialogManager().dismissDialog(); + stopCounter(); + EventBus.getDefault().unregister(this); + } + + + /** + * 上报登录结果 + * + * @param result + * @param failDetail + */ + private void reportLoginResult(int result, String failDetail) { + HashMap map = new HashMap<>(6); + map.put(IReportConstants.LOGIN_TYPE, IReportConstants.FIVE); + map.put(IReportConstants.MODULE, IReportConstants.MOLISTAR_LOGIN); + map.put(IReportConstants.RESULT, result); + if (result == IReportConstants.ZERO) { + map.put(IReportConstants.FAIL_DETAIL, failDetail); + } + ReportManager.get().reportEvent(IReportConstants.LOGIN_RESULT, map); + } + + public void dealWithLoginError(Throwable e) { + LogoutHelper.dealWithLoginError(this, e); + } + + + /** + * 注册成功后发送过来的事件 + */ + @Subscribe(threadMode = ThreadMode.MAIN) + public void onLoginEvent(LoginEvent event) { + OtherExtKt.doLog(" 登录事件 注册成功后发送过来的事件 "); + binding.getRoot().post(() -> { + getDialogManager().dismissDialog(); + NimMiddleActivity.delayOpenCommunity = false; + MainActivity.start(LoginPasswordActivity.this); + finish(); + }); + } + + WeakReference weakReference = new WeakReference<>(context); + protected void setProtocol() { + String privacyAgreementTip = context.getString(R.string.tip_privacy_agreement); + String userAgreementTip = context.getString(R.string.tip_user_agreement); + String privacyAgreementDescTip = context.getString(R.string.text_login_protocol, privacyAgreementTip, userAgreementTip); + SpannableString ss = new SpannableString(privacyAgreementDescTip); + int privacyAgreementTipIndex = privacyAgreementDescTip.indexOf(privacyAgreementTip); + int userAgreementTipIndex = privacyAgreementDescTip.indexOf(userAgreementTip); + ss.setSpan(new ForegroundColorSpan(ContextCompat.getColor(context, R.color.color_1E1E1F)), privacyAgreementTipIndex, privacyAgreementTipIndex + privacyAgreementTip.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + ss.setSpan(new OriginalDrawStatusClickSpan(ContextCompat.getColor(context, R.color.color_1E1E1F)) { + @Override + public void onClick(@NonNull View widget) { + //隐私政策点击 + HashMap map = new HashMap<>(5); + map.put(IReportConstants.CLICK_TYPE, IReportConstants.TWO); + map.put(IReportConstants.MODULE, IReportConstants.MOLISTAR_LOGIN); + map.put(IReportConstants.PAGE, IReportConstants.TWO); + ReportManager.get().reportEvent(IReportConstants.AGREEMENT_CLICK, map); + + if (widget instanceof TextView) ((TextView) widget).setHighlightColor(getResources().getColor(android.R.color.transparent)); + + if (weakReference.get() != null) { + CommonWebViewActivity.start(weakReference.get(), UriProvider.getPrivacyAgreement()); + } + } + }, privacyAgreementTipIndex, privacyAgreementTipIndex + privacyAgreementTip.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + ss.setSpan(new ForegroundColorSpan(ContextCompat.getColor(context, R.color.color_1F1A4E)), userAgreementTipIndex, userAgreementTipIndex + userAgreementTip.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + ss.setSpan(new OriginalDrawStatusClickSpan(ContextCompat.getColor(context, R.color.color_1F1A4E)) { + @Override + public void onClick(@NonNull View widget) { + //用户协议点击 + HashMap map = new HashMap<>(5); + map.put(IReportConstants.CLICK_TYPE, IReportConstants.ONE); + map.put(IReportConstants.MODULE, IReportConstants.MOLISTAR_LOGIN); + map.put(IReportConstants.PAGE, IReportConstants.TWO); + ReportManager.get().reportEvent(IReportConstants.AGREEMENT_CLICK, map); + + if (widget instanceof TextView) ((TextView) widget).setHighlightColor(getResources().getColor(android.R.color.transparent)); + if (weakReference.get() != null) { + CommonWebViewActivity.start(weakReference.get(), UriProvider.getUserProtocolUrl()); + } + } + }, userAgreementTipIndex, userAgreementTipIndex + privacyAgreementTip.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + + binding.tvProtocol.setText(ss); + binding.tvProtocol.setHighlightColor(Color.TRANSPARENT); + binding.tvProtocol.setMovementMethod(new LinkMovementMethod()); + + if (DemoCache.readBoolean(NEED_CHECKED_PROTOCOL, false)) { + binding.tvProtocol.setChecked(true); + } + + binding.tvProtocol.setOnCheckedChangeListener((buttonView, isChecked) -> { + if (isChecked) { + //协议点击同意 + HashMap map = new HashMap<>(5); + map.put(IReportConstants.CLICK_TYPE, IReportConstants.THREE); + map.put(IReportConstants.MODULE, IReportConstants.MOLISTAR_LOGIN); + map.put(IReportConstants.PAGE, IReportConstants.TWO); + ReportManager.get().reportEvent(IReportConstants.AGREEMENT_CLICK, map); + + binding.tvProtocolHint.setVisibility(View.GONE); + DemoCache.saveBoolean(NEED_CHECKED_PROTOCOL, true); + } + }); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + moveTaskToBack(true); + return true; + } + return super.onKeyDown(keyCode, event); + } + + +} diff --git a/app/src/main/java/com/chwl/app/ui/login/LoginPhoneActivity.kt b/app/src/main/java/com/chwl/app/ui/login/LoginPhoneActivity.kt new file mode 100644 index 0000000..36e3a7d --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/login/LoginPhoneActivity.kt @@ -0,0 +1,155 @@ +package com.chwl.app.ui.login + +import android.content.Context +import android.content.Intent +import android.text.TextUtils +import android.view.MotionEvent +import android.view.View +import android.widget.EditText +import com.netease.nim.uikit.StatusBarUtil +import com.trello.rxlifecycle3.android.ActivityEvent +import com.chwl.app.MainActivity +import com.chwl.app.NimMiddleActivity +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.databinding.ActivityLoginPhoneBinding +import com.chwl.core.auth.AuthModel +import com.chwl.core.auth.event.LoginEvent +import com.chwl.core.code.CodeType +import com.chwl.core.RegionHelper +import io.reactivex.SingleObserver +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode + +/** + * 手机号登录页面 + * Created by wushaocheng + * Date: 2022/11/28 + */ +class LoginPhoneActivity : BaseViewBindingActivity(), + View.OnClickListener { + + companion object { + + @JvmStatic + fun start(context: Context) { + val starter = Intent(context, LoginPhoneActivity::class.java) + context.startActivity(starter) + } + } + + override fun init() { + EventBus.getDefault().register(this) + initListener() + RegionHelper().loadRecommendRegion(lifecycle, binding.tvAreaCode) + } + + private fun initListener() { + binding.ivBack.setOnClickListener(this) + binding.tvAreaCode.setOnClickListener(this) + binding.btnNext.setOnClickListener(this) + } + + override fun onClick(view: View?) { + when (view?.id) { + R.id.iv_back -> { + finish() + } + R.id.tvAreaCode -> { + AreaCodeActivity.startForResult(this, BindPhoneActivity.REQUEST_AREA_CODE) + } + R.id.btnNext -> { + if (TextUtils.isEmpty(binding.etAccount.text.toString())) { + toast(getString(R.string.ui_setting_resetpasswordactivity_04)) + return + } + hideIME() + dialogManager.showProgressDialog(this) + val areaCode = binding.tvAreaCode.text.toString().substring(1) + val phone = binding.tvAreaCode.text.toString() + .substring(1) + binding.etAccount.text.toString() + AuthModel.get() + .getSmsCode( + areaCode, + phone, + CodeType.REGISTER + ) + .observeOn(AndroidSchedulers.mainThread()) + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .subscribe(object : SingleObserver { + override fun onSubscribe(d: Disposable) {} + + override fun onSuccess(tip: String) { + dialogManager.dismissDialog() + toast(tip) + LoginCodeActivity.start( + this@LoginPhoneActivity, + phone, + areaCode + ) + } + + override fun onError(e: Throwable) { + dialogManager.dismissDialog() + if(e.message != null) { + toast(e.message) + } + } + + }) + } + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (requestCode == BindPhoneActivity.REQUEST_AREA_CODE && resultCode == RESULT_OK) { + val areaCode = data?.getStringExtra(AreaCodeActivity.COUNTRY_NUMBER) + if (areaCode != null) { + binding.tvAreaCode.text = areaCode + } + } + } + + override fun onTouchEvent(event: MotionEvent): Boolean { + val view = currentFocus + var isPressEdit = false + if (view is EditText) { + if (event.rawX >= view.getX() && event.rawX <= view.getX() + view.getWidth() && event.rawY >= view.getY() && event.rawY <= view.getY() + view.getHeight()) { + isPressEdit = true + } + } + if (!isPressEdit) { + hideIME() + } + return super.onTouchEvent(event) + } + + override fun needSteepStateBar() = true + + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } + + override fun onDestroy() { + super.onDestroy() + dialogManager.dismissDialog() + EventBus.getDefault().unregister(this) + } + + /** + * 注册成功后发送过来的事件 + */ + @Subscribe(threadMode = ThreadMode.MAIN) + fun onLoginEvent(event: LoginEvent?) { + NimMiddleActivity.delayOpenCommunity = false + MainActivity.start(this) + finish() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/login/LoginVerifyActivity.java b/app/src/main/java/com/chwl/app/ui/login/LoginVerifyActivity.java new file mode 100644 index 0000000..4cc68c1 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/login/LoginVerifyActivity.java @@ -0,0 +1,433 @@ +package com.chwl.app.ui.login; + +import android.annotation.SuppressLint; +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.ActivityNotFoundException; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.graphics.Bitmap; +import android.net.Uri; +import android.net.http.SslError; +import android.os.Build; +import android.os.Bundle; +import android.text.TextUtils; +import android.webkit.SslErrorHandler; +import android.webkit.ValueCallback; +import android.webkit.WebBackForwardList; +import android.webkit.WebChromeClient; +import android.webkit.WebSettings; +import android.webkit.WebView; +import android.webkit.WebViewClient; + +import androidx.annotation.LayoutRes; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AlertDialog; + +import com.chwl.app.R; +import com.chwl.app.application.App; +import com.chwl.app.base.BaseActivity; +import com.chwl.app.ui.webview.JSInterface; +import com.chwl.app.ui.webview.ShareH5Event; +import com.chwl.app.ui.webview.event.ShowNavEvent; +import com.chwl.app.ui.webview.event.TaroPayResultEvent; +import com.chwl.app.utils.WebViewUtils; +import com.chwl.core.Constants; +import com.chwl.core.UriProvider; +import com.chwl.core.certification.event.CertificationResultEvent; +import com.chwl.core.web.bean.WebJsBeanInfo; +import com.chwl.core.web.event.WebViewRefreshEvent; +import com.chwl.library.rxbus.RxBus; +import com.chwl.library.utils.ResUtil; +import com.google.gson.Gson; +import com.netease.nim.uikit.StatusBarUtil; +import com.netease.nim.uikit.common.util.log.LogUtil; +import com.netease.nim.uikit.common.util.string.StringUtil; +import com.orhanobut.logger.Logger; +import com.trello.rxlifecycle3.android.ActivityEvent; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.HashMap; +import java.util.Map; + +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; + + +/** + * @author Administrator + */ +public class LoginVerifyActivity extends BaseActivity { + + protected WebView webView; + private LoginVerifyActivity mActivity; + private WebChromeClient wvcc; + + private WebJsBeanInfo mWebJsBeanInfo; + private String url; + private String from; + private String targetUrl; + + private ValueCallback mUploadMessage; + private ValueCallback mUploadMessage5; + public static final int FILECHOOSER_RESULTCODE = 5173; + public static final int FILECHOOSER_RESULTCODE_FOR_ANDROID_5 = 5174; + + private static final String POSITION = "position"; + private int mPosition; + + private JSInterface jsInterface; + + public static void start(Context context, String url) { + Intent intent = new Intent(context, LoginVerifyActivity.class); + intent.putExtra("url", url); + context.startActivity(intent); + } + + /** + * 排行榜专用 + */ + public static void start(Context context, String url, int position) { + Intent intent = new Intent(context, LoginVerifyActivity.class); + intent.putExtra("url", url); + intent.putExtra(POSITION, position); + context.startActivity(intent); + } + + /** + * webView 某些h5 功能页面 需要在h5 使用结束后做一些操作 + * + * @param context + * @param url + * @param callBack 回调 + */ + public static void start(Context context, String url, WebViewCallBack callBack) { + Intent intent = new Intent(context, LoginVerifyActivity.class); + intent.putExtra("url", url); + context.startActivity(intent); + webViewCallBack = callBack; + } + + @LayoutRes + protected int getLayoutId() { + return R.layout.activity_login_verify; + } + + @SuppressLint("CheckResult") + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + this.initBefore(savedInstanceState); + setContentView(getLayoutId()); + Intent intent = getIntent(); + url = UriProvider.getHumanMachineVerification(); + from = intent.getStringExtra("from"); + mPosition = intent.getIntExtra(POSITION, 0) + 1; + mActivity = this; + initView(); + initData(); + setListener(); + showWebView(url); + RxBus.get().toFlowable(ShareH5Event.class) + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .subscribeOn(Schedulers.newThread()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(shareH5Event -> { + WebJsBeanInfo webJsBeanInfo = shareH5Event.getWebJsBeanInfo(); + if (webJsBeanInfo != null) { + if (App.isDebug()) { + toast("WebJsBeanInfo->" + new Gson().toJson(webJsBeanInfo)); + } + mWebJsBeanInfo = webJsBeanInfo; + showMenu(webJsBeanInfo.getData()); + } + }); + EventBus.getDefault().register(this); + + + + } + + /** + * 该方法是在onCreate()方法里执行,在setContentView()方法被调用之前触发,可用于处理解析Activity#getIntent()中的数据时的场景 + */ + protected void initBefore(@Nullable Bundle savedInstanceState) { + + } + + + private void setListener() { + + } + + @SuppressLint("SetJavaScriptEnabled") + private void initData() { + webView.getSettings().setJavaScriptEnabled(true); + webView.getSettings().setUseWideViewPort(true); + webView.getSettings().setLoadWithOverviewMode(true); + webView.getSettings().setDomStorageEnabled(true); + // 设置 WebView 可以在 HTTPS 通道上加载 HTTP 资源,Android 4.4 后的暗坑 + // 因为 Android 4.4 后默认不允许在 HTTPS 通道上加载 HTTP 资源 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + webView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE); + } + webView.getSettings().setTextZoom(100); + jsInterface = new JSInterface(webView, this); + jsInterface.setPosition(mPosition); + jsInterface.setVerifyActivity(this); + webView.addJavascriptInterface(jsInterface, "androidJsObj"); + webView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE); + webView.setWebViewClient(new WebViewClient() { + + + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + Logger.e("shouldOverrideUrlLoading--------" + url); + LogUtil.e("shouldOverrideUrlLoading" + url); + targetUrl = url; + + if (url.contains("tel:")) { + //删除直接拨打电话的功能 + return true; + } + // ------- 处理结束 ------- + + if (!(url.startsWith("http") || url.startsWith("https"))) { + return true; + } + + view.loadUrl(url); + return true; + } + + @Override + public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { + // super.onReceivedSslError(view, handler, error); + AlertDialog.Builder builder = new AlertDialog.Builder(view.getContext()); + builder.setMessage(ResUtil.getString(R.string.ui_webview_commonwebviewactivity_07)); + builder.setPositiveButton(ResUtil.getString(R.string.ui_webview_commonwebviewactivity_08), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + handler.proceed();// 接受https所有网站的证书 + } + }); + + builder.setNegativeButton(ResUtil.getString(R.string.ui_webview_commonwebviewactivity_09), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + handler.cancel(); + } + }); + + AlertDialog dialog = builder.create(); + dialog.show(); + } + + @Override + public void onPageFinished(WebView view, String url) { + Logger.e("onPageFinished--------" + url); + super.onPageFinished(view, url); + } + + @Override + public void onPageStarted(WebView view, String url, Bitmap favicon) { + super.onPageStarted(view, url, favicon); + } + }); + //获取webviewtitle作为titlebar的title + wvcc = new WebChromeClient() { + @Override + public void onProgressChanged(WebView view, int newProgress) { + super.onProgressChanged(view, newProgress); + } + + @Override + public void onReceivedTitle(WebView view, String title) { + super.onReceivedTitle(view, title); + } + + // For Android >= 4.1 + public void openFileChooser(ValueCallback uploadMsg, + String acceptType, String capture) { + mUploadMessage = uploadMsg; + Intent i = new Intent(Intent.ACTION_GET_CONTENT); + i.addCategory(Intent.CATEGORY_OPENABLE); + i.setType("*/*"); + startActivityForResult(Intent.createChooser(i, "File Browser"), + FILECHOOSER_RESULTCODE); + } + + //xxx 接收 webView 的 標籤的 文件選擇 + // For Lollipop 5.0+ Devices + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + public boolean onShowFileChooser(WebView mWebView, + ValueCallback filePathCallback, + FileChooserParams fileChooserParams) { + if (mUploadMessage5 != null) { + mUploadMessage5.onReceiveValue(null); + mUploadMessage5 = null; + } + mUploadMessage5 = filePathCallback; + Intent intent = fileChooserParams.createIntent(); + try { + startActivityForResult(intent, + FILECHOOSER_RESULTCODE_FOR_ANDROID_5); + } catch (ActivityNotFoundException e) { + mUploadMessage5 = null; + return false; + } + return true; + } + + }; + // 设置setWebChromeClient对象 + webView.setWebChromeClient(wvcc); + // 设置Webview的user-agent + webView.getSettings().setUserAgentString(webView.getSettings().getUserAgentString() + " molistarAppAndroid"); + } + + private void onGotoAppFinish(WebView view) { + // 跳转成功或失败与否,都重新回到最后打开的App内非第三方网页 + view.post(() -> { + if (from != null && from.equals("xplan_flutter")) { + finish(); + return; + } + WebBackForwardList list = view.copyBackForwardList(); + final int length = list.getSize(); + int steps = 1; + for (int i = length - 1; i >= 0; i--) { + String lastUrl = list.getItemAtIndex(i).getUrl(); + steps--; + if (lastUrl != null && lastUrl.startsWith(UriProvider.JAVA_WEB_URL)) { + view.goBackOrForward(steps); + break; + } + } + }); + } + + @SuppressLint("NewApi") + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent intent) { + super.onActivityResult(requestCode, resultCode, intent); + if (requestCode == FILECHOOSER_RESULTCODE) { + if (null == mUploadMessage) { + return; + } + Uri result = intent == null || resultCode != Activity.RESULT_OK ? null + : intent.getData(); + mUploadMessage.onReceiveValue(result); + mUploadMessage = null; + } else if (requestCode == FILECHOOSER_RESULTCODE_FOR_ANDROID_5) { + if (null == mUploadMessage5) { + return; + } + mUploadMessage5.onReceiveValue(WebChromeClient.FileChooserParams + .parseResult(resultCode, intent)); + mUploadMessage5 = null; + } + } + + private void initView() { + webView = (WebView) findViewById(R.id.webview); + findViewById(R.id.back).setOnClickListener(v -> { + setResult(RESULT_CANCELED); + finish(); + }); + } + + private void showMenu(WebJsBeanInfo.DataBean data) { + + } + + public void showWebView(String url) { + Logger.d("ShowWebView--------" + url); + if (!TextUtils.isEmpty(url)) { + Map map = new HashMap<>(); + map.put("Referer", Constants.WXPAY_REFERER); + webView.loadUrl(url, map); + } else { + toast(ResUtil.getString(R.string.ui_webview_commonwebviewactivity_010)); + finish(); + } + } + + @Override + public void onBackPressed() { + if (webView.canGoBack()) { + if (!TextUtils.isEmpty(targetUrl) && targetUrl.contains("modules/nobles/paySuccess.html")) { + finish(); + } else + webView.goBack(); + } else { + this.finish(); + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onRecieveNeedRefreshWebView(WebViewRefreshEvent event) { + if (!StringUtil.isEmpty(url)) { + showWebView(url); + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void handleCertificationResultEvent(CertificationResultEvent event) { + webView.evaluateJavascript("renderByStatus(" + event.getStatus() + ")", null); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void showNavEvent(ShowNavEvent event) { + if (event != null) { + // true为显示,false为关闭 + if (event.isShowNav()) { + } else { + } + } + } + + @Override + protected void onDestroy() { + if (jsInterface != null) { + jsInterface.onCleared(); + } + EventBus.getDefault().unregister(this); + + if (webViewCallBack != null) { + webViewCallBack.onResult(""); + webViewCallBack = null; + } + super.onDestroy(); + WebViewUtils.releaseWeb(webView); + } + + private static WebViewCallBack webViewCallBack; + + public interface WebViewCallBack { + void onResult(String str); + } + + @Override + protected boolean needSteepStateBar() { + return true; + } + + @Override + protected void setStatusBar() { + super.setStatusBar(); + StatusBarUtil.transparencyBar(this); + StatusBarUtil.StatusBarLightMode(this); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onTaroPayResultEvent(TaroPayResultEvent event) { + if (webView != null) { + webView.evaluateJavascript("taroPayResultCallback(" + event.getResult() + ")", null); + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/login/ModifyInfoActivity.java b/app/src/main/java/com/chwl/app/ui/login/ModifyInfoActivity.java new file mode 100644 index 0000000..c262a7e --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/login/ModifyInfoActivity.java @@ -0,0 +1,191 @@ +package com.chwl.app.ui.login; + +import android.content.Intent; +import android.os.Bundle; +import android.text.Editable; +import android.text.InputFilter; +import android.text.TextWatcher; +import android.view.View; +import android.widget.EditText; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.core.content.ContextCompat; + +import com.google.android.material.snackbar.Snackbar; +import com.netease.nim.uikit.StatusBarUtil; +import com.chwl.app.R; +import com.chwl.app.base.BaseActivity; +import com.chwl.app.base.TitleBar; +import com.chwl.core.user.UserModel; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.library.utils.ResUtil; + +/** + * Created by zhouxiangfeng on 2017/5/13. + */ + +public class ModifyInfoActivity extends BaseActivity implements View.OnClickListener { + public static final int CONTENT_MODIFY = 1; + public static final int NICK_MODIFY = 2; + public static final String MODIFY_TYPE = "modify_type"; + private int modifyType = CONTENT_MODIFY; + + private EditText etEditText; + private RelativeLayout rlContentGroup; + + private EditText etEditTextNick; + private RelativeLayout rlNickGroup; + + private TextView tvCountDown; + + public static final String CONTENT = "content"; + public static final String CONTENT_NICK = "contentNick"; + private CoordinatorLayout layout_coordinator; + + TextWatcher textWatcher = new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + + int subCount = 0; + if (modifyType == CONTENT_MODIFY) + subCount = 60 - s.length(); + else if (modifyType == NICK_MODIFY) + subCount = 15 - s.length(); + + tvCountDown.setText(String.valueOf(subCount)); + + } + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_modify_info); + onFindViews(); + onSetListener(); + init(); + initData(); + } + + private void initData() { + UserInfo userInfo = UserModel.get().getCacheLoginUserInfo(); + if (userInfo != null) { + if (modifyType == CONTENT_MODIFY) { + etEditText.setText(userInfo.getUserDesc()); + } else if (modifyType == NICK_MODIFY) { + etEditTextNick.setText(userInfo.getNick()); + } + } + } + + private void init() { + modifyType = getIntent().getIntExtra(MODIFY_TYPE, CONTENT_MODIFY); + + if (modifyType == CONTENT_MODIFY) { + etEditText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(60)}); + etEditText.addTextChangedListener(textWatcher); + rlNickGroup.setVisibility(View.GONE); + initWhiteTitleBar(ResUtil.getString(R.string.ui_login_modifyinfoactivity_01)); + + } else if (modifyType == NICK_MODIFY) { + rlNickGroup.setVisibility(View.VISIBLE); + rlContentGroup.setVisibility(View.GONE); + etEditTextNick.setFilters(new InputFilter[]{new InputFilter.LengthFilter(15)}); + etEditTextNick.addTextChangedListener(textWatcher); + initWhiteTitleBar(ResUtil.getString(R.string.ui_login_modifyinfoactivity_02)); + } else { + initTitleBar(""); + } + mTitleBar.addAction(new TitleBar.TextAction(getString(R.string.label_modify_info_confirm), + ContextCompat.getColor(this, R.color.text_normal_c6c6e9)) { + @Override + public void performAction(View view) { + + // 个人简介允许为空,nick不能为空 + if (modifyType == CONTENT_MODIFY) { + String content = etEditText.getText().toString(); + Intent intent = new Intent(); + intent.putExtra(CONTENT, content); + setResult(RESULT_OK, intent); + finish(); + + } else if (modifyType == NICK_MODIFY) { + String contentNick = etEditTextNick.getText().toString(); + + if (!contentNick.trim().isEmpty()) { + Intent intent = new Intent(); + intent.putExtra(CONTENT_NICK, contentNick); + setResult(RESULT_OK, intent); + finish(); + } else { + Snackbar.make(layout_coordinator, ResUtil.getString(R.string.ui_login_modifyinfoactivity_03), Snackbar.LENGTH_SHORT).show(); + } + } + + } + }); + + } + + + private void onSetListener() { + findViewById(R.id.iv_nick_delete).setOnClickListener(this); + findViewById(R.id.iv_content_delete).setOnClickListener(this); + } + + private void onFindViews() { + + etEditText = findViewById(R.id.et_content); + rlContentGroup = findViewById(R.id.rl_content_group); + + etEditTextNick = findViewById(R.id.et_content_nick); + rlNickGroup = findViewById(R.id.rl_nick_group); + + tvCountDown = findViewById(R.id.tv_count_down); + + layout_coordinator = findViewById(R.id.layout_coordinator); + } + + public boolean isValid() { + return etEditText.length() > 60; + } + + @Override + public void onClick(View v) { + + switch (v.getId()) { + case R.id.iv_nick_delete: + etEditTextNick.setText(""); + break; + + case R.id.iv_content_delete: + etEditText.setText(""); + break; + } + + } + + @Override + protected boolean needSteepStateBar() { + return true; + } + + @Override + protected void setStatusBar() { + StatusBarUtil.transparencyBar(this); + StatusBarUtil.StatusBarLightMode(this); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/login/PasswordValidator.java b/app/src/main/java/com/chwl/app/ui/login/PasswordValidator.java new file mode 100644 index 0000000..6cbdb4e --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/login/PasswordValidator.java @@ -0,0 +1,61 @@ +package com.chwl.app.ui.login; + +import android.text.TextUtils; + +import androidx.annotation.NonNull; + +import com.chwl.app.R; +import com.chwl.library.utils.ResUtil; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Created by zhouxiangfeng on 2017/5/3. + */ + +public class PasswordValidator { + + private static final String REG = "^(?![0-9]+$)(?![a-zA-Z]+$)[a-z_A-Z0-9-.!@#$%\\\\^&*)(+={}\\[\\]/\",'<>~·`?:;|]{6,16}$"; + + private String errorMessage; + + public PasswordValidator() { + } + + public boolean isValid(@NonNull String text) { + if (!TextUtils.isEmpty(text)) { + if (16 >= text.length() && text.length() >= 6) { + return true; + } else { + errorMessage = ResUtil.getString(R.string.ui_login_passwordvalidator_01); + return false; + } + } else { + errorMessage = ResUtil.getString(R.string.ui_login_passwordvalidator_02); + } + return false; + } + + + + public String getErrorMessage() { + return errorMessage; + } + + + /** + * 检查密码是否同时包含数字和字母 + * + * @param psw + * @return + */ + public static boolean checkPwdFormat(String psw) { + if (psw == null || psw.isEmpty()) { + return false; + } + Pattern p = Pattern.compile(REG); + Matcher m = p.matcher(psw); + return m.matches(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/login/RegionListAdapter.kt b/app/src/main/java/com/chwl/app/ui/login/RegionListAdapter.kt new file mode 100644 index 0000000..227493f --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/login/RegionListAdapter.kt @@ -0,0 +1,32 @@ +package com.chwl.app.ui.login + +import com.chad.library.adapter.base.BaseMultiItemQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.core.bean.RegionBean + +/** + * Created by Max on 2023/12/7 19:34 + * Desc: + **/ +class RegionListAdapter: + BaseMultiItemQuickAdapter(ArrayList()) { + + companion object { + const val ITEM_TYPE_GROUP = 1 + } + + init { + addItemType(0, R.layout.region_item_def) + addItemType(ITEM_TYPE_GROUP, R.layout.region_item_group) + } + + override fun convert(helper: BaseViewHolder, item: RegionBean?) { + if (helper.itemViewType == ITEM_TYPE_GROUP) { + helper.setText(R.id.tv_group, item?.groupName?.toString() ?: "") + } + helper.setText(R.id.tv_name, item?.name ?: "") + helper.setText(R.id.tv_country_code, "+${item?.code}") + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/login/ShowBindEmailActivity.kt b/app/src/main/java/com/chwl/app/ui/login/ShowBindEmailActivity.kt new file mode 100644 index 0000000..967cbbc --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/login/ShowBindEmailActivity.kt @@ -0,0 +1,53 @@ +package com.chwl.app.ui.login + +import android.annotation.SuppressLint +import android.content.Context +import android.content.Intent +import android.text.TextUtils +import android.view.View +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.databinding.ActivityShowBindEmailBinding +import com.chwl.app.ui.setting.VerifyEmailActivity +import com.chwl.core.user.UserModel +import com.netease.nim.uikit.StatusBarUtil + +/** + * 已綁定手機號頁面 + * Created by wushaocheng + * Date: 2022/11/28 + */ +class ShowBindEmailActivity : BaseViewBindingActivity() { + + companion object { + @JvmStatic + fun start(context: Context) { + val intent = Intent(context, ShowBindEmailActivity::class.java) + context.startActivity(intent) + } + } + + @SuppressLint("SetTextI18n") + override fun init() { + initWhiteTitleBar(getString(R.string._ver_24_text_change_email)) + val userInfo = UserModel.get().cacheLoginUserInfo + if (userInfo != null && !TextUtils.isEmpty(userInfo.email)) { + binding.tvPhone.text = userInfo.email + } + binding.tvChangeEmail.setOnClickListener { v: View? -> + VerifyEmailActivity.start(this@ShowBindEmailActivity, false) + finish() + } + } + + override fun needSteepStateBar(): Boolean { + return true + } + + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/login/ShowBindPhoneActivity.kt b/app/src/main/java/com/chwl/app/ui/login/ShowBindPhoneActivity.kt new file mode 100644 index 0000000..08173d7 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/login/ShowBindPhoneActivity.kt @@ -0,0 +1,54 @@ +package com.chwl.app.ui.login + +import android.annotation.SuppressLint +import android.content.Context +import com.chwl.app.R +import com.chwl.library.utils.ResUtil +import com.chwl.core.user.UserModel +import com.chwl.app.ui.setting.VerifyPhoneActivity +import com.netease.nim.uikit.StatusBarUtil +import android.content.Intent +import android.text.TextUtils +import android.view.View +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.databinding.ActivityShowBindPhoneBinding + +/** + * 已綁定手機號頁面 + * Created by wushaocheng + * Date: 2022/11/28 + */ +class ShowBindPhoneActivity : BaseViewBindingActivity() { + + companion object { + @JvmStatic + fun start(context: Context) { + val intent = Intent(context, ShowBindPhoneActivity::class.java) + context.startActivity(intent) + } + } + + @SuppressLint("SetTextI18n") + override fun init() { + initWhiteTitleBar(getString(R.string.text_bind_phone)) + val userInfo = UserModel.get().cacheLoginUserInfo + if (userInfo != null && !TextUtils.isEmpty(userInfo.phone)) { + binding.tvPhone.text = "+${userInfo.phoneAreaCode} ${userInfo.phone}" + } + binding.tvChangePhone.setOnClickListener { v: View? -> + VerifyPhoneActivity.start(this@ShowBindPhoneActivity, false) + finish() + } + } + + override fun needSteepStateBar(): Boolean { + return true + } + + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/login/dialog/CountrySelectDialog.kt b/app/src/main/java/com/chwl/app/ui/login/dialog/CountrySelectDialog.kt new file mode 100644 index 0000000..472333b --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/login/dialog/CountrySelectDialog.kt @@ -0,0 +1,102 @@ +package com.chwl.app.ui.login.dialog + +import android.view.Gravity +import android.view.WindowManager +import androidx.core.widget.doOnTextChanged +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.chwl.app.R +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.bindadapter.BaseBindingAdapter +import com.chwl.app.bindadapter.BaseBindingViewHolder +import com.chwl.app.databinding.DialogCountrySelectBinding +import com.chwl.app.databinding.ItemCountrySelectBinding +import com.chwl.app.ui.bean.CountryBean +import com.chwl.app.ui.utils.load +import com.chwl.library.common.util.ClickUtils.click +import com.chwl.library.common.util.setVis +import com.example.lib_utils.ktx.getColor +import com.netease.nim.uikit.common.util.sys.ScreenUtil + +class CountrySelectDialog : BaseDialogFragment() { + + + override var width = WindowManager.LayoutParams.MATCH_PARENT + override var height = ScreenUtil.screenHeight / 2 + override var dimAmount = 0.3f + override var gravity = Gravity.BOTTOM + + private var mPosition = -1 + lateinit var mAdapter: CountryAdapter + + var isRegion = false + var mData = mutableListOf() + + override fun init() { + + + binding.titleBar.setTitle(R.string.layout_layout_phone_country_choose_01) + binding.titleBar.setTitleColor(R.color.color_313131.getColor()) + + binding.search.setVis(isRegion) + binding.searchIcon.setVis(isRegion) + + mAdapter = CountryAdapter() + mAdapter.setOnItemClickListener { adapter, view, position -> + mAdapter.data?.getOrNull(mPosition)?.checked = false + mPosition = position + mAdapter.data?.getOrNull(position)?.checked = true + mAdapter.notifyDataSetChanged() + } + + binding.rvList.layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false) + binding.rvList.adapter = mAdapter + + binding.search.doOnTextChanged { text, start, before, count -> + getSearch(text) + } + + mData.forEachIndexed{ index, countryBean -> + if (countryBean.checked) { + mPosition = index + } + } + mAdapter.setNewData(mData) + + + binding.confirm.click { + mAdapter.data?.getOrNull(mPosition)?.let { + mActionCallBack?.onAction(mPosition,it) + dismiss() + } + } + } + + + private fun getSearch(text: CharSequence?) { + if (text != null) { + val newData = mData.filter { it.name.contains(text,true) } + mAdapter.setNewData(newData) + } else { + mAdapter.setNewData(mData) + } + } + + + class CountryAdapter : BaseBindingAdapter() { + + override fun convert(helper: BaseBindingViewHolder, data: CountryBean) { + + helper.binding.let { + val position = helper.bindingAdapterPosition + it.select.setVis(data.checked) + it.icon.load(data.icon) + it.text.text = data.name + } + + } + } + + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/login/fragment/AddUserInfoFragment.java b/app/src/main/java/com/chwl/app/ui/login/fragment/AddUserInfoFragment.java new file mode 100644 index 0000000..fa766db --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/login/fragment/AddUserInfoFragment.java @@ -0,0 +1,391 @@ +package com.chwl.app.ui.login.fragment; + +import android.annotation.SuppressLint; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.text.InputFilter; +import android.text.TextUtils; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.RadioButton; + +import androidx.annotation.Nullable; + +import com.bumptech.glide.load.DataSource; +import com.bumptech.glide.load.engine.GlideException; +import com.bumptech.glide.request.RequestListener; +import com.bumptech.glide.request.target.Target; +import com.chwl.app.R; +import com.chwl.app.application.IReportConstants; +import com.chwl.app.application.ReportManager; +import com.chwl.app.base.BaseFragment; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.app.ui.bean.CountryBean; +import com.chwl.app.ui.link.LinkHelper; +import com.chwl.app.ui.link.LinkIntent; +import com.chwl.app.ui.login.dialog.CountrySelectDialog; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.auth.entity.ThirdUserInfo; +import com.chwl.core.bean.response.ServiceResult; +import com.chwl.core.initial.InitialModel; +import com.chwl.core.initial.bean.InitInfo; +import com.chwl.core.linked.LinkedModel; +import com.chwl.core.linked.bean.LinkedInfo; +import com.chwl.core.user.UserModel; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.core.utils.net.RxHelper; +import com.chwl.library.common.glide.GlideUtils; +import com.chwl.library.common.util.OtherExtKt; +import com.chwl.library.net.rxnet.RxNet; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.widget.text.DrawableTextView; +import com.example.lib_utils.ktx.ResourcesKtxKt; +import com.google.android.material.textfield.TextInputEditText; +import com.netease.nim.uikit.common.util.sys.ScreenUtil; +import com.sleepbot.datetimepicker.time.RadialPickerLayout; +import com.sleepbot.datetimepicker.time.TimePickerDialog; +import com.trello.rxlifecycle3.android.FragmentEvent; + +import java.util.List; + +import io.reactivex.Single; +import io.reactivex.SingleObserver; +import io.reactivex.disposables.Disposable; +import me.shihao.library.XRadioGroup; +import retrofit2.http.GET; + +/** + * @author jack + * @Description 新用戶注冊 + * @Date 2018/11/23 + */ +public class AddUserInfoFragment extends BaseFragment + implements View.OnClickListener, + TimePickerDialog.OnTimeSetListener { + private TextInputEditText tvNick, tvCode; + private Button okBtn; + private View tvRandomNick; + private int gender = -1; + private XRadioGroup rgGender; + private RadioButton rbMale; + private DrawableTextView mTvCountry; + + private String avatarUrl = "https://img.molistar.xyz/default_avatar_molistar.png"; + public static String INVITE_USER_CODE = ""; + + private List mData; + + @Override + public int getRootLayoutId() { + return R.layout.fragment_add_user_info; + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + tvNick = view.findViewById(R.id.tv_nick); + tvCode = view.findViewById(R.id.tv_code); + okBtn = view.findViewById(R.id.ok_btn); + tvRandomNick = view.findViewById(R.id.tv_random_nick); + rgGender = view.findViewById(R.id.rg_gender); + rbMale = view.findViewById(R.id.rb_male); + mTvCountry = view.findViewById(R.id.tvCountry); + } + + @Override + public void initiate() { + View titleBar = mView.findViewById(R.id.tv_title); + ViewGroup.LayoutParams layoutParams = titleBar.getLayoutParams(); + if (layoutParams instanceof ViewGroup.MarginLayoutParams) { + ((ViewGroup.MarginLayoutParams) layoutParams).setMargins(0, ScreenUtil.getStatusBarHeight(getContext()), 0, 0); + titleBar.setLayoutParams(layoutParams); + } + gender = -1; + okBtn.setOnClickListener(this); + tvRandomNick.setOnClickListener(this); + mTvCountry.setOnClickListener(this); + addUserInfo(); + addInviteCodeInfo(); + InitialModel.get().init(false); + getCountryListData(false); + } + + private void addUserInfo() { + ThirdUserInfo thirdUserInfo = AuthModel.get().getThirdUserInfo(); + if (thirdUserInfo != null) { + if (thirdUserInfo.getType() == ThirdUserInfo.TYPE_FACEBOOK || thirdUserInfo.getType() == ThirdUserInfo.TYPE_LINE || thirdUserInfo.getType() == ThirdUserInfo.TYPE_GOOGLE) { + avatarUrl = TextUtils.isEmpty(thirdUserInfo.getUserIcon()) ? avatarUrl : thirdUserInfo.getUserIcon(); + String str_gender = thirdUserInfo.getUserGender() == null ? "" : thirdUserInfo.getUserGender(); + gender = str_gender.equals("m") ? UserInfo.GENDER_MALE : UserInfo.GENDER_FEMALE; + rgGender.check(gender == UserInfo.GENDER_MALE ? R.id.rb_male : R.id.rb_female); + tvNick.setText(thirdUserInfo.getUserName()); + } + } else { + // 设置默认昵称 + setRandomNick(); + } + tvNick.setFilters(new InputFilter[]{new InputFilter.LengthFilter(8)}); + rgGender.setOnCheckedChangeListener((radioGroup, i) -> gender = i == rbMale.getId() ? UserInfo.GENDER_MALE : UserInfo.GENDER_FEMALE); + } + + /** + * 如果有邀请码的话,自动填写,H5预填写的邀请码优先级高于LinkedMe的 + */ + private void addInviteCodeInfo() { + if (!TextUtils.isEmpty(UserModel.get().getPreFillInviteCode())) { + tvCode.setText(UserModel.get().getPreFillInviteCode()); + } else { + LinkedInfo linkedInfo = LinkedModel.get().getLinkedInfo(); + if (linkedInfo != null && !TextUtils.isEmpty(linkedInfo.getInviteCode())) { + tvCode.setText(linkedInfo.getInviteCode()); + } else { + try { + LinkIntent intent = LinkHelper.INSTANCE.getLinkIntent(); + if (intent != null) { + String path = intent.getUri().getPath(); + if (path != null && path.equals("/invite")) { + String code = intent.getUri().getQueryParameter("code"); + if (!TextUtils.isEmpty(code)) { + tvCode.setText(code); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.ok_btn: + + if (tvNick.getText() == null) { + toast(ResUtil.getString(R.string.login_fragment_adduserinfofragment_01)); + return; + } + + if (TextUtils.isEmpty(tvNick.getText().toString().trim())) { + toast(ResUtil.getString(R.string.login_fragment_adduserinfofragment_01)); + return; + } + + if (gender == -1) { + toast(ResUtil.getString(R.string.login_fragment_adduserinfofragment_02)); + return; + } + + InitInfo initInfo = InitialModel.get().getCacheInitInfo(); + String code = ""; + if (tvCode.getText() != null) { + code = tvCode.getText().toString().trim(); + } + if (initInfo != null && initInfo.isCheckInviteCode() && TextUtils.isEmpty(code)) { + String message = ResUtil.getString(R.string.login_fragment_adduserinfofragment_03); + getDialogManager().showOkCancelDialog( + message, + ResUtil.getString(R.string.login_fragment_adduserinfofragment_04), + ResUtil.getString(R.string.login_fragment_adduserinfofragment_05), + new DialogManager.OkCancelDialogListener() { + @Override + public void onCancel() { + + } + + @Override + public void onOk() { + commit(tvNick.getText().toString().trim(), avatarUrl, gender, tvCode.getText() == null ? "" : tvCode.getText().toString().trim()); + } + }); + } else { + commit(tvNick.getText().toString().trim(), avatarUrl, gender, tvCode.getText() == null ? "" : tvCode.getText().toString().trim()); + } + break; + case R.id.tv_random_nick: + setRandomNick(); + break; + case R.id.tvCountry: + showCountryDialog(mData); + break; + + default: + break; + } + } + + @SuppressLint("CheckResult") + private void setRandomNick() { + tvRandomNick.setVisibility(View.VISIBLE); + tvRandomNick.setEnabled(false); + UserModel.get().getRandomNick() + .compose(bindToLifecycle()) + .subscribe((nick, throwable) -> { + tvRandomNick.setEnabled(true); + if (throwable != null) { + toast(throwable.getMessage()); + } else if (!TextUtils.isEmpty(nick)) { + tvNick.setText(nick); + } + }); + } + + //获取国家列表 + private void getCountryListData(boolean needShowDialog) { + getCountryList(). + compose(bindToLifecycle()) + .doOnSuccess(countryBeans -> { + + mData = countryBeans; + + if (OtherExtKt.isVerify(countryBeans)) { + if (needShowDialog) { + showCountryDialog(countryBeans); + } else { + CountryBean checkData = null; + for (int i = 0; i < countryBeans.size(); i++) { + if (countryBeans.get(i).checked) { + checkData = countryBeans.get(i); + } + } + + if (checkData != null) { + setCountryInfo(checkData); + } else { + mTvCountry.setDrawableEmpty(ResourcesKtxKt.getDrawable(R.drawable.transparent_draw),null,ResourcesKtxKt.getDrawable(R.drawable.base_ic_arrow_right),null); + OtherExtKt.doLog(" 没有默认 地区"); + } + } + } + }).doOnError(throwable -> { + + }).subscribe(); + } + + //弹出国家列表选择弹窗 + private void showCountryDialog(List list) { + if (OtherExtKt.isVerify(list)) { + CountrySelectDialog dialog = new CountrySelectDialog(); + dialog.setRegion(true); + dialog.setMData(list); + dialog.setMActionCallBack((type, data) -> { + if (data != null && data instanceof CountryBean) { + setCountryInfo((CountryBean) data); + } + }); + dialog.show(getContext()); + } else { + getCountryListData(true); + } + } + + private void setCountryInfo(CountryBean data) { + mTvCountry.setText(data.name); + mTvCountry.setTag(data); + GlideUtils.instance().downloadFromUrlToDrawable(getContext(), data.icon, new RequestListener() { + @Override + public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { + return false; + } + + @Override + public boolean onResourceReady(Drawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { + try { + mTvCountry.setDrawableEmpty(resource, null, ResourcesKtxKt.getDrawable(R.drawable.base_ic_arrow_right), null); + } catch (Exception e) {} + return false; + } + }); + } + + + private void commit(String nick, String avatarUrl, int gender, String shareCode) { + try { + UserInfo userInfo = new UserInfo(); + userInfo.setUid(AuthModel.get().getCurrentUid()); + userInfo.setNick(nick); + userInfo.setAvatar(avatarUrl); + + if (gender == UserInfo.GENDER_MALE || gender == UserInfo.GENDER_FEMALE) { + userInfo.setGender(gender); + } else { + toast(ResUtil.getString(R.string.login_fragment_adduserinfofragment_07)); + return; + } + + //不选国家不给注册 + Object country = mTvCountry.getTag(); + if (country != null && country instanceof CountryBean) { + userInfo.setRegionId(((CountryBean) country).id); + } else { + toast(ResUtil.getString(R.string.regionTips)); + return; + } + + + getDialogManager().showProgressDialog(getContext(), ResUtil.getString(R.string.login_fragment_adduserinfofragment_08)); + LinkedInfo linkedInfo = LinkedModel.get().getLinkedInfo(); + + String channel = ""; + String roomUid = ""; + String uid = ""; + if (linkedInfo != null) { + channel = linkedInfo.getChannel(); + roomUid = linkedInfo.getRoomUid(); + uid = linkedInfo.getUid(); + } + INVITE_USER_CODE = shareCode; + String finalChannel = channel; +// String adid = Adjust.getAdid(); + String adid = ""; + UserModel.get().requestCompleteUserInfo(userInfo, channel, uid, roomUid, shareCode, adid) + .compose(bindUntilEvent(FragmentEvent.DESTROY)) + .subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onSuccess(UserInfo userInfo) { + getDialogManager().dismissDialog(); + ReportManager.get().reportAdjustEvent(IReportConstants.ADJUST_REGISTER); + // HashMap map = new HashMap<>(2); + // map.put(FirebaseAnalytics.Param.METHOD, finalChannel); + // ReportManager.get().reportEvent(FirebaseAnalytics.Event.SIGN_UP, map); + AuthModel.get().setThirdUserInfo(null); + getActivity().finish(); + } + + @Override + public void onError(Throwable e) { + getDialogManager().dismissDialog(); + toast(e.getMessage()); + } + }); + } catch (Exception e) {} + } + + @Override + public void onTimeSet(RadialPickerLayout view, int hourOfDay, int minute) { + + } + + + private Single> getCountryList() { + return api.getCountryList() + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()); + } + + private final Api api = RxNet.create(Api.class); + public interface Api{ + //获取国家列表 + @GET("/regionInfo/listAll") + Single>> getCountryList(); + } + + +} diff --git a/app/src/main/java/com/chwl/app/ui/login/helper/LogoutHelper.java b/app/src/main/java/com/chwl/app/ui/login/helper/LogoutHelper.java new file mode 100644 index 0000000..92d146d --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/login/helper/LogoutHelper.java @@ -0,0 +1,81 @@ +package com.chwl.app.ui.login.helper; + +import android.text.Spannable; +import android.text.SpannableString; +import android.text.TextUtils; +import android.text.style.ForegroundColorSpan; + +import androidx.core.content.ContextCompat; + +import com.chwl.app.R; +import com.chwl.app.base.BaseActivity; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.auth.exception.AccountCancelException; +import com.chwl.core.auth.exception.BanAccountException; +import com.chwl.core.auth.exception.IsSuperAdminException; +import com.chwl.library.net.rxnet.exception.ExceptionHandle; +import com.chwl.library.utils.ResUtil; + +import java.io.IOException; +import java.net.SocketException; +import java.net.SocketTimeoutException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; + +import retrofit2.HttpException; + +/** + * create by lvzebiao @2019/12/9 + */ +public class LogoutHelper { + + public static void logout() { + AuthModel.get().logout().subscribe(); + } + + public static void dealWithLoginError(BaseActivity activity, Throwable e) { + if (!(e instanceof IsSuperAdminException)) { + String msg = e.getMessage(); + StringBuilder eventLabel = new StringBuilder(ResUtil.getString(R.string.login_helper_logouthelper_01)); + if (!TextUtils.isEmpty(msg)) { + eventLabel.append(msg); + } + } + if (e instanceof SocketTimeoutException || e instanceof SocketException || e instanceof HttpException) { + activity.toast(ResUtil.getString(R.string.login_helper_logouthelper_013)); + } else if (e instanceof BanAccountException) { + BanAccountException exception = (BanAccountException) e; + String text = exception.getMessage() + " " +ResUtil.getString(R.string.login_helper_logouthelper_03); + int start = text.length(); + SimpleDateFormat simpleDateFormat = new SimpleDateFormat(ResUtil.getString(R.string.login_helper_logouthelper_04), Locale.ENGLISH); + simpleDateFormat.setTimeZone(TimeZone.getTimeZone("GMT+08")); + text += simpleDateFormat.format(new Date(exception.getDate())); + SpannableString spannableString = new SpannableString(text); + spannableString.setSpan(new ForegroundColorSpan(ContextCompat.getColor(activity, R.color.appColor)), + start, text.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE); + activity.getDialogManager().showOkCancelWithTitleDialog(ResUtil.getString(R.string.login_helper_logouthelper_05), + spannableString, ResUtil.getString(R.string.login_helper_logouthelper_06), ResUtil.getString(R.string.login_helper_logouthelper_07), null); + } else if (e instanceof AccountCancelException) { + AccountCancelException exception = (AccountCancelException) e; + SimpleDateFormat simpleDateFormat = new SimpleDateFormat(ResUtil.getString(R.string.login_helper_logouthelper_08), Locale.ENGLISH); + simpleDateFormat.setTimeZone(TimeZone.getTimeZone("GMT+08")); + + String text = ResUtil.getString(R.string.login_helper_logouthelper_09) + simpleDateFormat.format(new Date(exception.getCancelDate())); + int end = text.length(); + text += ResUtil.getString(R.string.login_helper_logouthelper_010); + SpannableString spannableString = new SpannableString(text); + spannableString.setSpan(new ForegroundColorSpan(ContextCompat.getColor(activity, R.color.appColor)), + 0, end, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); + activity.getDialogManager().showOkWithTitleDialog(ResUtil.getString(R.string.login_helper_logouthelper_011), + spannableString, ResUtil.getString(R.string.login_helper_logouthelper_012), true, null); + } else if (e instanceof IOException) { + activity.toast(ResUtil.getString(R.string.login_helper_logouthelper_013)); + } else { + String message = ExceptionHandle.Companion.handleException(e); + activity.toast(message); + } + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/login/ui/CodeEditText.java b/app/src/main/java/com/chwl/app/ui/login/ui/CodeEditText.java new file mode 100644 index 0000000..813b7d0 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/login/ui/CodeEditText.java @@ -0,0 +1,236 @@ +package com.chwl.app.ui.login.ui; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.text.InputFilter; +import android.text.TextPaint; +import android.util.AttributeSet; +import android.view.inputmethod.InputMethodManager; + +import com.chwl.app.R; + +/** + * 验证码输入框,重写EditText的绘制方法实现。 + * @author RAE + */ +public class CodeEditText extends androidx.appcompat.widget.AppCompatEditText { + + + private int mTextColor; + + public interface OnTextFinishListener { + + void onTextFinish(CharSequence text, int length); + } + + // 输入的最大长度 + private int mMaxLength = 4; + // 边框宽度 + private int mStrokeWidth; + // 边框高度 + private int mStrokeHeight; + // 边框之间的距离 + private int mStrokePadding = 20; + + + private final Rect mRect = new Rect(); + + + /** + * 输入结束监听 + */ + private OnTextFinishListener mOnInputFinishListener; + + // 方框的背景 + private Drawable mStrokeDrawable; + + /** + * 构造方法 + * + */ + public CodeEditText(Context context, AttributeSet attrs) { + super(context, attrs); + TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CodeEditText); + int indexCount = typedArray.getIndexCount(); + for (int i = 0; i < indexCount; i++) { + int index = typedArray.getIndex(i); + if (index == R.styleable.CodeEditText_strokeHeight) { + this.mStrokeHeight = (int) typedArray.getDimension(index, 60); + } else if (index == R.styleable.CodeEditText_strokeWidth) { + this.mStrokeWidth = (int) typedArray.getDimension(index, 60); + + } else if (index == R.styleable.CodeEditText_strokePadding) { + this.mStrokePadding = (int) typedArray.getDimension(index, 20); + + } else if (index == R.styleable.CodeEditText_strokeBackground) { + this.mStrokeDrawable = typedArray.getDrawable(index); + + } else if (index == R.styleable.CodeEditText_strokeLength) { + this.mMaxLength = typedArray.getInteger(index, 4); + } + } + typedArray.recycle(); + + if (mStrokeDrawable == null) { + throw new NullPointerException("stroke drawable not allowed to be null!"); + } + + setMaxLength(mMaxLength); + setLongClickable(false); + // 去掉背景颜色 + setBackgroundColor(Color.TRANSPARENT); + // 不显示光标 + setCursorVisible(false); + } + + @Override + public boolean onTextContextMenuItem(int id) { + return false; + } + +// private int px(int size) { +// return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, size, getResources().getDisplayMetrics()); +// } + + /** + * 设置最大长度 + */ + private void setMaxLength(int maxLength) { + if (maxLength >= 0) { + setFilters(new InputFilter[]{new InputFilter.LengthFilter(maxLength)}); + } else { + setFilters(new InputFilter[0]); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + int width = getMeasuredWidth(); + int height = getMeasuredHeight(); + int widthMode = MeasureSpec.getMode(widthMeasureSpec); + int heightMode = MeasureSpec.getMode(heightMeasureSpec); + + // 判断高度是否小于推荐高度 + if (height < mStrokeHeight) { + height = mStrokeHeight; + } + + // 判断高度是否小于推荐宽度 + int recommendWidth = mStrokeWidth * mMaxLength + mStrokePadding * (mMaxLength - 1); + if (width < recommendWidth) { + width = recommendWidth; + } + + widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, widthMode); + heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, heightMode); + setMeasuredDimension(widthMeasureSpec, heightMeasureSpec); + + } + + @Override + protected void onDraw(Canvas canvas) { + mTextColor = getCurrentTextColor(); + setTextColor(Color.TRANSPARENT); + super.onDraw(canvas); + setTextColor(mTextColor); + // 重绘背景颜色 + drawStrokeBackground(canvas); + // 重绘文本 + drawText(canvas); + } + + + /** + * 重绘背景 + */ + private void drawStrokeBackground(Canvas canvas) { + // 绘制方框背景颜色 + mRect.left = 0; + mRect.top = 0; + mRect.right = mStrokeWidth; + mRect.bottom = mStrokeHeight; + int count = canvas.getSaveCount(); + canvas.save(); + for (int i = 0; i < mMaxLength; i++) { + mStrokeDrawable.setBounds(mRect); + mStrokeDrawable.setState(new int[]{android.R.attr.state_enabled}); + mStrokeDrawable.draw(canvas); + float dx = mRect.right + mStrokePadding; + // 移动画布 + canvas.save(); + canvas.translate(dx, 0); + } + canvas.restoreToCount(count); + canvas.translate(0, 0); + + // 绘制激活状态的边框 + // 当前激活的索引 + int activatedIndex = Math.max(0, getEditableText().length()); + mRect.left = mStrokeWidth * activatedIndex + mStrokePadding * activatedIndex; + mRect.right = mRect.left + mStrokeWidth; + mStrokeDrawable.setState(new int[]{android.R.attr.state_focused}); + mStrokeDrawable.setBounds(mRect); + mStrokeDrawable.draw(canvas); + + } + + + /** + * 重绘文本 + */ + private void drawText(Canvas canvas) { + int count = canvas.getSaveCount(); + canvas.translate(0, 0); + int length = getEditableText().length(); + for (int i = 0; i < length; i++) { + String text = String.valueOf(getEditableText().charAt(i)); + TextPaint textPaint = getPaint(); + textPaint.setColor(mTextColor); + // 获取文本大小 + textPaint.getTextBounds(text, 0, 1, mRect); + // 计算(x,y) 坐标 + int x = mStrokeWidth / 2 + (mStrokeWidth + mStrokePadding) * i - (mRect.centerX()); + int y = canvas.getHeight() / 2 + mRect.height() / 2; + canvas.drawText(text, x, y, textPaint); + } + canvas.restoreToCount(count); + } + + @Override + protected void onTextChanged(CharSequence text, int start, + int lengthBefore, int lengthAfter) { + super.onTextChanged(text, start, lengthBefore, lengthAfter); + + // 当前文本长度 + int textLength = getEditableText().length(); + + if (textLength == mMaxLength) { + hideSoftInput(); + if (mOnInputFinishListener != null) { + mOnInputFinishListener.onTextFinish(getEditableText().toString(), mMaxLength); + } + } + + } + + + public void hideSoftInput() { + InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + if (imm != null) + imm.hideSoftInputFromWindow(getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); + } + + /** + * 设置输入完成监听 + */ + public void setOnTextFinishListener(OnTextFinishListener onInputFinishListener) { + this.mOnInputFinishListener = onInputFinishListener; + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/patriarch/PatriarchModeActivity.java b/app/src/main/java/com/chwl/app/ui/patriarch/PatriarchModeActivity.java new file mode 100644 index 0000000..fbfa9e9 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/patriarch/PatriarchModeActivity.java @@ -0,0 +1,58 @@ +package com.chwl.app.ui.patriarch; + +import android.content.Context; +import android.content.Intent; +import android.graphics.Paint; + +import com.netease.nim.uikit.StatusBarUtil; +import com.chwl.app.R; +import com.chwl.app.base.BaseBindingActivity; +import com.chwl.app.databinding.ActivityPatriarchModeBinding; +import com.chwl.app.ui.webview.CommonWebViewActivity; +import com.chwl.core.UriProvider; +import com.chwl.core.user.UserModel; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.library.annatation.ActLayoutRes; +import com.chwl.library.utils.ResUtil; + +@ActLayoutRes(R.layout.activity_patriarch_mode) +public class PatriarchModeActivity extends BaseBindingActivity { + +public static void start(Context context) { + Intent starter = new Intent(context, PatriarchModeActivity.class); + context.startActivity(starter); +} + + @Override + protected void init() { + initWhiteTitleBar(ResUtil.getString(R.string.ui_patriarch_patriarchmodeactivity_01)); + mBinding.tvPlan.setOnClickListener(v -> CommonWebViewActivity.start(PatriarchModeActivity.this, UriProvider.IM_SERVER_URL + "/molistar/activity/cleanNet/index.html")); + mBinding.tvOpen.setOnClickListener(v -> start(PatriarchPwdActivity.class)); + + mBinding.tvPlan.getPaint().setFlags(Paint.UNDERLINE_TEXT_FLAG); //下划线 + mBinding.tvPlan.getPaint().setAntiAlias(true);//抗锯齿 + } + + @Override + protected void onResume() { + super.onResume(); + UserInfo userInfo = UserModel.get().getCacheLoginUserInfo(); + if (userInfo != null && userInfo.isParentMode()) { + mBinding.tvOpen.setText(ResUtil.getString(R.string.ui_patriarch_patriarchmodeactivity_02)); + } else { + mBinding.tvOpen.setText(ResUtil.getString(R.string.ui_patriarch_patriarchmodeactivity_03)); + } + } + + @Override + protected boolean needSteepStateBar() { + return true; + } + + @Override + protected void setStatusBar() { + super.setStatusBar(); + StatusBarUtil.transparencyBar(this); + StatusBarUtil.StatusBarLightMode(this); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/patriarch/PatriarchPwdActivity.java b/app/src/main/java/com/chwl/app/ui/patriarch/PatriarchPwdActivity.java new file mode 100644 index 0000000..f3e7788 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/patriarch/PatriarchPwdActivity.java @@ -0,0 +1,130 @@ +package com.chwl.app.ui.patriarch; + +import android.annotation.SuppressLint; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; + +import com.netease.nim.uikit.StatusBarUtil; +import com.chwl.app.R; +import com.chwl.app.base.BaseBindingActivity; +import com.chwl.app.databinding.ActivityPatriarchPwdBinding; +import com.chwl.core.user.UserModel; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.library.annatation.ActLayoutRes; +import com.chwl.library.utils.ResUtil; + + +@ActLayoutRes(R.layout.activity_patriarch_pwd) +public class PatriarchPwdActivity extends BaseBindingActivity { + private String firstPwd; + + @Override + protected void init() { + initWhiteTitleBar(""); + UserInfo userInfo = UserModel.get().getCacheLoginUserInfo(); + if (userInfo == null) { + toast(ResUtil.getString(R.string.ui_patriarch_patriarchpwdactivity_01)); + finish(); + return; + } + + mBinding.tvClosePmTips.setVisibility(View.GONE); + if (userInfo.isParentMode()) { + mBinding.tvClosePmTips.setVisibility(View.VISIBLE); + mBinding.text.setVisibility(View.GONE); + mBinding.tvTip.setVisibility(View.GONE); + mBinding.tvCommit.setVisibility(View.GONE); + resetEditViewLocation(); + } + + mBinding.tvCommit.setOnClickListener(v -> { + if (ResUtil.getString(R.string.ui_patriarch_patriarchpwdactivity_02).equals(mBinding.tvCommit.getText().toString())) { + firstPwd = mBinding.etPwd.getText().toString(); + mBinding.etPwd.setText(""); + mBinding.text.setText(ResUtil.getString(R.string.ui_patriarch_patriarchpwdactivity_03)); + mBinding.tvTip.setText(ResUtil.getString(R.string.ui_patriarch_patriarchpwdactivity_04)); + mBinding.tvCommit.setText(ResUtil.getString(R.string.ui_patriarch_patriarchpwdactivity_05)); + } else if (firstPwd != null && !firstPwd.equals(mBinding.etPwd.getText().toString())) { + toast(ResUtil.getString(R.string.ui_patriarch_patriarchpwdactivity_06)); + } else { + commit(); + } + }); + setCommitBtnStatus(false); + mBinding.etPwd.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + if (s.length() == 4) { + if (mBinding.tvCommit.getVisibility() == View.GONE) { + commit(); + } else { + setCommitBtnStatus(true); + } + } else { + setCommitBtnStatus(false); + } + } + + @Override + public void afterTextChanged(Editable s) { + + } + }); + } + + @SuppressLint("CheckResult") + private void commit() { + UserModel.get().openOrClosePatriarchMode( + DESAndBase64(mBinding.etPwd.getText().toString()), + UserModel.get().getCacheLoginUserInfo().isParentMode() ? 0 : 1) + .subscribe(s -> { + toast(UserModel.get().getCacheLoginUserInfo().isParentMode() ? ResUtil.getString(R.string.ui_patriarch_patriarchpwdactivity_07) : ResUtil.getString(R.string.ui_patriarch_patriarchpwdactivity_08)); + UserModel.get().getCacheLoginUserInfo().setParentMode(!UserModel.get().getCacheLoginUserInfo().isParentMode()); + UserModel.get().getCacheLoginUserInfo().setHasSetParentPwd(true); + finish(); + }); + } + + private void setCommitBtnStatus(boolean canClick) { + mBinding.tvCommit.setClickable(canClick); + if (canClick) { + mBinding.tvCommit.setBackgroundResource(R.drawable.base_shape_positive_30dp); + mBinding.tvCommit.setTextColor(getResources().getColor(R.color.base_color_positive_text)); + } else { + mBinding.tvCommit.setBackgroundResource(R.drawable.base_shape_e6e6e6_30dp); + mBinding.tvCommit.setTextColor(getResources().getColor(R.color.color_FFFFFF)); + } + } + + private void resetEditViewLocation() { + ViewGroup.LayoutParams tmp = mBinding.etPwd.getLayoutParams(); + if (tmp instanceof LinearLayout.LayoutParams) { + LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) tmp; + params.gravity = Gravity.CENTER_HORIZONTAL; + params.leftMargin = 0; + params.rightMargin = 0; + mBinding.etPwd.setLayoutParams(params); + } + } + + @Override + protected boolean needSteepStateBar() { + return true; + } + + @Override + protected void setStatusBar() { + StatusBarUtil.transparencyBar(this); + StatusBarUtil.StatusBarLightMode(this); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/patriarch/help/LimitEnterRoomHelper.java b/app/src/main/java/com/chwl/app/ui/patriarch/help/LimitEnterRoomHelper.java new file mode 100644 index 0000000..892fa6b --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/patriarch/help/LimitEnterRoomHelper.java @@ -0,0 +1,79 @@ +package com.chwl.app.ui.patriarch.help; + +import android.app.Dialog; +import android.content.Context; +import android.text.TextUtils; + +import com.chwl.app.R; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.utils.ActivityUtil; +import com.chwl.library.utils.ResUtil; + +/** + * 进房限制的一些处理,因为main和avroom 基本一样,所以写一起减少冗余 + * + * create by lvzebiao @2019/8/19 + */ +public class LimitEnterRoomHelper { + + /** + * 青少年限制时长的弹窗 + */ + private Dialog pmLimitTimeDialog; + + /** + * + * @param thisContext - + * @param isNeedCheckRoomInfo ture,表示需要检查房间信息是否为空 + */ + public void handleThisContext(Context thisContext, CharSequence tips, + boolean isNeedCheckRoomInfo, OnDialogClickHandle handle) { + if (TextUtils.isEmpty(tips)) { + return; + } + if (!ActivityUtil.isCanShowAppCompatDialog(thisContext)) { + return; + } + if (isNeedCheckRoomInfo) { + if (AvRoomDataManager.get().mCurrentRoomInfo == null) { + return; + } + } + try { + dismissDialog(); + pmLimitTimeDialog = DialogManager.createDialog(thisContext); + pmLimitTimeDialog.show(); + DialogManager.setDialog( + pmLimitTimeDialog, ResUtil.getString(R.string.patriarch_help_limitenterroomhelper_01), tips, ResUtil.getString(R.string.patriarch_help_limitenterroomhelper_02), null, false, false, true, + () -> { + if (handle != null) { + handle.clickHandle(); + } + }, () -> { + if (handle != null) { + handle.clickHandle(); + } + }, true); + } catch (Exception ex) { + ex.printStackTrace(); + } + + } + + public void release() { + dismissDialog(); + } + + public void dismissDialog() { + if (pmLimitTimeDialog != null) { + pmLimitTimeDialog.dismiss(); + pmLimitTimeDialog = null; + } + } + + public interface OnDialogClickHandle { + void clickHandle(); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/patriarch/help/PmDialogShowMrg.java b/app/src/main/java/com/chwl/app/ui/patriarch/help/PmDialogShowMrg.java new file mode 100644 index 0000000..af07245 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/patriarch/help/PmDialogShowMrg.java @@ -0,0 +1,172 @@ +package com.chwl.app.ui.patriarch.help; + +import android.content.Context; +import android.text.TextUtils; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.initial.InitialModel; +import com.chwl.core.user.UserModel; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.core.utils.ActivityUtil; +import com.chwl.core.utils.SharedPreferenceUtils; +import com.chwl.core.utils.net.DontWarnObserver; +import com.chwl.core.utils.net.RxHelper; +import com.chwl.library.utils.TimeUtils; + +import java.lang.ref.WeakReference; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import io.reactivex.Single; +import io.reactivex.android.schedulers.AndroidSchedulers; +import lombok.Getter; +import lombok.Setter; + +/** + * create by lvzebiao @2019/7/27 + */ +public class PmDialogShowMrg { + + @Getter + private boolean hasShow; + + private final static String KEY_SAVE_PATRIARCH_MODE_STATUS = "key_save_patriarch_mode_status"; + + /** + * 家长模式引导 1-强 2- 弱 + */ + @Setter + @Getter + private int parentMode; + + private PmDialogShowMrg() { + hasShow = false; + } + + private static PmDialogShowMrg instance; + + public static PmDialogShowMrg get() { + if (instance == null) { + instance = new PmDialogShowMrg(); + } + return instance; + } + + private void show(Context context) { + if (!ActivityUtil.isValidContext(context)) { + return; + } + hasShow = true; +// new PatriarchModeDialog(context).show(); + saveCache(); + } + + /** + * 延迟弹框处理 + */ + public void handle(WeakReference reference) { + Context context = reference.get(); + if (context == null) { + return; + } + UserInfo userInfo = UserModel.get().getCacheLoginUserInfo(); + if (userInfo == null) { + return; + } + //开启过,就不用弹窗 + if (userInfo.isParentMode()) { + return; + } + Single.timer(15, TimeUnit.SECONDS, AndroidSchedulers.mainThread()) + .compose(RxHelper.bindContext(context)) + .subscribe(new DontWarnObserver() { + @Override + public void acceptThrowable(Long aLong, Throwable throwable) { + super.acceptThrowable(aLong, throwable); + if (throwable == null) { + handleCode(reference); + } + } + }); + } + + private void handleCode(WeakReference reference) { + Context context = reference.get(); + if (context == null) { + return; + } + if (hasShow || !ActivityUtil.isValidContext(context)) { + return; + } + long currUid = AuthModel.get().getCurrentUid(); + if (currUid <= 0) { + return; + } + Map map = cacheToMap(); + //判断该用户,今天是不是弹窗过了 + if (map == null) { + map = new HashMap<>(); + } + //如果弱引导,并且该uid已经存在缓存中,说明弹过一次,则不用再弹窗 + if (InitialModel.get().getTeenagerMode() == 2) { + if (map.containsKey(currUid)) { + hasShow = true; + return; + } + show(context); + return; + } + long currUidTime = 0L; + if (map.containsKey(currUid)) { + Long tmp = map.get(currUid); + if (tmp != null) { + currUidTime = tmp; + } + } + if (!TimeUtils.isTomorrow(currUidTime)) { + hasShow = true; + return; + } + show(context); + } + + public void onLogout() { + hasShow = false; + } + + public static void saveCache() { + Map map = cacheToMap(); + if (map == null) { + map = new HashMap<>(); + } + if (map.size() > 20) { + map.clear(); + } + map.put(AuthModel.get().getCurrentUid(), System.currentTimeMillis()); + try { + String json = new Gson().toJson(map); + if (!TextUtils.isEmpty(json)) { + SharedPreferenceUtils.put(KEY_SAVE_PATRIARCH_MODE_STATUS, json); + } + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + public static HashMap cacheToMap() { + try { + String cache = (String) SharedPreferenceUtils.get(KEY_SAVE_PATRIARCH_MODE_STATUS, ""); + if (!TextUtils.isEmpty(cache)) { + return new Gson().fromJson(cache, new TypeToken>() { + }.getType()); + } + } catch (Exception ex) { + ex.printStackTrace(); + } + return null; + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/pay/ChargeActivity.java b/app/src/main/java/com/chwl/app/ui/pay/ChargeActivity.java new file mode 100644 index 0000000..6366c89 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/pay/ChargeActivity.java @@ -0,0 +1,433 @@ +package com.chwl.app.ui.pay; + +import static com.chwl.core.pay.PayModel.RECHARGE_LIMIT; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.graphics.Color; +import android.os.Bundle; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.method.LinkMovementMethod; +import android.text.style.ForegroundColorSpan; +import android.util.Log; +import android.view.View; +import android.widget.CheckBox; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; +import androidx.recyclerview.widget.RecyclerView; + +import com.chwl.app.R; +import com.chwl.app.application.IReportConstants; +import com.chwl.app.application.ReportManager; +import com.chwl.app.base.BaseMvpActivity; +import com.chwl.app.common.widget.OriginalDrawStatusClickSpan; +import com.chwl.app.pay.presenter.ChargePresenter; +import com.chwl.app.pay.view.IChargeView; +import com.chwl.app.ui.im.avtivity.NimP2PMessageActivity; +import com.chwl.app.ui.setting.ModifyPwdActivity; +import com.chwl.app.ui.webview.CommonWebViewActivity; +import com.chwl.core.DemoCache; +import com.chwl.core.UriProvider; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.exception.FailReasonException; +import com.chwl.core.pay.PayModel; +import com.chwl.core.pay.bean.ChargeBean; +import com.chwl.core.pay.bean.WalletInfo; +import com.chwl.core.utils.net.IgnoreException; +import com.chwl.library.base.factory.CreatePresenter; +import com.chwl.library.utils.FormatUtils; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; +import com.example.module_base.support.billing.IBillingService; +import com.example.module_base.support.billing.IProductDetails; +import com.example.module_base.support.billing.IPurchase; +import com.example.module_base.support.google.IGoogleService; +import com.netease.nim.uikit.StatusBarUtil; + +import org.greenrobot.eventbus.EventBus; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * Created by MadisonRong on 05/01/2018. + * 充值页面 + */ +@CreatePresenter(ChargePresenter.class) +public class ChargeActivity extends BaseMvpActivity + implements IChargeView, IBillingService.Listener { + private static final String TAG = "ChargeActivity"; + + private TextView mTv_gold; + // private BannerViewPager mVpBanner; + private RecyclerView mRecyclerView; + private TextView mIvCharge; + private CheckBox mTvProtocol; + private TextView mTvProHint; + private ChargeAdapter mChargeAdapter; + + private final int BINDCODE_GOLD = 200; + + private IBillingService billingManager; + + private int mChargePosition = -1; + + private static final String NEED_CHECKED_CHARGE_PROTOCOL = "need_checked_charge_protocol"; + + public static void start(Context context) { + Intent intent = new Intent(context, ChargeActivity.class); + context.startActivity(intent); + } + + @SuppressLint("StringFormatMatches") + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_charge); + findView(); + EventBus.getDefault().register(this); + getDialogManager().showProgressDialog(this); + initViews(); + initBilling(); + setProtocol(); + getMvpPresenter().loadUserInfo(); + +// if (BuildConfig.DEBUG) { +// PayModel.get().getChargeList(1, AuthModel.get().getCurrentUid()) +// .compose(bindToLifecycle()) +// .subscribe(chargeListResult -> { +// mChargeAdapter.setNewData(chargeListResult.getList()); +// }); +// } + } + + private void findView() { + mTv_gold = findViewById(R.id.tv_gold); +// mVpBanner = findViewById(R.id.vp_banner); + mRecyclerView = findViewById(R.id.recyclerView); + mIvCharge = findViewById(R.id.tv_charge); + mTvProtocol = findViewById(R.id.tv_protocol); + mTvProHint = findViewById(R.id.tv_protocol_hint); + } + + protected void setProtocol() { + String privacyAgreementTip = context.getString(R.string.agreement); + String privacyAgreementDescTip = context.getString(R.string.text_login_charge_protocol, privacyAgreementTip); + SpannableString ss = new SpannableString(privacyAgreementDescTip); + int privacyAgreementTipIndex = privacyAgreementDescTip.indexOf(privacyAgreementTip); + + ss.setSpan(new ForegroundColorSpan(ContextCompat.getColor(context, R.color.color_8E8E8E)), privacyAgreementTipIndex, privacyAgreementTipIndex + privacyAgreementTip.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + ss.setSpan(new OriginalDrawStatusClickSpan(ContextCompat.getColor(context, R.color.color_AD89FF)) { + @Override + public void onClick(@NonNull View widget) { + if (widget instanceof TextView) + ((TextView) widget).setHighlightColor(getResources().getColor(android.R.color.transparent)); + + CommonWebViewActivity.start(context, UriProvider.getChargeAgreementUrl()); + } + }, privacyAgreementTipIndex, privacyAgreementTipIndex + privacyAgreementTip.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + + mTvProtocol.setText(ss); + mTvProtocol.setHighlightColor(Color.TRANSPARENT); + mTvProtocol.setMovementMethod(new LinkMovementMethod()); + + if (DemoCache.readBoolean(NEED_CHECKED_CHARGE_PROTOCOL, false)) { + mTvProtocol.setChecked(true); + } + + mTvProtocol.setOnCheckedChangeListener((buttonView, isChecked) -> { + if (isChecked) { + mTvProHint.setVisibility(View.GONE); + DemoCache.saveBoolean(NEED_CHECKED_CHARGE_PROTOCOL, true); + } + }); + + } + + @Override + protected void setStatusBar() { + super.setStatusBar(); + StatusBarUtil.transparencyBar(this); + StatusBarUtil.StatusBarLightMode(this); + } + + @Override + protected boolean needSteepStateBar() { + return true; + } + + /*初始化*/ + public void initBilling() { + billingManager = IGoogleService.Companion.newBillingService(this, this); + if (billingManager == null) { + toast(R.string.bean_response_serviceresult_015); + } + } + + /*客户端设置成功回调*/ + @SuppressLint("CheckResult") + @Override + public void onBillingClientSetupFinished() { + Log.i(TAG, "onBillingClientSetupFinished"); + PayModel.get().getChargeList(1, AuthModel.get().getCurrentUid()) + .compose(bindToLifecycle()) + .subscribe(chargeListResult -> initProduceList(chargeListResult.getList())); + } + + public void initProduceList(List chargeBeanList) { + final List productKeys = new ArrayList<>(); + for (ChargeBean chargeBean : chargeBeanList) { + productKeys.add(chargeBean.getChargeProdId()); + } + mChargeAdapter.setNewData(chargeBeanList); + if (billingManager == null) { + return; + } + billingManager.querySkuDetailsAsync(productKeys, (billingResult, productDetails) -> { + if (!billingResult.isResponseOk()) { + Log.w(TAG, "Unsuccessful query for Error code: " + billingResult.getResponseCode()); + getDialogManager().dismissDialog(); + toast(getString(R.string.Recharge_failure)); + } else if (productDetails.size() > 0) { + getDialogManager().dismissDialog(); + List showChargeList = new ArrayList<>(); + for (ChargeBean chargeBean : chargeBeanList) { + for (IProductDetails product : productDetails) { + if (product.getProductId().equals(chargeBean.getChargeProdId())) { + chargeBean.setProductDetails(product); + showChargeList.add(chargeBean); + break; + } + } + } + runOnUiThread(() -> mChargeAdapter.setNewData(showChargeList)); + } else { + Log.d(TAG, "initProduceList() 0"); + getDialogManager().dismissDialog(); + toast(getString(R.string.Recharge_failure)); + } + }); + } + + + /*商品更新回调*/ + @SuppressLint("CheckResult") + @Override + public void onPurchasesUpdated(@Nullable List purchases) { + Log.i(TAG, "onPurchasesUpdated"); + if (purchases == null) { + return; + } + for (IPurchase purchase : purchases) { + Log.d(TAG, "onPurchasesUpdated() purchase:" + purchase.getPurchaseState()); + if (purchase.isPurchasedState() && + purchase.getAccountIdentifiers() != null) { + Log.d(TAG, "onPurchasesUpdated() verifyOrder"); + PayModel.get().verifyOrder( + purchase.getAccountIdentifiers().getObfuscatedAccountId(), + purchase.getProducts().get(0), + purchase.getPackageName(), + purchase.getPurchaseToken()) + .compose(bindToLifecycle()) + .subscribe(token -> { + Log.d(TAG, "onPurchasesUpdated() verifyOrder success"); + billingManager.consumeAsync(token); + +// IProductDetails productDetails = null; +// for (ChargeBean datum : mChargeAdapter.getData()) { +// if (datum.getChargeProdId().equals(purchase.getProducts().get(0))) { +// productDetails = datum.getProductDetails(); +// break; +// } +// } +// if (productDetails != null) { +// Map eventValue = new HashMap<>(); +// eventValue.put(AFInAppEventParameterName.CONTENT_TYPE, "Gold"); +// eventValue.put(AFInAppEventParameterName.QUANTITY, 1); +// eventValue.put(AFInAppEventParameterName.CONTENT_ID, purchase.getOrderId()); +// if (productDetails.getOneTimePurchaseOfferDetails() != null) { +// eventValue.put(AFInAppEventParameterName.REVENUE, productDetails.getOneTimePurchaseOfferDetails().getPriceAmountMicros() / 1000000f); +// eventValue.put("Price", productDetails.getOneTimePurchaseOfferDetails().getFormattedPrice()); +// eventValue.put(AFInAppEventParameterName.CURRENCY, productDetails.getOneTimePurchaseOfferDetails().getPriceCurrencyCode()); +// } +// AppsFlyerLib.getInstance().logEvent(getApplicationContext(), AFInAppEventType.PURCHASE, eventValue); +// } + }, + throwable -> { + Log.d(TAG, "onPurchasesUpdated() verifyOrder throwable:"+throwable); + if (!(throwable instanceof IgnoreException)) { + SingleToastUtil.showToast(throwable.getMessage()); + } + }); + } + } + } + + @Override + public void onConsumeFinished(String token, int result) { + Log.d(TAG, "onConsumeFinished() " + result); + getMvpPresenter().loadUserInfo(); + } + + /*失败处理*/ + public void onFailedHandle(int result) { + Log.d(TAG, "onFailedHandle() " + result); + } + + /*购买商品*/ + @SuppressLint("CheckResult") + public void buyProduct(IProductDetails productDetails) { + Log.d(TAG, "buyProduct()"); + if (billingManager == null) { + Log.d(TAG, "buyProduct() null"); + return; + } + if (productDetails != null) { + Log.d(TAG, "buyProduct():" + productDetails.getProductId()); + PayModel.get().placeOrder(productDetails.getProductId()) + .compose(bindToLifecycle()) + .subscribe(recordId -> { + Log.d(TAG, "buyProduct() rid:" + recordId); + billingManager.initiatePurchaseFlow(productDetails, recordId.getRecordId()); + }, + throwable -> { + if (throwable instanceof FailReasonException) { + FailReasonException failReasonException = (FailReasonException) throwable; + if (failReasonException.getCode() == RECHARGE_LIMIT) { + getDialogManager().showOkDialog(failReasonException.getMessage(), ResUtil.getString(R.string.contact_customer_service), true, + () -> jumpContact()); + return; + } + } + SingleToastUtil.showToast(throwable.getMessage()); + }); + } else { + Log.w(TAG, "skuDetails ==null"); + + } + } + + @SuppressLint("CheckResult") + private void jumpContact() { + PayModel.get().getChargeContact() + .compose(bindToLifecycle()) + .subscribe(data -> NimP2PMessageActivity.start(this, data), + e -> toast(e.getMessage())); + } + + @Override + protected void onResume() { + super.onResume(); + if (billingManager != null && billingManager.isServiceConnected()) { + billingManager.onQueryPurchases(); + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + EventBus.getDefault().unregister(this); + if (billingManager != null) { + billingManager.destroy(); + } + getDialogManager().dismissDialog(); + } + + private void initViews() { + mChargeAdapter = new ChargeAdapter(); + mRecyclerView.setAdapter(mChargeAdapter); + mChargeAdapter.setOnItemClickListener((baseQuickAdapter, view, position) -> { + ChargeBean oldBean = mChargeAdapter.getItem(mChargePosition); + if (oldBean != null) { + oldBean.isSelected = false; + } + mChargeAdapter.notifyItemChanged(mChargePosition); + ChargeBean bean = mChargeAdapter.getItem(position); + if (bean != null) { + bean.isSelected = true; + } + mChargeAdapter.notifyItemChanged(position); + mChargePosition = position; + }); + mIvCharge.setOnClickListener(view -> { + if (!mTvProtocol.isChecked()) { + mTvProHint.setVisibility(View.VISIBLE); + return; + } + if (mChargePosition != -1) { + ChargeBean bean = mChargeAdapter.getItem(mChargePosition); + if (bean != null && bean.getProductDetails() != null) { + buyProduct(bean.getProductDetails()); + //点击充值 + HashMap map = new HashMap<>(3); + map.put(IReportConstants.MONEY, bean.money); + map.put(IReportConstants.MODULE, IReportConstants.MOLISTAR_PAY); + ReportManager.get().reportEvent(IReportConstants.PAY_CLICK, map); + } else { + toast(getString(R.string.Recharge_failure)); + } + } + }); + } + + @Override + public void initTitleBar() { + mTitleBar = findViewById(R.id.title_bar); + if (mTitleBar != null) { + mTitleBar.setTitle(getString(R.string.label_my_radish)); + mTitleBar.setImmersive(false); + mTitleBar.setTitleColor(getResources().getColor(R.color.color_000000)); + mTitleBar.setLeftImageResource(R.drawable.arrow_left); + mTitleBar.setBackgroundResource(R.color.transparent); + mTitleBar.setLeftClickListener(v -> finish()); + } + } + + @SuppressLint("SetTextI18n") + @Override + public void setupUserWalletBalance(WalletInfo walletInfo) { + mTv_gold.setText(FormatUtils.formatBigInteger(walletInfo.getDiamondNum())); + } + + @Override + public void getUserWalletInfoFail(String error) { + toast(error); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + //支付页面返回处理 + if (requestCode == BINDCODE_GOLD && resultCode == Activity.RESULT_OK) { + ModifyPwdActivity.start(this, ModifyPwdActivity.FOGERT_PAY_PWD); + } + } + +// @Override +// public void onLoadedBanners(List banners) { +// mVpBanner.setVisibility(View.VISIBLE); +// mVpBanner.setLifecycleRegistry(getLifecycle()) +// .setAdapter(new BaseBannerAdapter<>() { +// @Override +// protected void bindData(BaseViewHolder holder, Banner data, int position, int pageSize) { +// ImageView ivBanner = holder.findViewById(R.id.iv_banner); +// ImageLoadUtilsV2.loadImage(ivBanner, data.getBannerUrl()); +// ivBanner.setOnClickListener(v -> +// CommonWebViewActivity.start(ChargeActivity.this, data.getLinkUrl())); +// } +// +// @Override +// public int getLayoutId(int viewType) { +// return R.layout.item_banner_charge; +// } +// }) +// .create(banners); +// } +} diff --git a/app/src/main/java/com/chwl/app/ui/pay/ChargeAdapter.java b/app/src/main/java/com/chwl/app/ui/pay/ChargeAdapter.java new file mode 100644 index 0000000..4c06698 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/pay/ChargeAdapter.java @@ -0,0 +1,58 @@ +package com.chwl.app.ui.pay; + +import android.view.View; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.app.ui.bean.FirstRechargeInfo; +import com.chwl.app.ui.bean.LevelChargeBean; +import com.chwl.app.utils.LoginSuccessManager; +import com.chwl.core.pay.bean.ChargeBean; +import com.chwl.library.common.util.OtherExtKt; +import com.chwl.library.widget.text.DrawableTextView; + +import org.jetbrains.annotations.NotNull; + +/** + *

充值adapter

+ * Created by Administrator on 2017/11/20. + */ +public class ChargeAdapter extends BaseQuickAdapter { + public ChargeAdapter() { + super(R.layout.list_item_charge); + } + + @Override + protected void convert(@NotNull BaseViewHolder baseViewHolder, ChargeBean chargeBean) { + if (chargeBean == null) return; + baseViewHolder.getView(R.id.iv_selected).setVisibility(chargeBean.isSelected ? View.VISIBLE : View.GONE); + baseViewHolder.setText(R.id.tv_currency_value, chargeBean.getProdName()); + if (chargeBean.getProductDetails() != null && chargeBean.getProductDetails().getOneTimePurchaseOfferDetails() != null) { + baseViewHolder.setText(R.id.item_charge_money, chargeBean.getProductDetails().getOneTimePurchaseOfferDetails().getFormattedPrice()); + } else { + baseViewHolder.setText(R.id.item_charge_money, "USD$" + chargeBean.getMoney()); + } + + DrawableTextView tag = baseViewHolder.getView(R.id.firstRechargeTag); + if (tag != null) { + tag.setVisibility(View.GONE); + if (!LoginSuccessManager.Companion.getInstance().getMFirstRechargeStatus()) { + FirstRechargeInfo mFirstRechargeInfo = LoginSuccessManager.Companion.getInstance().getMFirstRechargeInfo(); + if (mFirstRechargeInfo != null && OtherExtKt.isVerify(mFirstRechargeInfo.levelCharge)) { + for (int i = 0; i < mFirstRechargeInfo.levelCharge.size(); i++) { + LevelChargeBean levelChargeBean = mFirstRechargeInfo.levelCharge.get(i); + if (levelChargeBean != null) { + if (chargeBean.getChargeGoldNum() == levelChargeBean.getExp()) { + tag.setVisibility(View.VISIBLE); + tag.setText("+ "+levelChargeBean.getAwardNum()); + } + } + } + } + } + } + } + + +} diff --git a/app/src/main/java/com/chwl/app/ui/praise/BezierEvaluator.java b/app/src/main/java/com/chwl/app/ui/praise/BezierEvaluator.java new file mode 100644 index 0000000..e4ca48d --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/praise/BezierEvaluator.java @@ -0,0 +1,32 @@ +package com.chwl.app.ui.praise; + +import android.animation.TypeEvaluator; +import android.graphics.PointF; + +/** + * @author lim lee + *

+ * 三阶贝塞尔曲线 + */ +public class BezierEvaluator implements TypeEvaluator { + + PointF pointF1; + PointF pointF2; + + public BezierEvaluator(PointF pointF1, PointF pointF2) { + this.pointF1 = pointF1; + this.pointF2 = pointF2; + } + + @Override + public PointF evaluate(float t, PointF pointF0, PointF pointF3) { + PointF pointF = new PointF(); + pointF.x = pointF0.x * (1 - t) * (1 - t) * (1 - t) + 3 * pointF1.x * t + * (1 - t) * (1 - t) + 3 * pointF2.x * t * t * (1 - t) + + pointF3.x * t * t * t; + pointF.y = pointF0.y * (1 - t) * (1 - t) * (1 - t) + 3 * pointF1.y * t + * (1 - t) * (1 - t) + 3 * pointF2.y * t * t * (1 - t) + + pointF3.y * t * t * t; + return pointF; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/praise/HPUtils.java b/app/src/main/java/com/chwl/app/ui/praise/HPUtils.java new file mode 100644 index 0000000..2c91cd9 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/praise/HPUtils.java @@ -0,0 +1,15 @@ +package com.chwl.app.ui.praise; + +import java.util.Random; + +public class HPUtils { + private static final Random RANDOM = new Random(); + + private HPUtils() { + } + + public static int rondomRange(int max, int min) { + return RANDOM.nextInt(max) + % (max - min + 1) + min; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/praise/HiPraise.java b/app/src/main/java/com/chwl/app/ui/praise/HiPraise.java new file mode 100644 index 0000000..6993a3e --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/praise/HiPraise.java @@ -0,0 +1,34 @@ +package com.chwl.app.ui.praise; + +import android.graphics.Bitmap; + +import com.chwl.app.ui.praise.base.IDrawable; +import com.chwl.app.ui.praise.base.IPraise; + +import java.util.Random; + +public class HiPraise implements IPraise { + protected Bitmap bitmap; + public float scale = 1.0f; + public float alpha = 1.0f; + public long duration; + public long startDelay; + public long delayAplhaTime; + + public HiPraise(Bitmap bitmap) { + this.bitmap = bitmap; + final int maxDuration = 2500; + final int minDuration = 2000; + int minDelayAlphaTime = minDuration / 4; + duration = HPUtils.rondomRange(maxDuration, minDuration); + delayAplhaTime = new Random().nextInt((int) duration) + % (duration - minDelayAlphaTime + 1) + minDelayAlphaTime; + } + + @Override + public IDrawable toDrawable() { + return new PraiseDrawable(bitmap, scale, + alpha, duration, startDelay, delayAplhaTime, 0.45f); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/praise/HiPraiseAnimationView.java b/app/src/main/java/com/chwl/app/ui/praise/HiPraiseAnimationView.java new file mode 100644 index 0000000..fa0a4f7 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/praise/HiPraiseAnimationView.java @@ -0,0 +1,172 @@ +package com.chwl.app.ui.praise; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.PixelFormat; +import android.os.Handler; +import android.os.Looper; +import android.os.SystemClock; +import android.util.AttributeSet; +import android.view.SurfaceHolder; +import android.view.SurfaceView; + +import com.chwl.app.ui.praise.base.IDrawTask; +import com.chwl.app.ui.praise.base.IDrawable; +import com.chwl.app.ui.praise.base.IPraise; +import com.chwl.app.ui.praise.base.IPraiseView; + + +public class HiPraiseAnimationView extends SurfaceView implements IPraiseView, SurfaceHolder.Callback { + private static final String TAG = HiPraiseAnimationView.class.getSimpleName(); + private static final int MAX_UPDATE_RATE = 25; //刷新频率 + private boolean mIsUpdateThreadStarted; + private volatile boolean mIsSurfaceCreated; + private IDrawTask mDrawTask; + private UpdateThread mUpdateThread; + private int mUpdateRate = MAX_UPDATE_RATE; + private boolean mIsAttached; + private int mSurfaceWidth; + private int mSurfaceHeight; + + public HiPraiseAnimationView(Context context) { + this(context, null); + } + + public HiPraiseAnimationView(Context context, AttributeSet attrs) { + super(context, attrs); + if (!isInEditMode()) { + setZOrderMediaOverlay(true); + setZOrderOnTop(true); + } + setWillNotCacheDrawing(true); + setDrawingCacheEnabled(false); + setWillNotDraw(true); + getHolder().setFormat(PixelFormat.TRANSPARENT);//透明背景 + getHolder().addCallback(this); + mDrawTask = new SimpleDrawTask(new Handler(Looper.getMainLooper())); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + mIsAttached = true; + mDrawTask.start(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + mIsAttached = false; + mDrawTask.stop(); + stop(); + } + + @Override + public void surfaceCreated(SurfaceHolder holder) { + mIsSurfaceCreated = true; + clearSurface(); + } + + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + mSurfaceWidth = width; + mSurfaceHeight = height; + } + + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + mIsSurfaceCreated = false; + } + + /** + * @return 绘制耗时 + */ + private long drawSurface() { + if (!mIsSurfaceCreated) { + return 0; + } + if (mSurfaceWidth == 0 + || mSurfaceHeight == 0) { + return 0; + } + if (!isShown()) { + mDrawTask.clearDrawable(); //清除绘制对象 + clearSurface(); + return 0; + } + final long startTime = SystemClock.uptimeMillis(); + Canvas canvas = getHolder().lockCanvas(); + if (null != canvas) { + mDrawTask.draw(canvas); //绘制点赞动画 + if (mIsSurfaceCreated) { + getHolder().unlockCanvasAndPost(canvas); + } + } + return SystemClock.uptimeMillis() - startTime; + } + + private void clearSurface() { + if (mIsSurfaceCreated) { + Canvas canvas = getHolder().lockCanvas(); + if (null != canvas) { + canvas.drawColor(Color.TRANSPARENT, + android.graphics.PorterDuff.Mode.CLEAR); + if (mIsSurfaceCreated) { + getHolder().unlockCanvasAndPost(canvas); + } + } + } + } + + public synchronized void start() { + if (mIsUpdateThreadStarted) return; + if (null == mUpdateThread) { + mUpdateThread = new UpdateThread("Update Thread") { + + @Override + public void run() { + try { + while (!isQuited() + && !Thread.currentThread().isInterrupted()) { + final long cost = mUpdateRate - drawSurface(); + if (isQuited()) { + break; + } + if (cost > 0) { + SystemClock.sleep(cost); + } + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + HiPraiseAnimationView.this.stop(); + } + } + }; + } + mIsUpdateThreadStarted = true; + mUpdateThread.start(); + } + + public synchronized void stop() { + mIsUpdateThreadStarted = false; + mDrawTask.clearDrawable(); + if (null != mUpdateThread) { + UpdateThread thread = mUpdateThread; + mUpdateThread = null; + thread.quit(); + thread.interrupt(); + } + } + + @Override + public void addPraise(IPraise praise) { + if (!mIsAttached + || !mIsUpdateThreadStarted) return; + final IDrawable drawable = praise.toDrawable(); + if (null != drawable) { + mDrawTask.addDrawable(drawable); + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/praise/HiPraiseWithCallback.java b/app/src/main/java/com/chwl/app/ui/praise/HiPraiseWithCallback.java new file mode 100644 index 0000000..1f996e6 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/praise/HiPraiseWithCallback.java @@ -0,0 +1,22 @@ +package com.chwl.app.ui.praise; + +import android.graphics.Bitmap; + +import com.chwl.app.ui.praise.base.IDrawable; + + +public class HiPraiseWithCallback extends HiPraise { + + private OnDrawCallback mOnDrawCallback; + + public HiPraiseWithCallback(Bitmap bitmap, OnDrawCallback onDrawCallback) { + super(bitmap); + mOnDrawCallback = onDrawCallback; + } + + @Override + public IDrawable toDrawable() { + return new PraiseWithCallbackDrawable(bitmap, scale, + alpha, duration, startDelay, delayAplhaTime, 0.45f, mOnDrawCallback); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/praise/OnDrawCallback.java b/app/src/main/java/com/chwl/app/ui/praise/OnDrawCallback.java new file mode 100644 index 0000000..9911dca --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/praise/OnDrawCallback.java @@ -0,0 +1,13 @@ +package com.chwl.app.ui.praise; + +/** + * Created by apple on 16/10/20. + */ +public interface OnDrawCallback { + + /** + * 主线程回调,不能在这里处理耗时的操作 + */ + void onFinish(); + +} diff --git a/app/src/main/java/com/chwl/app/ui/praise/PraiseDrawable.java b/app/src/main/java/com/chwl/app/ui/praise/PraiseDrawable.java new file mode 100644 index 0000000..d105bab --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/praise/PraiseDrawable.java @@ -0,0 +1,253 @@ +package com.chwl.app.ui.praise; + +import android.animation.FloatEvaluator; +import android.animation.TimeInterpolator; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.PointF; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.LinearInterpolator; + +import androidx.annotation.NonNull; + +import com.chwl.app.ui.praise.base.IDrawable; + +import java.util.Random; + +public class PraiseDrawable implements IDrawable { + private static final String TAG = PraiseDrawable.class.getSimpleName(); + private static final long MIN_END_POINTY = 16; + private Bitmap bitmap; + private Matrix mMatrix; + private Paint mPaint; + private PointF curPoint; + private PointF startPoint; + private PointF endPoint; + + private int bitmapWidth; + private int bitmapHeight; + private int canvasWidth; + private int canvasHeight; + + private float scale; + private float alpha; + private long duration; + private long startDelay; + private long startFrameTime; + private long startAplhaAnimTime; + private long endFrameTime; + private long delayAphaAnimTime; + private float endYPercentage; + + private BezierEvaluator xFrameEvaluator; + private FloatEvaluator mScaleEvaluator; + private FloatEvaluator mAlphaEvaluator; + private TimeInterpolator mFrameTimeInterpolator; + private TimeInterpolator mScaleTimeInterpolator; + private TimeInterpolator mAlphaTimeInterpolator; + private boolean isFinished; //是否绘制完成了 + private boolean isStarted; //是否开始绘制了 + + public PraiseDrawable(@NonNull Bitmap bitmap, + float scale, float alpha, long duration, long delay, + long delayAphaAnimTime, float endYPercentage) { + mMatrix = new Matrix(); + mPaint = new Paint(); + this.bitmap = bitmap; + this.endYPercentage = Math.min(Math.max(0, endYPercentage), 1); + + /** + * params + * + */ + this.scale = scale; + this.alpha = alpha; + this.duration = duration; + this.startDelay = delay; + this.delayAphaAnimTime = delayAphaAnimTime; + bitmapWidth = (int) (bitmap.getWidth() * scale); + bitmapHeight = (int) (bitmap.getHeight() * scale); + + + /** + * evaluator and interpolator + */ + + mScaleEvaluator = new FloatEvaluator(); + mAlphaEvaluator = new FloatEvaluator(); + mScaleTimeInterpolator = new LinearInterpolator(); + mFrameTimeInterpolator = new AccelerateInterpolator(0.8f); + mAlphaTimeInterpolator = new DecelerateInterpolator(0.5f); + } + + /** + * 绘制起点 + * + * @return + */ + private PointF genStartPoint() { + final float pointX = canvasWidth / 2; + float pointY; + if (bitmapHeight > canvasHeight) { + pointY = canvasHeight; + } else { + pointY = canvasHeight - bitmapHeight; + } + return new PointF(pointX, pointY); + } + + /** + * 绘制终点 + * + * @param point1 + * @param point2 + * @return + */ + private PointF genEndPoint(PointF point1, PointF point2) { + long tempEndY = getEndPointY(); + final float endX = (point1.x + point2.x) / 2; + final float endY = tempEndY; + return new PointF(endX, endY); + } + + /** + * 绘制最后的Y点,获取startPoint后调用 + * + * @return + */ + private long getEndPointY() { + long tempEndY = (long) (startPoint.y * endYPercentage); + if (tempEndY < MIN_END_POINTY) { + tempEndY = MIN_END_POINTY; + } + return tempEndY; + } + + private PointF genRandomPoint2() { + long tempEndY = getEndPointY(); + final float middel = startPoint.x; + final float minX = bitmapWidth / 2; + final int maxX = canvasWidth + bitmapWidth / 2; + float minY = (startPoint.y - tempEndY) / 3 + tempEndY; + final int maxY = (int) ((startPoint.y - tempEndY) / 3 * 2 + tempEndY); + float pointX; + while ((pointX = new Random().nextInt(maxX) % (maxX - minX + 1) + minX) == middel) { + } + final float pointY = new Random().nextInt(maxY) % (maxY - minY + 1) + + minY; + return new PointF(pointX, pointY); + } + + private PointF genRandomPoint1(PointF point2) { + long tempEndY = getEndPointY(); + final float middel = startPoint.x; + final float minX = bitmapWidth / 2; + final int maxX = canvasWidth + bitmapWidth / 2; + final float minY = tempEndY; + final int maxY = (int) ((startPoint.y - tempEndY) / 3 + tempEndY); + float pointX; + if (point2.x > middel) { + while ((pointX = new Random().nextInt(maxX) % (maxX - minX + 1) + + minX) >= middel) { + } + } else { + while ((pointX = new Random().nextInt(maxX) % (maxX - minX + 1) + + minX) <= middel) { + } + } + final float pointY = new Random().nextInt(maxY) % (maxY - minY + 1) + + minY; + return new PointF(pointX, pointY); + } + + @Override + public boolean isFinished() { + return isFinished; + } + + @Override + public void draw(Canvas canvas, long current) { + if (null == bitmap + || duration == 0 + || alpha == 0 + || scale == 0 + || startDelay >= duration) { + isFinished = true; + } + if (!isStarted) { + isStarted = true; + canvasWidth = canvas.getWidth(); + canvasHeight = canvas.getHeight(); + startFrameTime = current + startDelay; + startAplhaAnimTime = startFrameTime + delayAphaAnimTime; + endFrameTime = startFrameTime + duration; + startPoint = genStartPoint(); //动画开始位置 + curPoint = new PointF(startPoint.x, startPoint.y); + PointF point2 = genRandomPoint2(); + PointF point1 = genRandomPoint1(point2); + endPoint = genEndPoint(point1, point2); + xFrameEvaluator = new BezierEvaluator(point2, point1); + } + if (current < startFrameTime) return; + if (current >= endFrameTime) { + isFinished = true; + } + if (!isFinished + && isStarted) { + float fraction = (current - startFrameTime) / (float) duration; + PointF point = drawFrame(fraction, startPoint, endPoint); + mMatrix.setTranslate(curPoint.x = (point.x - bitmapWidth / 2), + curPoint.y = point.y); + float scale = drawScale(fraction); + mMatrix.preScale(scale, scale, bitmapWidth / 2, bitmapHeight); + mPaint.setAlpha((int) (alpha * 255)); + if (current >= startAplhaAnimTime) { + float alphaFraction = (current - startAplhaAnimTime) + / (float) (endFrameTime - startAplhaAnimTime); + mPaint.setAlpha((int) (drawAlpah(alphaFraction) * 255)); + } + canvas.drawBitmap(bitmap, mMatrix, mPaint); + } + } + + /** + * 绘制drawable的缩放 + * + * @param fraction + * @return + */ + private float drawScale(float fraction) { + float newFraction = 4.50f * fraction; + fraction = newFraction > 1 ? 1 : newFraction; + fraction = mScaleTimeInterpolator.getInterpolation(fraction); + return mScaleEvaluator.evaluate(fraction, 0.0f, this.scale); + } + + /** + * 绘制drawable的alpha值 + * + * @param fraction + * @return + */ + private float drawAlpah(float fraction) { + fraction = mAlphaTimeInterpolator.getInterpolation(fraction); + return mAlphaEvaluator.evaluate(fraction, this.alpha, 0.0f); + } + + /** + * 绘制drawable每一帧的移动位置 + * + * @param fraction + * @param start + * @param end + * @return + */ + private PointF drawFrame(float fraction, PointF start, PointF end) { + fraction = mFrameTimeInterpolator.getInterpolation(fraction); + return xFrameEvaluator.evaluate(fraction, start, end); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/praise/PraiseWithCallbackDrawable.java b/app/src/main/java/com/chwl/app/ui/praise/PraiseWithCallbackDrawable.java new file mode 100644 index 0000000..b6bae42 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/praise/PraiseWithCallbackDrawable.java @@ -0,0 +1,24 @@ +package com.chwl.app.ui.praise; + +import android.graphics.Bitmap; + +import androidx.annotation.NonNull; + + +public class PraiseWithCallbackDrawable extends PraiseDrawable implements OnDrawCallback { + + private OnDrawCallback mOnDrawCallback; + + public PraiseWithCallbackDrawable(@NonNull Bitmap bitmap, float scale, float alpha, long duration, + long delay, long delayAphaAnimTime, float endYPercentage, OnDrawCallback onDrawCallback) { + super(bitmap, scale, alpha, duration, delay, delayAphaAnimTime, endYPercentage); + mOnDrawCallback = onDrawCallback; + } + + @Override + public void onFinish() { + if (null != mOnDrawCallback) { + mOnDrawCallback.onFinish(); + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/praise/SimpleDrawTask.java b/app/src/main/java/com/chwl/app/ui/praise/SimpleDrawTask.java new file mode 100644 index 0000000..a837759 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/praise/SimpleDrawTask.java @@ -0,0 +1,131 @@ +package com.chwl.app.ui.praise; + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.RectF; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.SystemClock; + +import com.chwl.app.ui.praise.base.IDrawTask; +import com.chwl.app.ui.praise.base.IDrawable; + +import java.util.Iterator; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; + + +public class SimpleDrawTask implements IDrawTask { + private static final String TAG = SimpleDrawTask.class.getSimpleName(); + private static final int MAX_DRAWABLES = 128; //最多显示绘制对象 + private static RectF RECT = new RectF(); + private static Paint PAINT = new Paint(); + private int mDrawables = MAX_DRAWABLES; + private BlockingQueue mDrawableQueue; + private Handler mCallbackHandler; + private Handler mHandler; + private HandlerThread mHandlerThread; + private boolean mIsStarted; + + static { + PAINT.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); + PAINT.setColor(Color.TRANSPARENT); + } + + public SimpleDrawTask(Handler callbackHandler) { + mCallbackHandler = callbackHandler; + mDrawableQueue = new ArrayBlockingQueue<>(mDrawables); + } + + @Override + public void start() { + if (mIsStarted) return; + if (null == mHandlerThread) { + mHandlerThread = new HandlerThread("DrawTask HandlerThread"); + mHandlerThread.start(); + } + if (null == mHandler) { + mHandler = new Handler(mHandlerThread.getLooper()); + } + mIsStarted = true; + } + + @Override + public void stop() { + mIsStarted = false; + if (null != mCallbackHandler) { + mCallbackHandler.removeCallbacksAndMessages(null); + } + mHandler.removeCallbacksAndMessages(null); + HandlerThread handlerThread = mHandlerThread; + mHandlerThread = null; + handlerThread.quit(); + try { + handlerThread.join(10); + } catch (InterruptedException e) { + e.printStackTrace(); + } + handlerThread.interrupt(); + } + + @Override + public void draw(Canvas canvas) { + clearCanvas(canvas); + consumeDrawableQueue(canvas); + } + + private void clearCanvas(Canvas canvas) { + canvas.drawColor(Color.TRANSPARENT, + PorterDuff.Mode.CLEAR); + RECT.set(0, 0, canvas.getWidth(), canvas.getHeight()); + canvas.drawRect(RECT, PAINT); + } + + @Override + public void addDrawable(final IDrawable drawable) { + if (mIsStarted + && null != mHandler) { + mHandler.post(new Runnable() { + @Override + public void run() { + try { + mDrawableQueue.offer(drawable); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } + } + }); + } + } + + @Override + public void clearDrawable() { + mDrawableQueue.clear(); + } + + private void consumeDrawableQueue(Canvas canvas) { + Iterator drawableIterator = mDrawableQueue.iterator(); + while (drawableIterator.hasNext()) { + final IDrawable drawable = drawableIterator.next(); + if (null != drawable) { + long currentTime = SystemClock.uptimeMillis(); + drawable.draw(canvas, currentTime); + if (drawable.isFinished()) { + if (null != mCallbackHandler + && drawable instanceof OnDrawCallback) { + mCallbackHandler.post(new Runnable() { + @Override + public void run() { + ((OnDrawCallback) drawable).onFinish(); + } + }); + } + drawableIterator.remove(); + } + } + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/praise/UpdateThread.java b/app/src/main/java/com/chwl/app/ui/praise/UpdateThread.java new file mode 100644 index 0000000..a721565 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/praise/UpdateThread.java @@ -0,0 +1,26 @@ +package com.chwl.app.ui.praise; + +/** + * @author lim lee 2017/3/10 + */ +public class UpdateThread extends Thread { + volatile boolean mIsQuited; + + public UpdateThread(String name) { + super(name); + } + + public void quit() { + mIsQuited = true; + } + + public boolean isQuited() { + return mIsQuited; + } + + @Override + public void run() { + if (mIsQuited) return; + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/praise/base/IDrawTask.java b/app/src/main/java/com/chwl/app/ui/praise/base/IDrawTask.java new file mode 100644 index 0000000..fe9171c --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/praise/base/IDrawTask.java @@ -0,0 +1,17 @@ +package com.chwl.app.ui.praise.base; + +import android.graphics.Canvas; + +public interface IDrawTask { + + void start(); + + void stop(); + + void draw(Canvas canvas); + + void addDrawable(IDrawable drawable); + + void clearDrawable(); + +} diff --git a/app/src/main/java/com/chwl/app/ui/praise/base/IDrawable.java b/app/src/main/java/com/chwl/app/ui/praise/base/IDrawable.java new file mode 100644 index 0000000..b0e010e --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/praise/base/IDrawable.java @@ -0,0 +1,22 @@ +package com.chwl.app.ui.praise.base; + +import android.graphics.Canvas; + +public interface IDrawable { + + /** + * 是否已经绘制完成 + * + * @return + */ + boolean isFinished(); + + /** + * 如果绘制当前动画 + * + * @param canvas + * @param current 当前绘制的时间 + */ + void draw(Canvas canvas, long current); + +} diff --git a/app/src/main/java/com/chwl/app/ui/praise/base/IPraise.java b/app/src/main/java/com/chwl/app/ui/praise/base/IPraise.java new file mode 100644 index 0000000..39bfdcb --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/praise/base/IPraise.java @@ -0,0 +1,12 @@ +package com.chwl.app.ui.praise.base; + +public interface IPraise { + + /** + * 转换成可以绘制的对象 + * + * @return + */ + IDrawable toDrawable(); + +} diff --git a/app/src/main/java/com/chwl/app/ui/praise/base/IPraiseView.java b/app/src/main/java/com/chwl/app/ui/praise/base/IPraiseView.java new file mode 100644 index 0000000..25af210 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/praise/base/IPraiseView.java @@ -0,0 +1,12 @@ +package com.chwl.app.ui.praise.base; + +public interface IPraiseView { + + /** + * 添加一个点赞的对象,这个对象用来描述这个点赞的动画,但它并不是一个动画对象 + * + * @param praise + */ + void addPraise(IPraise praise); + +} diff --git a/app/src/main/java/com/chwl/app/ui/radish/RadishRecordFragment.java b/app/src/main/java/com/chwl/app/ui/radish/RadishRecordFragment.java new file mode 100644 index 0000000..5748780 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/radish/RadishRecordFragment.java @@ -0,0 +1,152 @@ +package com.chwl.app.ui.radish; + +import android.os.Bundle; +import android.text.TextUtils; + +import androidx.core.content.ContextCompat; +import androidx.fragment.app.Fragment; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chwl.app.R; +import com.chwl.app.bills.adapter.BillBaseAdapter; +import com.chwl.app.bills.fragmemt.BaseBillsFragment; +import com.chwl.app.radish.adapter.RadishRecordAdapter; +import com.chwl.app.radish.presenter.RadishRecordFrgPresenter; +import com.chwl.app.radish.view.IRadishRecordFrgView; +import com.chwl.app.ui.widget.RecyclerViewNoBugLinearLayoutManager; +import com.chwl.core.Constants; +import com.chwl.core.bills.bean.BillItemEntity; +import com.chwl.core.bills.bean.RadishRecordInfo; +import com.chwl.core.bills.bean.RadishRecordListInfo; +import com.chwl.library.base.factory.CreatePresenter; +import com.chwl.library.utils.ListUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@CreatePresenter(RadishRecordFrgPresenter.class) +public class RadishRecordFragment extends BaseBillsFragment implements IRadishRecordFrgView{ + + public static final byte TYPE_RADISH_EXPAND = 1; + public static final byte TYPE_RADISH_INCOME = 2; + private static final String TYPE = "type_radish"; + private BillBaseAdapter mAdapter; + + private byte mType = TYPE_RADISH_INCOME; + + public static Fragment newInstance(byte type) { + Fragment fragment = new RadishRecordFragment(); + Bundle bundle = new Bundle(); + bundle.putByte(TYPE, type); + fragment.setArguments(bundle); + return fragment; + } + + @Override + public void loadData() { + getMvpPresenter().getRadishRecord(mCurrentCounter, PAGE_SIZE, mTime, mType); + } + + private void firstLoadDate() { + mCurrentCounter = Constants.PAGE_START; + showLoading(); + loadData(); + } + + @Override + public void initiate() { + super.initiate(); + + setRlyDateBackground(ContextCompat.getColor(mContext, R.color.color_F8F9FB)); + Bundle bundle = getArguments(); + if (bundle != null) { + mType = bundle.getByte(TYPE, TYPE_RADISH_INCOME); + } + + mAdapter = new RadishRecordAdapter(mBillItemEntityList, mType); + mAdapter.setOnLoadMoreListener(new BaseQuickAdapter.RequestLoadMoreListener() { + @Override + public void onLoadMoreRequested() { + mCurrentCounter++; + loadData(); + } + }, mRecyclerView); + + RecyclerViewNoBugLinearLayoutManager manager = new RecyclerViewNoBugLinearLayoutManager(mContext); + mRecyclerView.setLayoutManager(manager); + mRecyclerView.setAdapter(mAdapter); + firstLoadDate(); + + } + + @Override + public void getRadishRecordSuccess(RadishRecordListInfo list) { + mRefreshLayout.setRefreshing(false); + if (null != list) { + if (mCurrentCounter == Constants.PAGE_START) { + hideStatus(); + mBillItemEntityList.clear(); + mAdapter.setNewData(mBillItemEntityList); + } else { + mAdapter.loadMoreComplete(); + } + List>> billList = list.getBillList(); + if (!billList.isEmpty()) { + int size = mBillItemEntityList.size(); + List billItemEntities = new ArrayList<>(); + BillItemEntity billItemEntity; + for (int i = 0; i < billList.size(); i++) { + Map> map = billList.get(i); + for (String key : map.keySet()) { + // key ---日期 value:list集合记录 + List incomeInfos = map.get(key); + if (ListUtils.isListEmpty(incomeInfos)) continue; + + //标题 + if (size > 0) { + BillItemEntity lastBillItem = mBillItemEntityList.get(size - 1); + //时间不一致才会添加标题 + if (!TextUtils.equals(lastBillItem.time, key)) { + billItemEntity = new BillItemEntity(BillItemEntity.ITEM_DATE, key); + billItemEntities.add(billItemEntity); + } + } else { + billItemEntity = new BillItemEntity(BillItemEntity.ITEM_DATE, key); + billItemEntities.add(billItemEntity); + } + + //正常item + for (RadishRecordInfo temp : incomeInfos) { + billItemEntity = new BillItemEntity(BillItemEntity.ITEM_NORMAL); + billItemEntity.mRadishRecordInfo = temp; + //目的是为了比较 + billItemEntity.time = key; + billItemEntities.add(billItemEntity); + } + } + } + if (billItemEntities.size() < Constants.BILL_PAGE_SIZE && mCurrentCounter == Constants.PAGE_START) { + mAdapter.setEnableLoadMore(false); + } + mAdapter.addData(billItemEntities); + } else { + if (mCurrentCounter == Constants.PAGE_START) { + showNoData(R.drawable.icon_common_failure, mContext.getString(R.string.tips_radish_record_empty)); + } else { + mAdapter.loadMoreEnd(true); + } + } + } + + } + + @Override + public void getRadishRecordFail(String message) { + if (mCurrentCounter == Constants.PAGE_START) { + showNetworkErr(); + } else { + mAdapter.loadMoreFail(); + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/relation/AttentionListActivity.java b/app/src/main/java/com/chwl/app/ui/relation/AttentionListActivity.java new file mode 100644 index 0000000..cce5d65 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/relation/AttentionListActivity.java @@ -0,0 +1,242 @@ +package com.chwl.app.ui.relation; + +import static com.chwl.app.R.id.swipe_refresh; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.netease.nim.uikit.StatusBarUtil; +import com.chwl.app.R; +import com.chwl.app.avroom.activity.AVRoomActivity; +import com.chwl.app.base.BaseActivity; +import com.chwl.app.common.NoDataFragment; +import com.chwl.app.ui.relation.adapter.AttentionListAdapter; +import com.chwl.app.ui.user.activity.UserInfoActivity; +import com.chwl.core.Constants; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.praise.event.PraiseEvent; +import com.chwl.core.user.AttentionModel; +import com.chwl.core.user.bean.AttentionInfo; +import com.chwl.library.utils.ListUtils; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.ArrayList; +import java.util.List; + +import io.reactivex.SingleObserver; +import io.reactivex.disposables.Disposable; + +/** + * 关注列表 + */ +public class AttentionListActivity extends BaseActivity { + + private RecyclerView mRecylcerView; + private SwipeRefreshLayout swipeRefreshLayout; + private AttentionListActivity mActivity; + private AttentionListAdapter adapter; + private List mAttentionInfoList = new ArrayList<>(); + + private int mPage = Constants.PAGE_START; + + public static void start(Context context) { + Intent intent = new Intent(context, AttentionListActivity.class); + context.startActivity(intent); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + EventBus.getDefault().unregister(this); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_list_attention); + initWhiteTitleBar(getString(R.string.my_attention)); + initView(); + setListener(); + initData(); + EventBus.getDefault().register(this); + } + + private void setListener() { + swipeRefreshLayout.setOnRefreshListener(onRefreshLisetener); + adapter = new AttentionListAdapter(mAttentionInfoList); + adapter.setRylListener(new AttentionListAdapter.onClickListener() { + @Override + public void rylListeners(AttentionInfo attentionInfo) { + UserInfoActivity.Companion.start(mActivity, attentionInfo.getUid()); + } + + @Override + public void findHimListeners(AttentionInfo attentionInfo) { + if (attentionInfo.getUserInRoom() != null) + AVRoomActivity.start(mActivity, attentionInfo.getUserInRoom().getUid()); + } + + @Override + public void sendListener(AttentionInfo attentionInfo) { + } + }); + adapter.setOnLoadMoreListener(new BaseQuickAdapter.RequestLoadMoreListener() { + @Override + public void onLoadMoreRequested() { + mPage++; + onRefreshing(); + } + }, mRecylcerView); + } + + private void initData() { + mRecylcerView.setAdapter(adapter); + showLoading(); + onRefreshing(); + } + + private void initView() { + mActivity = this; + mRecylcerView = findViewById(R.id.recyclerView); + swipeRefreshLayout = findViewById(swipe_refresh); + mRecylcerView.setLayoutManager(new LinearLayoutManager(mActivity)); + + } + + SwipeRefreshLayout.OnRefreshListener onRefreshLisetener = new SwipeRefreshLayout.OnRefreshListener() { + @Override + public void onRefresh() { + mPage = Constants.PAGE_START; + onRefreshing(); + } + }; + + private void onRefreshing() { + AttentionModel.get().getAttentionList( + AuthModel.get().getCurrentUid(), + mPage, + Constants.PAGE_SIZE + ) + .subscribe(new SingleObserver>() { + @Override + public void onSubscribe(Disposable d) { + mCompositeDisposable.add(d); + } + + @Override + public void onSuccess(List attentionInfos) { + onGetAttentionList(attentionInfos,mPage); + } + + @Override + public void onError(Throwable e) { + onGetAttentionListFail(e.getMessage(),mPage); + } + }); + } + + public void onGetAttentionList(List attentionInfoList, int page) { + mPage = page; + if (!ListUtils.isListEmpty(attentionInfoList)) { + if (mPage == Constants.PAGE_START) { + hideStatus(); + swipeRefreshLayout.setRefreshing(false); + mAttentionInfoList.clear(); + adapter.setNewData(attentionInfoList); + if (attentionInfoList.size() < Constants.PAGE_SIZE) { + adapter.setEnableLoadMore(false); + } + } else { + adapter.loadMoreComplete(); + adapter.addData(attentionInfoList); + } + } else { + if (mPage == Constants.PAGE_START) { + showNoData(R.drawable.icon_common_failure, getString(R.string.no_attention_text)); + } else { + adapter.loadMoreEnd(true); + } + + } + } + + @SuppressLint("ResourceType") + @Override + public void showNoData(int drawable, CharSequence charSequence) { + if (!checkActivityValid()) { + return; + } + + View status = findViewById(R.id.status_layout); + if (status == null || status.getId() <= 0) { + return; + } + NoDataFragment fragment = NoDataFragment.newInstance(R.layout.fragment_no_data_large_iv, drawable, charSequence); + fragment.setListener(getLoadListener()); + getSupportFragmentManager().beginTransaction().replace(status.getId(), fragment, STATUS_TAG).commitAllowingStateLoss(); + } + + public void onGetAttentionListFail(String error, int page) { + mPage = page; + if (mPage == Constants.PAGE_START) { + swipeRefreshLayout.setRefreshing(false); + showNetworkErr(); + } else { + adapter.loadMoreFail(); + toast(error); + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onCanceledPraise(PraiseEvent event) { +// long uid = event.getData(); +// List data = adapter.getData(); +// if (!ListUtils.isListEmpty(data)) { +// ListIterator iterator = data.listIterator(); +// for (; iterator.hasNext(); ) { +// AttentionInfo attentionInfo = iterator.next(); +// if (attentionInfo.isValid() && attentionInfo.getUid() == uid) { +// iterator.remove(); +// } +// } +// adapter.notifyDataSetChanged(); +// } + } + + @Override + public View.OnClickListener getLoadListener() { + return new View.OnClickListener() { + @Override + public void onClick(View v) { + mPage = Constants.PAGE_START; + showLoading(); + onRefreshing(); + } + }; + } + + @Override + protected boolean needSteepStateBar() { + return true; + } + + @Override + protected void setStatusBar() { + super.setStatusBar(); + StatusBarUtil.transparencyBar(this); + StatusBarUtil.StatusBarLightMode(this); + } +} + + diff --git a/app/src/main/java/com/chwl/app/ui/relation/FansListActivity.kt b/app/src/main/java/com/chwl/app/ui/relation/FansListActivity.kt new file mode 100644 index 0000000..f659843 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/relation/FansListActivity.kt @@ -0,0 +1,111 @@ +package com.chwl.app.ui.relation + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.view.View +import android.view.ViewGroup +import android.widget.LinearLayout +import android.widget.TextView +import androidx.core.content.ContextCompat +import androidx.fragment.app.Fragment +import com.chwl.app.R +import com.chwl.app.base.BaseActivity +import com.chwl.app.friend.action.AbstractSelectFriendAction +import com.chwl.app.home.fragment.AttentionFragment +import com.chwl.app.ui.im.friend.FriendListFragment +import com.chwl.app.ui.search.SearchActivity +import com.chwl.core.Constants +import com.netease.nim.uikit.StatusBarUtil + +/** + * 粉丝列表 + */ +class FansListActivity : BaseActivity() { + + companion object { + private const val KEY_TYPE = "key_type" + const val TYPE_FANS = "fans" + const val TYPE_ATTENTION = "attention" + const val TYPE_FRIEND = "Friend" + const val TYPE_CP = "relation_cp" + const val TYPE_DECORATION = "type_decoration" + + @JvmStatic + fun start(context: Context, type: String) { + val starter = Intent(context, FansListActivity::class.java) + starter.putExtra(KEY_TYPE, type) + context.startActivity(starter) + } + } + + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_fans) + val type = intent.getStringExtra(KEY_TYPE) ?: "" + when (type) { + TYPE_ATTENTION -> { + initWhiteTitleBar(getString(R.string.my_attention)) + commitF(AttentionFragment.newInstance(Constants.FAN_NO_MAIN_PAGE_TYPE)) + } + TYPE_FRIEND -> { + initWhiteTitleBar(getString(R.string.friend)) + commitF(FriendListFragment.newInstance(false, 0)) + } + + + TYPE_CP, TYPE_DECORATION -> { + val searchType = if (TYPE_CP == type) { + AbstractSelectFriendAction.TYPE_CP + } else { + AbstractSelectFriendAction.TYPE_SEND_DECORATION + } + initWhiteTitleBar(getString(R.string.title_select_friend)) + findViewById(R.id.layout_search)?.apply { + visibility = View.VISIBLE + setOnClickListener { + SearchActivity.start( + this@FansListActivity, + searchType + ) + } + findViewById(R.id.search_edit).setOnClickListener { + SearchActivity.start( + this@FansListActivity, + searchType + ) + } + } + commitF(FriendListFragment.newInstance(false, searchType)) + } + + + else -> { + findViewById(R.id.ll_background)?.apply { + background = + ContextCompat.getDrawable(this@FansListActivity, R.color.color_white) + } + initWhiteTitleBar(getString(R.string.fan)) + commitF(FansListFragment.newInstance(Constants.FAN_NO_MAIN_PAGE_TYPE)) + } + } + } + + private fun commitF(fragment: Fragment) { + supportFragmentManager.beginTransaction() + .add(R.id.fragment_container, fragment) + .commitAllowingStateLoss() + } + + override fun needSteepStateBar(): Boolean { + return true + } + + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/relation/FansListFragment.java b/app/src/main/java/com/chwl/app/ui/relation/FansListFragment.java new file mode 100644 index 0000000..2c51b80 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/relation/FansListFragment.java @@ -0,0 +1,282 @@ +package com.chwl.app.ui.relation; + +import static com.chwl.app.friend.action.AbstractSelectFriendAction.ROOM_MSG; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Context; +import android.os.Bundle; +import android.view.View; + +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import com.chwl.app.R; +import com.chwl.app.base.BaseFragment; +import com.chwl.app.common.NoDataFragment; +import com.chwl.app.friend.action.AbstractSelectFriendAction; +import com.chwl.app.friend.view.SelectFriendActivity; +import com.chwl.app.ui.relation.adapter.FansViewAdapter; +import com.chwl.app.ui.user.activity.UserInfoActivity; +import com.chwl.app.room_chat.activity.NimRoomP2PMessageActivity; +import com.chwl.core.Constants; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.im.friend.IMFriendModel; +import com.chwl.core.praise.PraiseModel; +import com.chwl.core.praise.event.PraiseEvent; +import com.chwl.core.user.AttentionModel; +import com.chwl.core.user.bean.FansInfo; +import com.chwl.core.user.bean.FansListInfo; +import com.chwl.core.user.event.LoginUserInfoUpdateEvent; +import com.chwl.core.utils.SystemUidUtil; +import com.chwl.library.utils.ListUtils; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.ArrayList; +import java.util.List; + +import io.reactivex.SingleObserver; +import io.reactivex.disposables.Disposable; + + +/** + * 粉丝列表 + * Created by chenran on 2017/10/2. + */ +public class FansListFragment extends BaseFragment { + private RecyclerView mRecyclerView; + private SwipeRefreshLayout mSwipeRefreshLayout; + private FansViewAdapter adapter; + private int mCurrentCounter = Constants.PAGE_START; + private List mFansInfoList = new ArrayList<>(); + private Context mContext; + private int mPageType; + private int type; + private SelectFriendActivity friendActivity; + + public static FansListFragment newInstanceForSelect(int type) { + FansListFragment fragment = new FansListFragment(); + Bundle bundle = new Bundle(); + bundle.putInt(AbstractSelectFriendAction.KEY_TYPE, type); + fragment.setArguments(bundle); + return fragment; + } + + public static FansListFragment newInstance(int pageType) { + FansListFragment fragment = new FansListFragment(); + Bundle bundle = new Bundle(); + bundle.putInt(Constants.KEY_PAGE_TYPE, pageType); + fragment.setArguments(bundle); + return fragment; + } + + @Override + protected void onInitArguments(Bundle bundle) { + super.onInitArguments(bundle); + if (bundle != null) { + mPageType = bundle.getInt(Constants.KEY_PAGE_TYPE); + type = bundle.getInt(AbstractSelectFriendAction.KEY_TYPE); + } + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + if (activity instanceof SelectFriendActivity) { + friendActivity = (SelectFriendActivity) activity; + } + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mContext = getContext(); + EventBus.getDefault().register(this); + } + + @Override + public void onDestroy() { + super.onDestroy(); + EventBus.getDefault().unregister(this); + } + + @Override + public void onFindViews() { + mRecyclerView = mView.findViewById(R.id.recycler_view); + mSwipeRefreshLayout = mView.findViewById(R.id.swipe_refresh); + } + + @Override + public void onSetListener() { + mRecyclerView.setLayoutManager(new LinearLayoutManager(mContext)); + adapter = new FansViewAdapter(mFansInfoList); + adapter.setType(type); + adapter.setOnLoadMoreListener(() -> { + mCurrentCounter++; + onRefreshing(); + }, mRecyclerView); + mRecyclerView.setAdapter(adapter); + mSwipeRefreshLayout.setOnRefreshListener(() -> { + mCurrentCounter = Constants.PAGE_START; + onRefreshing(); + }); + adapter.setRylListener(new FansViewAdapter.OnItemClickListener() { + @Override + public void onItemClick(FansInfo fansInfo) { + if (SystemUidUtil.isSystemUid(String.valueOf(fansInfo.getUid()))) { + return; + } + if (type == ROOM_MSG) { + NimRoomP2PMessageActivity.start(getActivity(), String.valueOf(fansInfo.getUid())); + } else { + UserInfoActivity.Companion.start(mContext, fansInfo.getUid()); + } + } + + @Override + public void onAttentionBtnClick(FansInfo fansInfo) { + if (!IMFriendModel.get().isMyFriend(String.valueOf(fansInfo.getUid()))) { + getDialogManager().showProgressDialog(mContext, getString(R.string.waiting_text)); + PraiseModel.get().praise(fansInfo.getUid(), true).subscribe(); + } + } + + @Override + public void sendListener(FansInfo attentionInfo) { + if (friendActivity != null) { + friendActivity.showSureDialog(String.valueOf(attentionInfo.getUid()), attentionInfo.getAvatar(), attentionInfo.getNick()); + } + } + }); + } + + + private void onRefreshing() { + AttentionModel.get().getFansList( + AuthModel.get().getCurrentUid(), + mCurrentCounter, + Constants.PAGE_SIZE + ).subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) { + mCompositeDisposable.add(d); + } + + @Override + public void onSuccess(FansListInfo fansListInfo) { + onGetMyFansList(fansListInfo, mPageType, mCurrentCounter); + } + + @Override + public void onError(Throwable e) { + onGetMyFansListFail(e.getMessage(), mPageType, mCurrentCounter); + } + }); + } + + @Override + public void initiate() { + mSwipeRefreshLayout.setRefreshing(true); + mCurrentCounter = Constants.PAGE_START; + onRefreshing(); + } + + @Override + public int getRootLayoutId() { + return R.layout.fragment_fans_list; + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onPraise(PraiseEvent event) { + getDialogManager().dismissDialog(); + if (event.isFailed()) { + toast(event.getError()); + return; + } + //该界面关注后,关注按钮消失,所有没有取消操作 + toast(getString(R.string.fan_success)); + } + + public void onGetMyFansList(FansListInfo fansListInfo, int pageType, int page) { + mCurrentCounter = page; + if (pageType == mPageType) { + mSwipeRefreshLayout.setRefreshing(false); + if (fansListInfo == null || ListUtils.isListEmpty(fansListInfo.getFansList())) { + //第一页 + if (mCurrentCounter == Constants.PAGE_START) { + if (adapter != null) { + mFansInfoList.clear(); + adapter.setNewData(mFansInfoList); + } + showNoData(R.drawable.icon_common_failure, getString(R.string.no_fan_text)); + } else { + adapter.loadMoreEnd(true); + } + } else { + hideStatus(); + if (mCurrentCounter == Constants.PAGE_START) { + mFansInfoList.clear(); + List fansList = fansListInfo.getFansList(); + mFansInfoList.addAll(fansList); + adapter.setNewData(mFansInfoList); + if (fansList.size() < Constants.PAGE_SIZE) { + adapter.setEnableLoadMore(false); + } + return; + } + adapter.loadMoreComplete(); + adapter.addData(fansListInfo.getFansList()); + } + } + } + + @SuppressLint("ResourceType") + @Override + public void showNoData(View view, int drawable, CharSequence charSequence) { + if (!checkActivityValid()) + return; + + if (view == null) { + return; + } + View status = view.findViewById(R.id.status_layout); + if (status == null || status.getId() <= 0) { + return; + } + NoDataFragment fragment = NoDataFragment.newInstance(R.layout.frg_no_data_large_iv_transparent, drawable, charSequence); + fragment.setListener(getLoadListener()); + getChildFragmentManager().beginTransaction().replace(status.getId(), fragment, STATUS_TAG).commitAllowingStateLoss(); + } + + public void onGetMyFansListFail(String error, int pageType, int page) { + mCurrentCounter = page; + if (pageType == mPageType) { + if (mCurrentCounter == Constants.PAGE_START) { + mSwipeRefreshLayout.setRefreshing(false); + showNetworkErr(); + } else { + adapter.loadMoreFail(); + toast(error); + } + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onLoginUserInfoUpdateEvent(LoginUserInfoUpdateEvent event) { + mCurrentCounter = Constants.PAGE_START; + onRefreshing(); + } + + @Override + public void onReloadData() { + super.onReloadData(); + mCurrentCounter = Constants.PAGE_START; + showLoading(); + onRefreshing(); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/relation/adapter/AttentionListAdapter.java b/app/src/main/java/com/chwl/app/ui/relation/adapter/AttentionListAdapter.java new file mode 100644 index 0000000..077fdb5 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/relation/adapter/AttentionListAdapter.java @@ -0,0 +1,146 @@ +package com.chwl.app.ui.relation.adapter; + +import android.text.TextUtils; +import android.view.View; +import android.widget.TextView; + +import androidx.appcompat.widget.AppCompatImageView; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.app.friend.action.AbstractSelectFriendAction; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.app.ui.widget.NobleAvatarView; +import com.chwl.app.vip.util.VipHelper; +import com.chwl.core.Constants; +import com.chwl.core.user.bean.AttentionInfo; +import com.chwl.library.common.util.OtherExtKt; + +import java.util.List; + +/** + *

关注列表

+ * Created by Administrator on 2017/11/17. + */ +public class AttentionListAdapter extends BaseQuickAdapter { + + private int type = AbstractSelectFriendAction.TYPE_NORMAL; + private onClickListener rylListener; + + public AttentionListAdapter(List attentionInfoList) { + super(R.layout.attention_item_new, attentionInfoList); + } + + public void setType(int type) { + this.type = type; + } + + @Override + protected void convert(BaseViewHolder baseViewHolder, final AttentionInfo attentionInfo) { + if (attentionInfo == null) return; + + + + + boolean isSend = (type == AbstractSelectFriendAction.TYPE_WEAR || + type == AbstractSelectFriendAction.TYPE_CAR); + baseViewHolder.setText(R.id.tv_userName, attentionInfo.getNick()) + .setText(R.id.tv_user_desc, attentionInfo.getUserDesc() != null ? + attentionInfo.getUserDesc() + : baseViewHolder.itemView.getContext().getResources().getString(R.string.msg_no_user_desc)) + .setGone(R.id.tv_find_him, VipHelper.showFind(attentionInfo.getUserVipInfoVO()) && (attentionInfo.getUserInRoom() != null && (type == AbstractSelectFriendAction.TYPE_NORMAL || type == Constants.FAN_NO_MAIN_PAGE_TYPE))) + .setOnClickListener(R.id.tv_find_him, v -> { + if (rylListener != null) + rylListener.findHimListeners(attentionInfo); + }) + .setOnClickListener(R.id.rly, v -> { + if (rylListener != null) + switch (type) { + case AbstractSelectFriendAction.ROOM_MSG: + case AbstractSelectFriendAction.TYPE_NORMAL: + rylListener.rylListeners(attentionInfo); + break; + + case AbstractSelectFriendAction.TYPE_SHARE: + case AbstractSelectFriendAction.TYPE_WORLD_DYNAMIC: + rylListener.sendListener(attentionInfo); + break; + + case Constants.FAN_NO_MAIN_PAGE_TYPE: + rylListener.rylListeners(attentionInfo); + break; + } + }); + +// GenderAgeTextView tvGenderAge = baseViewHolder.getView(R.id.tv_gender_age); +// tvGenderAge.setGender(attentionInfo.getGender()); +// tvGenderAge.setBirthDay(attentionInfo.getBirth()); + View vipIcon = baseViewHolder.getView(R.id.iv_vip_icon); + VipHelper.loadVipNameplate(baseViewHolder.getView(R.id.iv_vip_icon), attentionInfo.getUserVipInfoVO()); + VipHelper.loadVipNickColor(baseViewHolder.getView(R.id.tv_userName), attentionInfo.getUserVipInfoVO(), "#FF333333"); + +// baseViewHolder.getView(R.id.iv_user_official).setVisibility(attentionInfo.isOfficial() ? View.VISIBLE : View.GONE); + +// AppCompatImageView ivNobleLevel = baseViewHolder.getView(R.id.iv_noble_level); +// if (attentionInfo.nobleUsers != null) { +// ivNobleLevel.setVisibility(View.VISIBLE); +// String badgeByLevel = NobleUtil.getBadgeByLevel(attentionInfo.nobleUsers.getLevel()); +// if (!TextUtils.isEmpty(badgeByLevel)) { +// NobleUtil.loadResource(badgeByLevel, ivNobleLevel); +// } else { +// ivNobleLevel.setVisibility(View.GONE); +// } +// } else { +// ivNobleLevel.setVisibility(View.GONE); +// } + + NobleAvatarView nobleAvatarView = baseViewHolder.getView(R.id.noble_avatar_view); + nobleAvatarView.setSize(47, 65, 15); + nobleAvatarView.setData(attentionInfo.avatar, attentionInfo.nobleUsers); + + AppCompatImageView ivUserLevel = baseViewHolder.getView(R.id.iv_user_level); + ivUserLevel.setVisibility(View.GONE); + if (attentionInfo.userLevelVo != null && !TextUtils.isEmpty(attentionInfo.userLevelVo.getExperUrl())) { + ivUserLevel.setVisibility(View.VISIBLE); + ImageLoadUtils.loadImage(mContext, attentionInfo.userLevelVo.getExperUrl(), ivUserLevel); + } + + AppCompatImageView ivCharmLevel = baseViewHolder.getView(R.id.iv_charm_level); + ivCharmLevel.setVisibility(View.GONE); + if (attentionInfo.userLevelVo != null && !TextUtils.isEmpty(attentionInfo.userLevelVo.getCharmUrl())) { + ivCharmLevel.setVisibility(View.VISIBLE); + ImageLoadUtils.loadImage(mContext, attentionInfo.userLevelVo.getCharmUrl(), ivCharmLevel); + } + + + + View view = baseViewHolder.getView(R.id.userInfoLayout); + if (view != null) { + view.post(() -> { + int iconNum = 0; + if (vipIcon.getVisibility() == View.VISIBLE) iconNum++; + if (ivUserLevel.getVisibility() == View.VISIBLE) iconNum++; + if (ivCharmLevel.getVisibility() == View.VISIBLE) iconNum++; + + int width = view.getWidth(); + int i = width - OtherExtKt.toDP(42) * iconNum; + TextView textView = baseViewHolder.getView(R.id.tv_userName); + textView.setMaxWidth(i); + }); + } + + } + + public void setRylListener(onClickListener onClickListener) { + rylListener = onClickListener; + } + + public interface onClickListener { + void rylListeners(AttentionInfo attentionInfo); + + void findHimListeners(AttentionInfo attentionInfo); + + void sendListener(AttentionInfo attentionInfo); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/relation/adapter/FansViewAdapter.java b/app/src/main/java/com/chwl/app/ui/relation/adapter/FansViewAdapter.java new file mode 100644 index 0000000..eb06795 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/relation/adapter/FansViewAdapter.java @@ -0,0 +1,143 @@ +package com.chwl.app.ui.relation.adapter; + +import android.text.TextUtils; +import android.view.View; +import android.widget.TextView; + +import androidx.appcompat.widget.AppCompatImageView; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.app.friend.action.AbstractSelectFriendAction; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.app.ui.widget.NobleAvatarView; +import com.chwl.app.vip.util.VipHelper; +import com.chwl.core.im.friend.IMFriendModel; +import com.chwl.core.user.bean.FansInfo; +import com.chwl.library.common.util.OtherExtKt; +import com.chwl.library.utils.ResUtil; + +import java.util.List; + +/** + * @author chenran + * @date 2017/10/2 + */ +public class FansViewAdapter extends BaseQuickAdapter { + + private OnItemClickListener onItemClickListener; + private int type = AbstractSelectFriendAction.TYPE_NORMAL; + + public void setType(int type) { + this.type = type; + } + + public interface OnItemClickListener { + void onItemClick(FansInfo fansInfo); + + void onAttentionBtnClick(FansInfo fansInfo); + + void sendListener(FansInfo attentionInfo); + } + + public void setRylListener(OnItemClickListener onClickListener) { + onItemClickListener = onClickListener; + } + + public FansViewAdapter(List fansInfoList) { + super(R.layout.fans_list_item_new, fansInfoList); + } + + @Override + protected void convert(BaseViewHolder baseViewHolder, final FansInfo fansInfo) { + if (fansInfo == null) return; + baseViewHolder.setText(R.id.tv_userName, fansInfo.getNick()) + .setText(R.id.tv_user_desc, fansInfo.getUserDesc() != null ? + fansInfo.getUserDesc() + : baseViewHolder.itemView.getContext().getResources().getString(R.string.msg_no_user_desc)) +// .setVisible(R.id.view_line, baseViewHolder.getLayoutPosition() != getItemCount() - 1) + .setOnClickListener(R.id.rly, v -> { + if (onItemClickListener != null) { + switch (type) { + case AbstractSelectFriendAction.ROOM_MSG: + case AbstractSelectFriendAction.TYPE_NORMAL: + onItemClickListener.onItemClick(fansInfo); + break; + + case AbstractSelectFriendAction.TYPE_SHARE: + case AbstractSelectFriendAction.TYPE_WORLD_DYNAMIC: + onItemClickListener.sendListener(fansInfo); + break; + } + } + }) + .setOnClickListener(R.id.attention_img, v -> { + if (onItemClickListener != null) { + onItemClickListener.onAttentionBtnClick(fansInfo); + } + }); + + TextView tvAttention = baseViewHolder.getView(R.id.attention_img); + baseViewHolder.setVisible(R.id.attention_img, type == AbstractSelectFriendAction.TYPE_NORMAL); + if (IMFriendModel.get().isMyFriend(String.valueOf(fansInfo.getUid()))) { + tvAttention.setText(ResUtil.getString(R.string.relation_adapter_fansviewadapter_01)); + } else { + tvAttention.setText(ResUtil.getString(R.string.relation_adapter_fansviewadapter_02)); + } + +// GenderAgeTextView tvGenderAge = baseViewHolder.getView(R.id.tv_gender_age); +// tvGenderAge.setGender(fansInfo.getGender()); +// tvGenderAge.setBirthDay(fansInfo.getBirth()); + + View vipIcon = baseViewHolder.getView(R.id.iv_vip_icon); + VipHelper.loadVipNameplate(baseViewHolder.getView(R.id.iv_vip_icon), fansInfo.getUserVipInfoVO()); + VipHelper.loadVipNickColor(baseViewHolder.getView(R.id.tv_userName), fansInfo.getUserVipInfoVO(), "#FF333333"); + + // 官字 +// baseViewHolder.getView(R.id.iv_user_official).setVisibility(fansInfo.isOfficial() ? View.VISIBLE : View.GONE); + + NobleAvatarView nobleAvatarView = baseViewHolder.getView(R.id.noble_avatar_view); + nobleAvatarView.setSize(47, 65, 15); + nobleAvatarView.setData(fansInfo.getAvatar(), fansInfo.getNobleUsers()); + + AppCompatImageView ivUserLevel = baseViewHolder.getView(R.id.iv_user_level); + ivUserLevel.setVisibility(View.GONE); + if (fansInfo.getUserLevelVo() != null && !TextUtils.isEmpty(fansInfo.getUserLevelVo().getExperUrl())) { + ivUserLevel.setVisibility(View.VISIBLE); + ImageLoadUtils.loadImage(mContext, fansInfo.getUserLevelVo().getExperUrl(), ivUserLevel); + } + + AppCompatImageView ivCharmLevel = baseViewHolder.getView(R.id.iv_charm_level); + ivCharmLevel.setVisibility(View.GONE); + if (fansInfo.getUserLevelVo() != null && !TextUtils.isEmpty(fansInfo.getUserLevelVo().getCharmUrl())) { + ivCharmLevel.setVisibility(View.VISIBLE); + ImageLoadUtils.loadImage(mContext, fansInfo.getUserLevelVo().getCharmUrl(), ivCharmLevel); + } + +// AppCompatImageView ivBadge = baseViewHolder.getView(R.id.iv_noble_level); +// ivBadge.setVisibility(View.GONE); +// if (fansInfo.getNobleUsers() != null) { +// String badgeByLevel = NobleUtil.getBadgeByLevel(fansInfo.getNobleUsers().getLevel()); +// if (!TextUtils.isEmpty(badgeByLevel)) { +// ivBadge.setVisibility(View.VISIBLE); +// NobleUtil.loadResource(badgeByLevel, ivBadge); +// } +// } + + View view = baseViewHolder.getView(R.id.userInfoLayout); + if (view != null) { + view.post(() -> { + int iconNum = 0; + if (vipIcon.getVisibility() == View.VISIBLE) iconNum++; + if (ivUserLevel.getVisibility() == View.VISIBLE) iconNum++; + if (ivCharmLevel.getVisibility() == View.VISIBLE) iconNum++; + + int width = view.getWidth(); + int i = width - OtherExtKt.toDP(42) * iconNum; + TextView textView = baseViewHolder.getView(R.id.tv_userName); + textView.setMaxWidth(i); + }); + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/search/RoomHistoryAdapter.java b/app/src/main/java/com/chwl/app/ui/search/RoomHistoryAdapter.java new file mode 100644 index 0000000..54fbce3 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/search/RoomHistoryAdapter.java @@ -0,0 +1,41 @@ +package com.chwl.app.ui.search; + +import android.content.Context; + +import androidx.annotation.Nullable; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.app.common.widget.CircleImageView; +import com.chwl.app.ui.utils.ImageLoadUtilsV2; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.core.bean.RoomHistoryInfo; + +import java.util.List; + +public class RoomHistoryAdapter extends BaseQuickAdapter { + private Context mContext; + + public RoomHistoryAdapter(@Nullable List data, Context context) { + super(R.layout.item_room_history, data); + mContext = context; + } + + @Override + protected void convert(BaseViewHolder helper, RoomHistoryInfo item) { + if (item == null) { + return; + } + + CircleImageView circleImageView = helper.getView(R.id.civ_room_avatar); + ImageLoadUtilsV2.loadImage(circleImageView, item.getAvatar()); + circleImageView.setBorderWidth(UIUtil.dip2px(mContext,1)); + circleImageView.setBorderColor(mContext.getResources().getColor(R.color.appColor)); + + helper.setText(R.id.tv_room_name, item.getTitle()); + helper.setGone(R.id.iv_living, item.isValid()); + helper.addOnClickListener(R.id.container_item_room_history); + + } +} diff --git a/app/src/main/java/com/chwl/app/ui/search/SearchActivity.java b/app/src/main/java/com/chwl/app/ui/search/SearchActivity.java new file mode 100644 index 0000000..cef8053 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/search/SearchActivity.java @@ -0,0 +1,651 @@ +package com.chwl.app.ui.search; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.KeyEvent; +import android.view.View; +import android.view.inputmethod.EditorInfo; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.fragment.app.Fragment; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.viewpager.widget.ViewPager; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.netease.nim.uikit.StatusBarUtil; +import com.netease.nimlib.sdk.msg.model.IMMessage; +import com.chwl.app.R; +import com.chwl.app.avroom.activity.AVRoomActivity; +import com.chwl.app.base.BaseMvpActivity; +import com.chwl.app.common.ViewPagerAdapter; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.app.decoration.helper.DecorationDialogHelper; +import com.chwl.app.decoration.helper.DecorationSaleType; +import com.chwl.app.friend.action.AbstractSelectFriendAction; +import com.chwl.app.friend.view.SelectFriendActivity; +import com.chwl.app.home.adapter.ContactsIndicatorAdapter; +import com.chwl.app.ui.search.presenter.SearchPresenter; +import com.chwl.app.ui.search.view.ISearchView; +import com.chwl.app.ui.widget.magicindicator.MagicIndicator; +import com.chwl.app.ui.widget.magicindicator.ViewPagerHelper; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.CommonNavigator; +import com.chwl.app.ui.widget.recyclerview.decoration.VerticalDecoration; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.bean.RoomHistoryInfo; +import com.chwl.core.community.dynamic.DynamicModel; +import com.chwl.core.community.im.DynamicImMsg; +import com.chwl.core.community.im.WorldDynamicAttachment; +import com.chwl.core.decoration.car.bean.CarInfo; +import com.chwl.core.decoration.headwear.bean.HeadWearInfo; +import com.chwl.core.manager.IMNetEaseManager; +import com.chwl.core.relation.cp.CpBindUnbindEvent; +import com.chwl.core.room.bean.SearchRoomInfo; +import com.chwl.core.utils.SharedPreferenceUtils; +import com.chwl.core.utils.net.DontWarnObserver; +import com.chwl.library.base.factory.CreatePresenter; +import com.chwl.library.utils.ImeUtil; +import com.chwl.library.utils.JavaUtil; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; +import com.chwl.library.utils.SizeUtils; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.ArrayList; +import java.util.List; + +import io.reactivex.android.schedulers.AndroidSchedulers; + +/** + * 搜索界面 + * + * @author chenran + * @date 2017/10/3 + *

+ * jack 修改于 2018/5/2 + */ +@CreatePresenter(SearchPresenter.class) +public class SearchActivity extends BaseMvpActivity implements ISearchView, View.OnClickListener, ContactsIndicatorAdapter.OnItemSelectListener { + public static final int CODE_REQUEST_TO_SEARCH = 200; + private static final String MARK = "isCar"; + private static final String CAR_INFO = "carInfo"; + private static final String WEAR_INFO = "wearInfo"; + private static final String SHOW_HISTORY = "show_history"; + protected EditText searchEdit; + protected int type = AbstractSelectFriendAction.TYPE_NORMAL; + private ImageView ivBack; + private TextView tvSearch; + private ImageView ivClearText; + private View clSearchHistoryContainer; + private RecyclerView rvSearchHistory; + private View flClearSearchHistory; + private View clRoomHistoryContainer; + private RecyclerView rvRoomHistory; + private View flClearRoomHistory; + private MagicIndicator indicator; + private ViewPager viewPager; + private LinearLayout llSearchDetail; + private CarInfo carInfo; + private HeadWearInfo wearInfo; + private int secondOperator = -1; + private boolean mShowHistory = false; + + private SearchHistoryAdapter mSearchHistoryAdapter; + private RoomHistoryAdapter mRoomHistoryAdapter; + private List mSearchHistoryList = new ArrayList<>(20); + + private SearchDetailFragment roomFrg; + private SearchDetailFragment userFrg; + private TextWatcher textWatcher = new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + if (s.length() <= 0) { + ivClearText.setVisibility(View.GONE); + showHistory(); + } else { + ivClearText.setVisibility(View.VISIBLE); + } + } + }; + + public static void start(Context context, CarInfo carInfo) { + Intent intent = new Intent(context, SearchActivity.class); + intent.putExtra(AbstractSelectFriendAction.KEY_TYPE, AbstractSelectFriendAction.TYPE_CAR); + intent.putExtra(CAR_INFO, carInfo); + context.startActivity(intent); + } + + public static void start(Context context, HeadWearInfo wearInfo) { + Intent intent = new Intent(context, SearchActivity.class); + intent.putExtra(AbstractSelectFriendAction.KEY_TYPE, AbstractSelectFriendAction.TYPE_WEAR); + intent.putExtra(WEAR_INFO, wearInfo); + context.startActivity(intent); + } + + public static void start(Context context) { + start(context, AbstractSelectFriendAction.TYPE_NORMAL); + } + + public static void start(Context context, int type) { + Intent intent = new Intent(context, SearchActivity.class); + intent.putExtra(SHOW_HISTORY, true); + intent.putExtra(AbstractSelectFriendAction.KEY_TYPE, type); + context.startActivity(intent); + } + + public static void startForSharing(Activity activity, int shareType) { + Intent intent = new Intent(activity, SearchActivity.class); + intent.putExtra(AbstractSelectFriendAction.KEY_TYPE, AbstractSelectFriendAction.TYPE_SHARE); + intent.putExtra(SelectFriendActivity.KEY_SECOND_OPERATOR, shareType); + activity.startActivityForResult(intent, CODE_REQUEST_TO_SEARCH); + } + + public static void startForShareDynamic(Activity activity, DynamicImMsg msg) { + Intent intent = new Intent(activity, SearchActivity.class); + intent.putExtra(AbstractSelectFriendAction.KEY_TYPE, AbstractSelectFriendAction.TYPE_WORLD_DYNAMIC); + intent.putExtra(SelectFriendActivity.EXTRA_DYNAMIC_DATA, msg); + activity.startActivityForResult(intent, CODE_REQUEST_TO_SEARCH); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_search); + initView(); + initSearchDetail(); + initObserver(); + } + + private void initView() { + mShowHistory = getIntent().getBooleanExtra(SHOW_HISTORY, false); + + indicator = findViewById(R.id.indicator); + viewPager = findViewById(R.id.viewpager); + + type = getIntent().getIntExtra(AbstractSelectFriendAction.KEY_TYPE, AbstractSelectFriendAction.TYPE_NORMAL); + secondOperator = getIntent().getIntExtra(SelectFriendActivity.KEY_SECOND_OPERATOR, -1); + switch (type) { + case AbstractSelectFriendAction.TYPE_CAR: + carInfo = (CarInfo) getIntent().getSerializableExtra(CAR_INFO); + break; + + case AbstractSelectFriendAction.TYPE_WEAR: + wearInfo = (HeadWearInfo) getIntent().getSerializableExtra(WEAR_INFO); + break; + case AbstractSelectFriendAction.TYPE_CP: + case AbstractSelectFriendAction.TYPE_SEND_DECORATION: + indicator.setVisibility(View.GONE); + break; + } + + clSearchHistoryContainer = findViewById(R.id.cl_search_history_container); + rvSearchHistory = findViewById(R.id.rv_search_history); + flClearSearchHistory = findViewById(R.id.fl_clear_search_history); + flClearSearchHistory.setOnClickListener(this); + + clRoomHistoryContainer = findViewById(R.id.cl_room_history_container); + rvRoomHistory = findViewById(R.id.rv_room_history); + flClearRoomHistory = findViewById(R.id.fl_clear_room_history); + flClearRoomHistory.setOnClickListener(this); + + + searchEdit = findViewById(R.id.search_edit); + searchEdit.addTextChangedListener(textWatcher); + searchEdit.setImeOptions(EditorInfo.IME_ACTION_SEARCH); + searchEdit.setOnEditorActionListener(new TextView.OnEditorActionListener() { + @Override + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + if (actionId == EditorInfo.IME_ACTION_SEARCH || (event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) { + toSearch(); + return true; + } + return false; + + } + }); + + + ivBack = findViewById(R.id.iv_back); + ivBack.setOnClickListener(this); + + tvSearch = findViewById(R.id.tv_search); + tvSearch.setOnClickListener(this); + tvSearch.requestLayout(); + + ivClearText = findViewById(R.id.iv_clear_text); + ivClearText.setOnClickListener(this); + ivClearText.setVisibility(View.GONE); + + llSearchDetail = findViewById(R.id.ll_search_detail); + + if (mShowHistory) { + showSearchHistory(); + if (type != AbstractSelectFriendAction.TYPE_CP && + type != AbstractSelectFriendAction.TYPE_SEND_DECORATION) { + showRoomHistory(); + } + } + } + + private void initSearchDetail() { + + List mTabs = new ArrayList<>(); + //CP + if (type == AbstractSelectFriendAction.TYPE_CP || type == AbstractSelectFriendAction.TYPE_SEND_DECORATION) { + userFrg = SearchDetailFragment.newInstance(SearchDetailFragment.TYPE_SEARCH_USER, type); + mTabs.add(userFrg); + viewPager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager(), mTabs, null)); + return; + } +// llSearchDetail.setVisibility(View.GONE); + List mTabInfoList = new ArrayList<>(); + mTabInfoList.add(getString(R.string.search_room_tab)); + mTabInfoList.add(getString(R.string.search_user_tab)); + + roomFrg = SearchDetailFragment.newInstance(SearchDetailFragment.TYPE_SEARCH_ROOM); + userFrg = SearchDetailFragment.newInstance(SearchDetailFragment.TYPE_SEARCH_USER); + mTabs.add(roomFrg); + mTabs.add(userFrg); + ContactsIndicatorAdapter topMagicIndicatorAdapter = new ContactsIndicatorAdapter(this, mTabInfoList, 0); + topMagicIndicatorAdapter.setOnItemSelectListener(this); + CommonNavigator commonNavigator = new CommonNavigator(this); + commonNavigator.setAdjustMode(true); + commonNavigator.setAdapter(topMagicIndicatorAdapter); + indicator.setNavigator(commonNavigator); + // must after setNavigator + LinearLayout titleContainer = commonNavigator.getTitleContainer(); + titleContainer.setShowDividers(LinearLayout.SHOW_DIVIDER_MIDDLE); + + viewPager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager(), mTabs, null)); + ViewPagerHelper.bind(indicator, viewPager); + } + + @Override + public void onItemSelect(int position) { + viewPager.setCurrentItem(position); + } + + private void addHistory(String record) { + if (mShowHistory) { + for (String sub : mSearchHistoryList) { + if (sub.equals(record)) { + mSearchHistoryList.remove(record); + break; + } + } + + mSearchHistoryList.add(0, record); + while (mSearchHistoryList.size() > 20) { + mSearchHistoryList.remove(20); + } + mSearchHistoryAdapter.notifyDataSetChanged(); + } + } + + private void showSearchHistory() { + mSearchHistoryAdapter = new SearchHistoryAdapter(mSearchHistoryList); + rvSearchHistory.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)); + rvSearchHistory.addItemDecoration(new VerticalDecoration(SizeUtils.dp2px(this, 10), false, true)); + mSearchHistoryAdapter.setOnItemChildClickListener(new BaseQuickAdapter.OnItemChildClickListener() { + @Override + public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) { + List list = adapter.getData(); + if (position >= 0 && position < list.size()) { + String record = list.get(position); + searchEdit.setText(record); + + toSearch(); + } + } + }); + rvSearchHistory.setAdapter(mSearchHistoryAdapter); + + String strSearchHistory = (String) SharedPreferenceUtils.get(SharedPreferenceUtils.SEARCH_HISTORY + AuthModel.get().getCurrentUid(), + ""); + + if (TextUtils.isEmpty(strSearchHistory)) { + clSearchHistoryContainer.setVisibility(View.GONE); + } else { + clSearchHistoryContainer.setVisibility(View.VISIBLE); + String[] split = strSearchHistory.split(","); + + for (String sub : split) { + mSearchHistoryList.add(sub); + } + + mSearchHistoryAdapter.notifyDataSetChanged(); + } + } + + private void showRoomHistory() { + mRoomHistoryAdapter = new RoomHistoryAdapter(null, context); + rvRoomHistory.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)); + rvRoomHistory.addItemDecoration(new VerticalDecoration(SizeUtils.dp2px(this, 10), false, true)); + mRoomHistoryAdapter.setOnItemChildClickListener(new BaseQuickAdapter.OnItemChildClickListener() { + @Override + public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) { + List list = adapter.getData(); + if (position >= 0 && position < list.size()) { + ImeUtil.hideIME(SearchActivity.this, tvSearch); + RoomHistoryInfo record = list.get(position); + if (record.isValid()) { + list.remove(position); + list.add(0, record); + mRoomHistoryAdapter.setNewData(list); + } + AVRoomActivity.start(SearchActivity.this, record.getRoomUid()); + } + } + }); + rvRoomHistory.setAdapter(mRoomHistoryAdapter); + getMvpPresenter().getInRoomRecord(); + } + + @Override + public void update(List homeRooms) { + + } + + @Override + public void showToast(String msg) { + toast(msg); + } + + @Override + public void getInRoomRecordSuccess(List list) { + if (list != null && list.size() > 0) { + clRoomHistoryContainer.setVisibility(View.VISIBLE); + mRoomHistoryAdapter.setNewData(list); + + } else { + clRoomHistoryContainer.setVisibility(View.GONE); + } + + } + + @Override + public void getInRoomRecordFail(String error) { + clRoomHistoryContainer.setVisibility(View.GONE); + } + + @Override + public void deleteInRoomRecordSuccess() { + clRoomHistoryContainer.setVisibility(View.GONE); + } + + @Override + public void deleteInRoomRecordFail(String error) { + toast(error); + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.iv_back: + goBack(); + break; + + case R.id.tv_search: + toSearch(); + break; + + case R.id.iv_clear_text: + searchEdit.setText(""); + showHistory(); + break; + + case R.id.fl_clear_search_history: + getDialogManager().showOkCancelDialog(ResUtil.getString(R.string.ui_search_searchactivity_04), ResUtil.getString(R.string.ui_search_searchactivity_05), ResUtil.getString(R.string.ui_search_searchactivity_06), new DialogManager.OkCancelDialogListener() { + @Override + public void onOk() { + clearSearchHistory(); + } + }); + break; + + case R.id.fl_clear_room_history: + getDialogManager().showOkCancelDialog(ResUtil.getString(R.string.ui_search_searchactivity_07), ResUtil.getString(R.string.ui_search_searchactivity_08), ResUtil.getString(R.string.ui_search_searchactivity_09), new DialogManager.OkCancelDialogListener() { + @Override + public void onOk() { + getMvpPresenter().deleteInRoomRecord(); + } + }); + break; + } + + } + + private void goBack() { + if (mShowHistory && llSearchDetail.getVisibility() == View.VISIBLE) { + showHistory(); + return; + } + finish(); + } + + private void toSearch() { + String str = searchEdit.getText().toString().trim(); + if (TextUtils.isEmpty(str)) { + SingleToastUtil.showToastShort(ResUtil.getString(R.string.ui_search_searchactivity_010)); + showHistory(); + return; + } else { + clSearchHistoryContainer.setVisibility(View.GONE); + clRoomHistoryContainer.setVisibility(View.GONE); + } + addHistory(str); + ImeUtil.hideIME(this, tvSearch); + + starSearch(str); + } + + private void starSearch(String str) { + if (userFrg == null || roomFrg == null && + type != AbstractSelectFriendAction.TYPE_CP && + type != AbstractSelectFriendAction.TYPE_SEND_DECORATION) { + initSearchDetail(); + } + if (roomFrg != null) { + roomFrg.search(str, SearchDetailFragment.TYPE_SEARCH_ROOM); + } + userFrg.search(str, SearchDetailFragment.TYPE_SEARCH_USER); + if (llSearchDetail.getVisibility() != View.VISIBLE) { + llSearchDetail.setVisibility(View.VISIBLE); + } + } + + private void clearSearch() { + llSearchDetail.setVisibility(View.GONE); + if (roomFrg != null) { + roomFrg.clear(); + } + if (userFrg != null) { + userFrg.clear(); + } + } + + private void clearSearchHistory() { + clSearchHistoryContainer.setVisibility(View.GONE); + mSearchHistoryList.clear(); + mSearchHistoryAdapter.notifyDataSetChanged(); + SharedPreferenceUtils.put(SharedPreferenceUtils.SEARCH_HISTORY + AuthModel.get().getCurrentUid(), ""); + } + + public void showSureDialog(String targetId, String avatar, String nick) { + switch (type) { + case AbstractSelectFriendAction.TYPE_CAR: + if (carInfo == null) { + return; + } + long targetUid = JavaUtil.str2long(targetId); + DecorationDialogHelper.Options options = new DecorationDialogHelper.Builder() + .setTargetUid(targetUid) + .setNick(nick) + .setType(DecorationSaleType.SEND_CAR) + .setDecoration(carInfo) + .create(); + DecorationDialogHelper helper = new DecorationDialogHelper(context, getDialogManager(), + options); + helper.showBuyOrDonateDialog(); + break; + + case AbstractSelectFriendAction.TYPE_WEAR: + if (wearInfo == null) { + return; + } + targetUid = JavaUtil.str2long(targetId); + options = new DecorationDialogHelper.Builder() + .setTargetUid(targetUid) + .setNick(nick) + .setType(DecorationSaleType.SEND_HEAD_WEAR) + .setDecoration(wearInfo) + .create(); + helper = new DecorationDialogHelper(context, getDialogManager(), + options); + helper.showBuyOrDonateDialog(); + break; + + case AbstractSelectFriendAction.TYPE_SHARE: + String msg = ""; + if (SelectFriendActivity.CODE_REQUEST_TO_SHARE_FAMILY == secondOperator) { + msg = getResources().getString(R.string.family_invite_friends_slogan); + } + getDialogManager().showInAppSharingConfirmDialog(avatar, nick, msg, new DialogManager.OkCancelDialogListener() { + @Override + public void onCancel() { + } + + @Override + public void onOk() { + Intent intent = new Intent(); + intent.putExtra(SelectFriendActivity.EXTRA_TARGET_UID, targetId); + intent.putExtra(SelectFriendActivity.EXTRA_TARGET_NAME, nick); + setResult(Activity.RESULT_OK, intent); + finish(); + } + }); + break; + case AbstractSelectFriendAction.TYPE_WORLD_DYNAMIC: + DynamicImMsg dynamicImMsg = (DynamicImMsg) getIntent().getSerializableExtra( + SelectFriendActivity.EXTRA_DYNAMIC_DATA); + if (dynamicImMsg == null) { + return; + } + getDialogManager().showOkCancelDialog(ResUtil.getString(R.string.ui_search_searchactivity_011) + nick + "?", () -> { + //发出自定义消息 + IMMessage message = WorldDynamicAttachment.createShareMsg(dynamicImMsg, targetId); + IMNetEaseManager.get().sendMessage(message) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new DontWarnObserver() { + @Override + public void accept(Boolean aBoolean, String error) { + super.accept(aBoolean, error); + if (error != null) { + SingleToastUtil.showToast(error); + } else { + SingleToastUtil.showToast(ResUtil.getString(R.string.ui_search_searchactivity_012)); + DynamicModel.get().reportShare(dynamicImMsg.getPublishUid(), + dynamicImMsg.getWorldId(), dynamicImMsg.getDynamicId()) + .subscribe(); + } + } + }); + setResult(RESULT_OK); + finish(); + }); + break; + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (mShowHistory && mSearchHistoryList.size() > 0) { + StringBuilder builder = new StringBuilder(); + for (String sub : mSearchHistoryList) { + builder.append(sub); + builder.append(","); + } + + if (builder.length() > 0) { + builder.deleteCharAt(builder.length() - 1); + SharedPreferenceUtils.put(SharedPreferenceUtils.SEARCH_HISTORY + AuthModel.get().getCurrentUid(), builder.toString()); + } + + } + EventBus.getDefault().unregister(this); + } + + private void showHistory() { +// hideStatus(); + if (mShowHistory) { + clearSearch(); + clSearchHistoryContainer.setVisibility(mSearchHistoryList != null && mSearchHistoryList.size() > 0 ? + View.VISIBLE : View.GONE); + + if (mRoomHistoryAdapter != null) { + List roomHistoryInfos = mRoomHistoryAdapter.getData(); + clRoomHistoryContainer.setVisibility(roomHistoryInfos.size() > 0 ? + View.VISIBLE : View.GONE); + + } else { + clRoomHistoryContainer.setVisibility(View.GONE); + } + + } else { + clSearchHistoryContainer.setVisibility(View.GONE); + clRoomHistoryContainer.setVisibility(View.GONE); + } + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + goBack(); + } + return true; + } + + @Override + protected boolean needSteepStateBar() { + return true; + } + + @Override + protected void setStatusBar() { + super.setStatusBar(); + StatusBarUtil.transparencyBar(this); + StatusBarUtil.StatusBarLightMode(this); + } + + private void initObserver() { + EventBus.getDefault().register(this); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onCpMsgEvent(CpBindUnbindEvent event) { + if (searchEdit != null && !TextUtils.isEmpty(searchEdit.getText())) { + starSearch(searchEdit.getText().toString()); + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/search/SearchAdapter.java b/app/src/main/java/com/chwl/app/ui/search/SearchAdapter.java new file mode 100644 index 0000000..7e106c6 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/search/SearchAdapter.java @@ -0,0 +1,164 @@ +package com.chwl.app.ui.search; + +import static com.chwl.app.ui.search.SearchDetailFragment.TYPE_SEARCH_ROOM; + +import android.content.Context; +import android.text.TextUtils; +import android.view.View; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import androidx.core.content.ContextCompat; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.coorchice.library.SuperTextView; +import com.chwl.app.R; +import com.chwl.app.avroom.activity.AVRoomActivity; +import com.chwl.app.friend.action.AbstractSelectFriendAction; +import com.chwl.app.ui.user.activity.UserInfoActivity; +import com.chwl.app.ui.widget.NobleAvatarView; +import com.chwl.app.utils.RegexUtil; +import com.chwl.core.room.bean.SearchRoomInfo; +import com.chwl.core.user.UserModel; +import com.chwl.library.utils.ResUtil; +import com.netease.nim.uikit.common.util.sys.ScreenUtil; + +/** + * @author chenran + * @date 2017/10/3 + */ +public class SearchAdapter extends BaseQuickAdapter { + + private Context context; + private int searchType; + private int fromType; + + + public SearchAdapter(Context context, int searchType, int fromType) { + super(R.layout.list_item_search); + this.context = context; + this.searchType = searchType; + this.fromType = fromType; + } + + public void setType(int type) { + this.fromType = type; + } + + @Override + protected void convert(ViewHolder holder, SearchRoomInfo item) { + holder.ivLive.setVisibility(View.GONE); + holder.tvOnlineNum.setVisibility(View.GONE); + if (searchType == SearchDetailFragment.TYPE_SEARCH_USER) { + holder.userName.setText(item.getNick() != null ? item.getNick().replaceAll(RegexUtil.getNotPrintableStringReg(), "?") : ""); + holder.ivLive.setVisibility(item.getRoomUid() == 0 ? View.GONE : View.VISIBLE); + holder.container.setOnClickListener(v -> { + UserInfoActivity.Companion.start(context, item.getUid()); + }); + } else { + holder.userName.setText(item.getTitle() != null ? item.getTitle().replaceAll(RegexUtil.getNotPrintableStringReg(), "?") : ""); + holder.tvOnlineNum.setVisibility(View.VISIBLE); + holder.tvOnlineNum.setText(item.getOnlineNum() + ""); + holder.container.setOnClickListener(v -> { + AVRoomActivity.start(mContext, item.getUid()); + }); + } + + if (fromType == AbstractSelectFriendAction.TYPE_MODULE_HALL) { + //模厅搜索 + if (item.getHallBtnStatus() == 0) { + holder.stvOp.setVisibility(View.GONE); + } else if (item.getHallBtnStatus() == 4) { + holder.stvOp.setVisibility(View.VISIBLE); + holder.stvOp.setText(ResUtil.getString(R.string.ui_search_searchadapter_02)); + holder.stvOp.setTextColor(ContextCompat.getColor(context, R.color.base_color_theme_text)); + holder.stvOp.setBackground(ContextCompat.getDrawable(context, R.drawable.base_shape_theme_30dp)); + } else if (item.getHallBtnStatus() == 5) { + holder.stvOp.setVisibility(View.VISIBLE); + holder.stvOp.setText(ResUtil.getString(R.string.ready_pass)); + holder.stvOp.setTextColor(ContextCompat.getColor(context, R.color.color_B3B3C3)); + holder.stvOp.setBackground(ContextCompat.getDrawable(context, R.drawable.bg_e6e6f0_15)); + } else if (item.getHallBtnStatus() == 6) { + holder.stvOp.setVisibility(View.VISIBLE); + holder.stvOp.setText(ResUtil.getString(R.string.to_audit)); + holder.stvOp.setTextColor(ContextCompat.getColor(context, R.color.color_white)); + holder.stvOp.setBackground(ContextCompat.getDrawable(context, R.drawable.bg_ffbc51_15)); + } + holder.addOnClickListener(R.id.stv_op); + if (UserModel.get().isMyseft(item.getUid())) { + holder.stvOp.setVisibility(View.GONE); + } + } + //CP + else if (fromType == AbstractSelectFriendAction.TYPE_CP) { + holder.stvOp.setVisibility(View.VISIBLE); + final int cpState = item.getCpState(); + holder.stvOp.setText( + cpState == 1 ? context.getResources().getString(R.string.invite_cp_state_invited) : + cpState == 2 ? context.getResources().getString(R.string.has_cp) : + context.getResources().getString(R.string.invite_cp) + ); + holder.stvOp.setEnabled(cpState != 1 && cpState != 2); + holder.addOnClickListener(R.id.stv_op); + holder.stvOp.setBackground(context.getResources().getDrawable(R.drawable.bg_button_relation_invite)); + } else if (fromType == AbstractSelectFriendAction.TYPE_SEND_DECORATION) { + holder.stvOp.setVisibility(View.VISIBLE); + holder.stvOp.setText(ResUtil.getString(R.string.ui_search_searchadapter_03)); + holder.addOnClickListener(R.id.stv_op); + } else { + holder.stvOp.setVisibility(View.GONE); + } + + + holder.mNobleAvatarView.setSize(40, 58, 15); + if (searchType == TYPE_SEARCH_ROOM) { + //房间封面 要 方形 + ImageLoadUtils.loadRectImage(context, item.getAvatar(), holder.mNobleAvatarView.getIvAvatar(), R.drawable.default_avatar, ScreenUtil.dip2px(8)); + } else { + holder.mNobleAvatarView.setData(item.getAvatar(), item.nobleUsers); + } + holder.erbanNo.setText(context.getString(R.string.me_user_id, item.getErbanNo())); + + holder.wealthLevelView.setVisibility(View.GONE); + if (item.getUserLevelVo() != null && !TextUtils.isEmpty(item.getUserLevelVo().getExperUrl())) { + holder.wealthLevelView.setVisibility(View.VISIBLE); + ImageLoadUtils.loadImage(mContext, item.getUserLevelVo().getExperUrl(), holder.wealthLevelView); + } + + holder.charmLevelView.setVisibility(View.GONE); + if (item.getUserLevelVo() != null && !TextUtils.isEmpty(item.getUserLevelVo().getCharmUrl())) { + holder.charmLevelView.setVisibility(View.VISIBLE); + ImageLoadUtils.loadImage(mContext, item.getUserLevelVo().getCharmUrl(), holder.charmLevelView); + } + } + + static class ViewHolder extends BaseViewHolder { + TextView userName; + TextView roomTitle; + TextView erbanNo; + TextView tvOnlineNum; + private ImageView ivLive; + RelativeLayout container; + private NobleAvatarView mNobleAvatarView; + private ImageView wealthLevelView; + private ImageView charmLevelView; + private SuperTextView stvOp; + + public ViewHolder(View itemView) { + super(itemView); + userName = itemView.findViewById(R.id.user_name); + roomTitle = itemView.findViewById(R.id.room_title); + erbanNo = itemView.findViewById(R.id.erban_no); + container = itemView.findViewById(R.id.container); + mNobleAvatarView = itemView.findViewById(R.id.noble_avatar_view); + wealthLevelView = itemView.findViewById(R.id.iv_user_level); + charmLevelView = itemView.findViewById(R.id.iv_user_charm); + ivLive = itemView.findViewById(R.id.iv_living); + tvOnlineNum = itemView.findViewById(R.id.tv_online_num); + stvOp = itemView.findViewById(R.id.stv_op); + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/search/SearchDetailFragment.java b/app/src/main/java/com/chwl/app/ui/search/SearchDetailFragment.java new file mode 100644 index 0000000..e19907f --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/search/SearchDetailFragment.java @@ -0,0 +1,233 @@ +package com.chwl.app.ui.search; + +import android.os.Bundle; +import android.text.style.ForegroundColorSpan; + +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.chwl.app.R; +import com.chwl.app.avroom.widget.MessageView; +import com.chwl.app.base.BaseMvpFragment; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.app.decoration.helper.DecorationHelper; +import com.chwl.app.friend.action.AbstractSelectFriendAction; +import com.chwl.app.module_hall.HallDataManager; +import com.chwl.app.module_hall.hall.activity.HallSearchActivity; +import com.chwl.app.ui.im.avtivity.NimP2PMessageActivity; +import com.chwl.app.ui.im.friend.FriendFragmentCpDelegate; +import com.chwl.app.ui.search.presenter.SearchPresenter; +import com.chwl.app.ui.search.view.ISearchView; +import com.chwl.app.ui.widget.TextSpannableBuilder; +import com.chwl.core.bean.RoomHistoryInfo; +import com.chwl.core.module_hall.hall.HallModel; +import com.chwl.core.room.bean.SearchRoomInfo; +import com.chwl.core.utils.net.BeanObserver; +import com.chwl.core.utils.net.RxHelper; +import com.chwl.library.base.factory.CreatePresenter; +import com.chwl.library.utils.JavaUtil; +import com.chwl.library.utils.ResUtil; + +import java.util.List; + +@CreatePresenter(SearchPresenter.class) +public class SearchDetailFragment extends BaseMvpFragment implements ISearchView { + + public static final int TYPE_SEARCH_ROOM = 1; + public static final int TYPE_SEARCH_USER = 2; + private RecyclerView recyclerView; + private SearchAdapter searchAdapter; + private long hallId; + private int mType; + private int fromType; + private FriendFragmentCpDelegate cpDelegate; + + + public static SearchDetailFragment newInstance(int type) { + Bundle args = new Bundle(); + args.putInt("type", type); + SearchDetailFragment fragment = new SearchDetailFragment(); + fragment.setArguments(args); + return fragment; + } + + public static SearchDetailFragment newInstance(int type, int fromType) { + Bundle args = new Bundle(); + args.putInt("type", type); + args.putInt("fromType", fromType); + SearchDetailFragment fragment = new SearchDetailFragment(); + fragment.setArguments(args); + return fragment; + } + + public static SearchDetailFragment newInstance(long hallId, int type, int fromType) { + Bundle args = new Bundle(); + args.putLong("hallId", hallId); + args.putInt("type", type); + args.putInt("fromType", fromType); + SearchDetailFragment fragment = new SearchDetailFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Override + public void onDestroy() { + super.onDestroy(); + } + + @Override + public void onFindViews() { + recyclerView = mView.findViewById(R.id.recycler_view); + +// initData(); + } + + @Override + public void onSetListener() { + + } + + @Override + public void initiate() { + if (getArguments() != null) { + mType = getArguments().getInt("type"); + fromType = getArguments().getInt("fromType"); + hallId = getArguments().getLong("hallId"); + } + initData(); + } + + private void initData() { + recyclerView.setLayoutManager(new LinearLayoutManager(mContext)); + searchAdapter = new SearchAdapter(mContext, mType, fromType); + searchAdapter.setType(fromType); + searchAdapter.setOnItemChildClickListener((adapter, view, position) -> { + SearchRoomInfo item = (SearchRoomInfo) adapter.getData().get(position); + if (fromType == AbstractSelectFriendAction.TYPE_CP) { + long targetUid = JavaUtil.str2long(item.getUid() + ""); + if (cpDelegate == null) { + cpDelegate = new FriendFragmentCpDelegate(this); + } + cpDelegate.inviteCp(targetUid); + } + if (fromType == AbstractSelectFriendAction.TYPE_SEND_DECORATION) { + DecorationHelper.showBuyDialog(mContext, + getDialogManager(), + item.getNick(), + item.getUid()); + } else { + if (item.getHallBtnStatus() == 5) { + toast(getString(R.string.invite_has_been_send)); + } else if (item.getHallBtnStatus() == 6) { + NimP2PMessageActivity.startRecord(mContext, String.valueOf(item.getHallMessageUid()), String.valueOf(item.getHallRecordId())); + } else if (item.getHallBtnStatus() == 4) { + showSureDialog(item.getUid() + "", item.getAvatar(), item.getNick(), position); + } + } + }); + recyclerView.setAdapter(searchAdapter); + } + + public void showSureDialog(String targetId, String avatar, String nick, int position) { + if (fromType == AbstractSelectFriendAction.TYPE_MODULE_HALL) { + if (nick == null) { + nick = ""; + } + long targetUid = JavaUtil.str2long(targetId); + TextSpannableBuilder text = new TextSpannableBuilder(null); + text.append(ResUtil.getString(R.string.ui_search_searchdetailfragment_01)) + .append(nick, new ForegroundColorSpan(getResources().getColor(R.color.color_9168FA))) + .append(ResUtil.getString(R.string.ui_search_searchdetailfragment_02)) + .append(HallDataManager.get().getHallName(), + new ForegroundColorSpan(getResources().getColor(R.color.color_9168FA))) + .append(ResUtil.getString(R.string.ui_search_searchdetailfragment_03)); + getDialogManager().showOkCancelDialog(text.build(), new DialogManager.OkCancelDialogListener() { + @Override + public void onCancel() { + + } + + @Override + public void onOk() { + HallModel.get().inviteMember(hallId, targetUid) + .compose(RxHelper.bindActivity((HallSearchActivity) getActivity())) + .subscribe(new BeanObserver() { + @Override + public void onErrorMsg(String error) { + toast(error); + } + + @Override + public void onSuccess(String s) { + searchAdapter.getData().get(position).setHallBtnStatus(5); + searchAdapter.notifyItemChanged(position); + toast(s); + } + }); + } + }); + } + } + + public void search(String str, int type) { + getMvpPresenter().searchRooms(str, type); + } + + public void clear() { + if (searchAdapter == null) { + return; + } + searchAdapter.setNewData(null); + searchAdapter.notifyDataSetChanged(); + } + + @Override + public void update(List homeRooms) { + if (homeRooms != null && homeRooms.size() > 0) { + hideStatus(); + searchAdapter.setNewData(homeRooms); + searchAdapter.notifyDataSetChanged(); + } else { + searchAdapter.setNewData(null); + showNoData(R.drawable.icon_common_failure, getString(R.string.dearch_no_data)); + searchAdapter.notifyDataSetChanged(); + } + } + + @Override + public int getRootLayoutId() { + return R.layout.fragment_search_detail; + } + + @Override + public void showToast(String msg) { + + } + + @Override + public void getInRoomRecordSuccess(List list) { + + } + + @Override + public void getInRoomRecordFail(String error) { + + } + + @Override + public void deleteInRoomRecordSuccess() { + + } + + @Override + public void deleteInRoomRecordFail(String error) { + + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/search/SearchHallActivity.java b/app/src/main/java/com/chwl/app/ui/search/SearchHallActivity.java new file mode 100644 index 0000000..b6e6560 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/search/SearchHallActivity.java @@ -0,0 +1,282 @@ +package com.chwl.app.ui.search; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.KeyEvent; +import android.view.View; +import android.view.inputmethod.EditorInfo; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.fragment.app.Fragment; +import androidx.viewpager.widget.ViewPager; +import androidx.viewpager2.widget.ViewPager2; + +import com.chwl.app.avroom.adapter.CommonVPAdapter; +import com.netease.nim.uikit.StatusBarUtil; +import com.chwl.app.R; +import com.chwl.app.base.BaseMvpActivity; +import com.chwl.app.common.ViewPagerAdapter; +import com.chwl.app.friend.action.AbstractSelectFriendAction; +import com.chwl.app.friend.view.SelectFriendActivity; +import com.chwl.app.home.adapter.ContactsIndicatorAdapter; +import com.chwl.app.ui.search.presenter.SearchPresenter; +import com.chwl.app.ui.search.view.ISearchView; +import com.chwl.app.ui.widget.magicindicator.MagicIndicator; +import com.chwl.app.ui.widget.magicindicator.ViewPagerHelper; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.CommonNavigator; +import com.chwl.core.bean.RoomHistoryInfo; +import com.chwl.core.room.bean.SearchRoomInfo; +import com.chwl.library.base.factory.CreatePresenter; +import com.chwl.library.utils.ImeUtil; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; + +import java.util.ArrayList; +import java.util.List; + +/** + * 搜索界面 + * + * @author chenran + * @date 2017/10/3 + *

+ * jack 修改于 2018/5/2 + */ +@CreatePresenter(SearchPresenter.class) +public class SearchHallActivity extends BaseMvpActivity implements ISearchView, View.OnClickListener, ContactsIndicatorAdapter.OnItemSelectListener { + private static final String SHOW_HISTORY = "show_history"; + + public static final int CODE_REQUEST_TO_SEARCH = 200; + protected EditText searchEdit; + private ImageView ivBack; + private TextView tvSearch; + private ImageView ivClearText; + private MagicIndicator indicator; + private ViewPager2 viewPager; + private LinearLayout llSearchDetail; + protected int type = AbstractSelectFriendAction.TYPE_NORMAL; + private long hallId; + private int secondOperator = -1; + + private SearchDetailFragment userFrg ; + + public static void start(Context context) { + Intent intent = new Intent(context, SearchActivity.class); + intent.putExtra(SHOW_HISTORY, true); + context.startActivity(intent); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_search_hall); + initView(); + initSearchDetail(); + } + + private void initView() { + type = getIntent().getIntExtra(AbstractSelectFriendAction.KEY_TYPE, AbstractSelectFriendAction.TYPE_NORMAL); + hallId = getIntent().getLongExtra("hallId",0); + secondOperator = getIntent().getIntExtra(SelectFriendActivity.KEY_SECOND_OPERATOR,-1); + searchEdit = findViewById(R.id.search_edit); + searchEdit.addTextChangedListener(textWatcher); + searchEdit.setImeOptions(EditorInfo.IME_ACTION_SEARCH); + searchEdit.setOnEditorActionListener(new TextView.OnEditorActionListener() { + @Override + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + if (actionId == EditorInfo.IME_ACTION_SEARCH || (event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) { + toSearch(); + return true; + } + return false; + + } + }); + + + ivBack = findViewById(R.id.iv_back); + ivBack.setOnClickListener(this); + + tvSearch = findViewById(R.id.tv_search); + tvSearch.setOnClickListener(this); + + ivClearText = findViewById(R.id.iv_clear_text); + ivClearText.setOnClickListener(this); + ivClearText.setVisibility(View.GONE); + + llSearchDetail = findViewById(R.id.ll_search_detail); + + indicator = findViewById(R.id.indicator); + viewPager = findViewById(R.id.viewpager); + } + + private void initSearchDetail(){ +// llSearchDetail.setVisibility(View.GONE); + List mTabInfoList = new ArrayList<>(); + mTabInfoList.add(getString(R.string.search_room_tab)); + mTabInfoList.add(getString(R.string.search_user_tab)); + + List mTabs = new ArrayList<>(); + userFrg = SearchDetailFragment.newInstance(hallId,SearchDetailFragment.TYPE_SEARCH_USER,AbstractSelectFriendAction.TYPE_MODULE_HALL); + mTabs.add(userFrg); + ContactsIndicatorAdapter topMagicIndicatorAdapter = new ContactsIndicatorAdapter(this, mTabInfoList,0); + topMagicIndicatorAdapter.setOnItemSelectListener(this); + CommonNavigator commonNavigator = new CommonNavigator(this); + commonNavigator.setAdjustMode(true); + commonNavigator.setAdapter(topMagicIndicatorAdapter); + indicator.setNavigator(commonNavigator); + // must after setNavigator + LinearLayout titleContainer = commonNavigator.getTitleContainer(); + titleContainer.setShowDividers(LinearLayout.SHOW_DIVIDER_MIDDLE); + + viewPager.setAdapter(new CommonVPAdapter(getSupportFragmentManager(), getLifecycle(), mTabs)); + ViewPagerHelper.bind(indicator, viewPager); + } + + + + @Override + public void onItemSelect(int position) { + viewPager.setCurrentItem(position); + } + + private TextWatcher textWatcher = new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + if (s.length()<=0) { + ivClearText.setVisibility(View.GONE); + showHistory(); + } else { + ivClearText.setVisibility(View.VISIBLE); + } + } + }; + + + @Override + public void update(List homeRooms) { + + } + + @Override + public void showToast(String msg) { + toast(msg); + } + + @Override + public void getInRoomRecordSuccess(List list) { + if (list != null && list.size() > 0) { + } + + } + + @Override + public void getInRoomRecordFail(String error) { + } + + @Override + public void deleteInRoomRecordSuccess() { + } + + @Override + public void deleteInRoomRecordFail(String error) { + toast(error); + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.iv_back: + goBack(); + break; + + case R.id.tv_search: + toSearch(); + break; + + case R.id.iv_clear_text: + searchEdit.setText(""); + showHistory(); + break; + } + + } + + private void goBack() { + finish(); + } + + private void toSearch() { + String str = searchEdit.getText().toString(); + if (TextUtils.isEmpty(str)) { + SingleToastUtil.showToastShort(ResUtil.getString(R.string.ui_search_searchhallactivity_01)); + showHistory(); + return; + } + ImeUtil.hideIME(this, tvSearch); + + starSearch(str); + } + private void starSearch(String str){ + if (userFrg == null){ + initSearchDetail(); + } + userFrg.search(str,SearchDetailFragment.TYPE_SEARCH_USER); + llSearchDetail.setVisibility(View.VISIBLE); + } + + private void clearSearch(){ + llSearchDetail.setVisibility(View.GONE); + if (userFrg == null){return;} + userFrg.clear(); + } + + + + @Override + protected void onDestroy() { + super.onDestroy(); + + } + + private void showHistory() { +// hideStatus(); + clearSearch(); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + goBack(); + } + return true; + } + + @Override + protected boolean needSteepStateBar() { + return true; + } + + @Override + protected void setStatusBar() { + super.setStatusBar(); + StatusBarUtil.transparencyBar(this); + StatusBarUtil.StatusBarLightMode(this); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/search/SearchHistoryAdapter.java b/app/src/main/java/com/chwl/app/ui/search/SearchHistoryAdapter.java new file mode 100644 index 0000000..96f58bf --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/search/SearchHistoryAdapter.java @@ -0,0 +1,32 @@ +package com.chwl.app.ui.search; + +import android.text.TextUtils; + +import androidx.annotation.Nullable; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; + +import java.util.List; + +public class SearchHistoryAdapter extends BaseQuickAdapter { + + public SearchHistoryAdapter(@Nullable List data) { + super(R.layout.item_search_history, data); + } + + @Override + protected void convert(BaseViewHolder helper, String item) { + if (TextUtils.isEmpty(item)) { + return; + } + + if (item.length() < 15) { + helper.setText(R.id.tv_search_history, item); + } else { + helper.setText(R.id.tv_search_history, item.substring(0, 14) + "..."); + } + helper.addOnClickListener(R.id.tv_search_history); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/search/SearchUserActivity.kt b/app/src/main/java/com/chwl/app/ui/search/SearchUserActivity.kt new file mode 100644 index 0000000..2513c41 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/search/SearchUserActivity.kt @@ -0,0 +1,158 @@ +package com.chwl.app.ui.search + +import android.content.Context +import android.content.Intent +import androidx.core.widget.doOnTextChanged +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.bindadapter.BaseBindingAdapter +import com.chwl.app.bindadapter.BaseBindingViewHolder +import com.chwl.app.common.EmptyViewHelper +import com.chwl.app.databinding.ActivitySearchUserBinding +import com.chwl.app.databinding.ItemSearchUserBinding +import com.chwl.app.decoration.ui.DressUpDialog +import com.chwl.app.ui.utils.loadAvatar +import com.chwl.core.bean.response.ServiceResult +import com.chwl.core.decoration.bean.DressUpInfo +import com.chwl.core.im.friend.IMFriendModel +import com.chwl.core.room.bean.SearchRoomInfo +import com.chwl.core.user.UserModel +import com.chwl.core.user.bean.UserInfo +import com.chwl.core.utils.net.RxHelper +import com.chwl.library.common.util.doToast +import com.chwl.library.common.util.isVerify +import com.chwl.library.net.rxnet.RxNet +import com.example.lib_utils.ktx.getString +import com.google.gson.Gson +import io.reactivex.Single +import retrofit2.http.GET +import retrofit2.http.Query + +class SearchUserActivity : BaseViewBindingActivity() { + + companion object{ + + fun start(context: Context, data:String) { + val intent = Intent(context, SearchUserActivity::class.java) + intent.putExtra("json",data) + context.startActivity(intent) + } + } + + private var mDressUpInfo : DressUpInfo? = null + private val mJson : String by lazy { intent.getStringExtra("json")?:"" } + lateinit var mAdapter : UserAdapter + override fun transparencyBar() = true + + + override fun init() { + initDarkTitleBar(R.string.search.getString()) + + if (mJson.isVerify()) { + mDressUpInfo = Gson().fromJson(mJson,DressUpInfo::class.java) + } + + mAdapter= UserAdapter() + binding.rvList.layoutManager = GridLayoutManager(context,1,RecyclerView.VERTICAL,false) + binding.rvList.adapter = mAdapter + mAdapter.setEmptyView(EmptyViewHelper.createEmptyTextViewHeight(context,R.string.no_frenids_text.getString())) + + mAdapter.setOnItemChildClickListener { adapter, view, position -> + + when (view.id) { + R.id.btnGive -> { + val uid = mAdapter?.data?.getOrNull(position)?.uid + if (uid != null && mDressUpInfo != null) { + val dressUpDialog = DressUpDialog() + dressUpDialog.mDressUpInfo = mDressUpInfo + dressUpDialog.mTargetUid = uid + dressUpDialog.show(context) + } + } + else -> {} + } + } + + binding.etSearch.doOnTextChanged { text, start, before, count -> + text?.let { + doSearch(text.toString()) + } + } + + loadFriends() + + } + + private fun loadFriends() { + val accounts = IMFriendModel.get().myFriendsAccounts + if (accounts.isVerify()) { + UserModel.get().loadUserInfoByUids(accounts) + .compose(bindToLifecycle()) + .doOnSuccess { + mAdapter.setNewData(it) + } + .doOnError { + it?.message?.doToast() + }.subscribe() + } + } + + private fun doSearch(key: String) { + roomSearch(key) + .compose(bindToLifecycle()) + .doOnSuccess { + if (it.isVerify()) { + val newData = mutableListOf() + it.forEach { + newData.add(UserInfo().apply { + avatar = it.avatar + uid = it.uid + erbanNo = it.erbanNo + nick = it.nick + }) + mAdapter.setNewData(newData) + } + } + }.doOnError { + it?.message?.doToast() + }.subscribe() + } + + + + + class UserAdapter : BaseBindingAdapter() { + + override fun convert(helper: BaseBindingViewHolder, item: UserInfo) { + helper.binding.let { + it.avatar.loadAvatar(item.avatar) + it.name.text = item.nick + it.id.text = "ID: ${item.erbanNo}" + + helper.addOnClickListener(it.btnGive.id) + } + } + } + + private fun roomSearch(key: String) : Single>{ + return api.roomSearch(key,2) + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()) + } + + private val api: Api = RxNet.create(Api::class.java); + + interface Api { + @GET("/search/room") + fun roomSearch( + @Query("key") key: String?, + @Query("type") type: Int + ): Single>> + } + + + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/search/event/SearchEvent.java b/app/src/main/java/com/chwl/app/ui/search/event/SearchEvent.java new file mode 100644 index 0000000..2dae37b --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/search/event/SearchEvent.java @@ -0,0 +1,10 @@ +package com.chwl.app.ui.search.event; + +public class SearchEvent { + public String inPutText; + public SearchEvent(String str) { + this.inPutText = str; + } + + +} diff --git a/app/src/main/java/com/chwl/app/ui/search/presenter/SearchPresenter.java b/app/src/main/java/com/chwl/app/ui/search/presenter/SearchPresenter.java new file mode 100644 index 0000000..ca06247 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/search/presenter/SearchPresenter.java @@ -0,0 +1,111 @@ +package com.chwl.app.ui.search.presenter; + +import android.annotation.SuppressLint; +import android.os.Bundle; + +import androidx.annotation.Nullable; + +import com.chwl.app.R; +import com.chwl.app.base.BaseMvpPresenter; +import com.chwl.app.ui.search.view.ISearchView; +import com.chwl.core.room.bean.SearchRoomInfo; +import com.chwl.core.room.model.AvRoomModel; +import com.chwl.core.user.UserModel; +import com.chwl.library.utils.NetworkUtils; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.config.BasicConfig; + +import java.util.List; + +/** + * @author jack + * @Description + * @Date 2018/5/2 + */ + +public class SearchPresenter extends BaseMvpPresenter { + + + public SearchPresenter() { + + } + + @Override + public void onCreatePresenter(@Nullable Bundle saveState) { + super.onCreatePresenter(saveState); + + } + + private void onSearchRoom(List homeRooms) { + getMvpView().update(homeRooms); + } + + private void onSearchRoomFail(String msg) { + if (NetworkUtils.isNetworkAvailable(BasicConfig.INSTANCE.getAppContext())) { + getMvpView().showToast(msg); + getMvpView().showNoData(); + } else { + getMvpView().showNetworkErr(); + } + } + + /** + * 搜索房间 + * @param str + */ + @SuppressLint("CheckResult") + public void searchRooms(String str,int type) { + AvRoomModel.get() + .roomSearch(str,type) + .compose(bindToLifecycle()) + .subscribe((homeTabResult, throwable) -> { + if (throwable != null) { + onSearchRoomFail(throwable.getMessage()); + } else if (homeTabResult != null && homeTabResult.isSuccess()) { + onSearchRoom(homeTabResult.getData()); + } else if (homeTabResult != null && !homeTabResult.isSuccess()){ + onSearchRoomFail(homeTabResult.getError()); + } else { + onSearchRoomFail(ResUtil.getString(R.string.search_presenter_searchpresenter_01)); + } + }); + } + + @SuppressLint("CheckResult") + public void getInRoomRecord() { + UserModel.get() + .getInRoomRecord() + .compose(bindToLifecycle()) + .subscribe((homeTabResult, throwable) -> { + if (throwable != null) { + if (mMvpView != null) { + mMvpView.getInRoomRecordFail(throwable.getMessage()); + } + } else { + if (mMvpView != null) { + mMvpView.getInRoomRecordSuccess(homeTabResult); + } + } + }); + } + + @SuppressLint("CheckResult") + public void deleteInRoomRecord() { + UserModel.get() + .deleteInRoomRecord() + .compose(bindToLifecycle()) + .subscribe((homeTabResult, throwable) -> { + if (homeTabResult.isSuccess()) { + if (mMvpView != null) { + mMvpView.deleteInRoomRecordSuccess(); + } + + } else { + if (mMvpView != null) { + mMvpView.deleteInRoomRecordFail(homeTabResult.getError()); + } + + } + }); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/search/view/ISearchView.java b/app/src/main/java/com/chwl/app/ui/search/view/ISearchView.java new file mode 100644 index 0000000..c0f05f4 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/search/view/ISearchView.java @@ -0,0 +1,30 @@ +package com.chwl.app.ui.search.view; + +import com.chwl.core.bean.RoomHistoryInfo; +import com.chwl.core.room.bean.SearchRoomInfo; +import com.chwl.library.base.IMvpBaseView; + +import java.util.List; + +/** + * @author jack + * @Description + * @Date 2018/5/2 + */ + +public interface ISearchView extends IMvpBaseView { + + void update(List homeRooms); + + void showNoData(); + + void showNetworkErr(); + + void showToast(String msg); + + void getInRoomRecordSuccess(List list); + void getInRoomRecordFail(String error); + + void deleteInRoomRecordSuccess(); + void deleteInRoomRecordFail(String error); +} diff --git a/app/src/main/java/com/chwl/app/ui/setting/GrantedPermissionsActivity.kt b/app/src/main/java/com/chwl/app/ui/setting/GrantedPermissionsActivity.kt new file mode 100644 index 0000000..a1ef56c --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/setting/GrantedPermissionsActivity.kt @@ -0,0 +1,103 @@ +package com.chwl.app.ui.setting + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.view.View +import android.widget.ImageView +import android.widget.TextView +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.trello.rxlifecycle3.android.ActivityEvent +import com.chwl.app.R +import com.chwl.app.base.BaseActivity +import com.chwl.app.common.EmptyViewHelper +import com.chwl.app.ui.setting.bean.PermissionEntity +import com.chwl.app.ui.utils.RVDelegate +import com.chwl.app.ui.widget.DividerItemDecoration +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil +import com.chwl.app.utils.PermissionUtil +import com.chwl.library.utils.ResUtil +import io.reactivex.Completable +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.schedulers.Schedulers +import java.util.concurrent.TimeUnit + +class GrantedPermissionsActivity : BaseActivity() { + private lateinit var recyclerView: RecyclerView + private lateinit var rvDelegate: RVDelegate + private var isResumedFromSetting = false + + companion object { + fun start(context: Context) { + val intent = Intent(context, GrantedPermissionsActivity::class.java) + context.startActivity(intent) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_granted_permissions) + initTitleBar(ResUtil.getString(R.string.ui_setting_grantedpermissionsactivity_01)) + initView() + rvDelegate = RVDelegate.Builder() + .setLayoutManager(LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)) + .setRecyclerView(recyclerView) + .setEmptyView(EmptyViewHelper.createEmptyTextView(this, ResUtil.getString(R.string.ui_setting_grantedpermissionsactivity_02))) + .setAdapter(PermissionAdapter()) + .build() + } + + override fun onResume() {//修改系统权限设置返回立即读取会有黑屏问题 + super.onResume() + if (isResumedFromSetting) { + isResumedFromSetting = false + Completable.timer(1500, TimeUnit.MILLISECONDS) + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .doOnSubscribe { dialogManager.showProgressDialog(context, false) } + .doOnComplete { + rvDelegate.setNewData(PermissionUtil.instance.getGrantedPermissions(context)) + dialogManager.dismissDialog() + } + .doOnError { dialogManager.dismissDialog() } + .subscribe() + } else { + rvDelegate.setNewData(PermissionUtil.instance.getGrantedPermissions(context)) + } + } + + override fun onStop() { + super.onStop() + isResumedFromSetting = true + } + + private fun initView() { + recyclerView = findViewById(R.id.recycler_view) + recyclerView.addItemDecoration( + DividerItemDecoration( + this, LinearLayoutManager.VERTICAL, + UIUtil.dip2px(this, 16.toDouble()), + R.color.transparent + ) + ) + } + + fun jumpToSystemSetting(view: View) { + PermissionUtil.instance.jumpToSetting(this) + } + + class PermissionAdapter : + BaseQuickAdapter(R.layout.item_permission_granted) { + override fun convert(helper: BaseViewHolder, item: PermissionEntity?) { + item?.let { + helper.getView(R.id.tv_name)?.text = it.alias + helper.getView(R.id.tv_desc)?.text = it.description + helper.getView(R.id.icon)?.setImageResource(it.icon) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/setting/LabActivity.java b/app/src/main/java/com/chwl/app/ui/setting/LabActivity.java new file mode 100644 index 0000000..379ff54 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/setting/LabActivity.java @@ -0,0 +1,73 @@ +package com.chwl.app.ui.setting; + +import android.os.Bundle; +import android.view.View; +import android.widget.RadioButton; +import android.widget.RadioGroup; + +import com.chwl.app.R; +import com.chwl.app.base.BaseActivity; +import com.chwl.app.ui.utils.ImageLoadKt; +import com.chwl.library.common.application.Env; +import com.chwl.core.auth.AuthModel; +import com.chwl.library.utils.ResUtil; + + + +/** + * Created by chenran on 2017/10/16. + */ + +public class LabActivity extends BaseActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_lab); + findViewById(R.id.rb_vap_test).setOnClickListener(v -> + ImageLoadKt.loadAnim( + findViewById(R.id.anim_vap_test), + "http://img.uat.lecheng163.com/mask_trunk_demo.mp4") + ); + + //根据ID找到RadioGroup实例 + RadioGroup group = (RadioGroup) this.findViewById(R.id.radioGroup); + RadioButton rbRelease = (RadioButton) findViewById(R.id.rb_release); + rbRelease.setTag(Env.EnvType.Release); + RadioButton rbStaging = (RadioButton) findViewById(R.id.rb_staging); + rbStaging.setTag(Env.EnvType.Staging); + RadioButton rbDebug = (RadioButton) findViewById(R.id.rb_debug); + rbDebug.setTag(Env.EnvType.Debug); + Env.EnvType envType = Env.getCurrentEnv(); + if (envType == null) { + toast(ResUtil.getString(R.string.ui_setting_labactivity_01)); + return; + } + //设置选中 + for (int i = 0; i < group.getChildCount(); i++) { + View view = group.getChildAt(i); + if (view.getTag() == envType) { + group.check(view.getId()); + break; + } + } + + + //绑定一个匿名监听器 + group.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { + + @Override + public void onCheckedChanged(RadioGroup arg0, int arg1) { + //获取变更后的选中项的ID + Object obj = findViewById(arg1).getTag(); + if (!(obj instanceof Env.EnvType)) { + toast(ResUtil.getString(R.string.ui_setting_labactivity_02)); + return; + } + toast(ResUtil.getString(R.string.ui_setting_labactivity_03)); + Env.changeEnv((Env.EnvType) obj); + AuthModel.get().logout().subscribe(); + finish(); + } + }); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/setting/ModifyPwdActivity.java b/app/src/main/java/com/chwl/app/ui/setting/ModifyPwdActivity.java new file mode 100644 index 0000000..66c23e1 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/setting/ModifyPwdActivity.java @@ -0,0 +1,348 @@ +package com.chwl.app.ui.setting; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.Intent; +import android.text.Editable; +import android.text.InputFilter; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.View; + +import com.chwl.app.R; +import com.chwl.app.base.BaseBindingActivity; +import com.chwl.app.databinding.ActivityModifyPwdBinding; +import com.chwl.app.ui.login.PasswordValidator; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.auth.event.LogoutEvent; +import com.chwl.core.user.UserModel; +import com.chwl.core.utils.net.BeanObserver; +import com.chwl.library.annatation.ActLayoutRes; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.TextWatcherWrapper; +import com.netease.nim.uikit.StatusBarUtil; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.Objects; + +import io.reactivex.SingleObserver; +import io.reactivex.disposables.Disposable; + +@ActLayoutRes(R.layout.activity_modify_pwd) +public class ModifyPwdActivity extends BaseBindingActivity { + public static final int LOGIN_PWD = 1; + public static final int SET_LOGIN_PWD = 4; + public static final int PAY_PWD = 2; + public static final int FOGERT_PAY_PWD = 3; + public static final int RESET_PAY_PWD = 5; + + private int type; + + private PasswordValidator passwordValidator = new PasswordValidator(); + /** + * 是否是首次设置支付密码 + */ + private boolean isFirstSetPayPwd = false; + + public static void start(Context context, int type) { + Intent intent = new Intent(context, ModifyPwdActivity.class); + intent.putExtra("type", type); + context.startActivity(intent); + } + + @Override + protected void init() { + if (UserModel.get().getCacheLoginUserInfo() == null) { + toast(ResUtil.getString(R.string.ui_setting_modifypwdactivity_01)); + finish(); + return; + } + EventBus.getDefault().register(this); + type = getIntent().getIntExtra("type", 1); + if (type == PAY_PWD && !Objects.requireNonNull(UserModel.get().getCacheLoginUserInfo()).isBindPaymentPwd()) { + type = FOGERT_PAY_PWD; + isFirstSetPayPwd = true; + } + if (type == LOGIN_PWD) { + if (Objects.requireNonNull(UserModel.get().getCacheLoginUserInfo()).isBindPasswd()) { + setModifyPwdUI(); + } else { + setLoginPwdUI(); + } + } else if (type == PAY_PWD) { + setModifyPayPwdUI(); + setEditStyle(); + + } else if (type == FOGERT_PAY_PWD) { + setPayPwdUI(ResUtil.getString(R.string.ui_setting_modifypwdactivity_02)); + setEditStyle(); + } else if (type == RESET_PAY_PWD) { + setPayPwdUI(ResUtil.getString(R.string.ui_setting_modifypwdactivity_03)); + setEditStyle(); + } + mBinding.setClick(this); + setPsdEnable(); + } + + private void setPsdEnable() { + mBinding.edCurrentPwd.getEditText().addTextChangedListener(textWatcher); + mBinding.edPwd.getEditText().addTextChangedListener(textWatcher); + mBinding.edSurePwd.getEditText().addTextChangedListener(textWatcher); + } + + private final TextWatcher textWatcher = new TextWatcherWrapper() { + @Override + public void afterTextChanged(Editable s) { + checkInput(); + } + }; + + private void checkInput() { + String edCurrentPwd = mBinding.edCurrentPwd.getText(); + String edPwd = mBinding.edPwd.getText(); + String edSurePwd = mBinding.edSurePwd.getText(); + if (mBinding.edCurrentPwd.getVisibility() == View.GONE) { + mBinding.btnCommit.setEnabled(!TextUtils.isEmpty(edPwd) && edPwd.length() >= 6 && !TextUtils.isEmpty(edSurePwd) && edSurePwd.length() >= 6); + } else + mBinding.btnCommit.setEnabled(!TextUtils.isEmpty(edCurrentPwd) && edCurrentPwd.length() >= 6 && !TextUtils.isEmpty(edPwd) && edPwd.length() >= 6 && !TextUtils.isEmpty(edSurePwd) && edSurePwd.length() >= 6); + } + + private void setModifyPwdUI() { + initWhiteTitleBar(ResUtil.getString(R.string.ui_setting_modifypwdactivity_04)); + mBinding.edCurrentPwd.setTitleHint(ResUtil.getString(R.string.ui_setting_modifypwdactivity_05)); + mBinding.edCurrentPwd.setEditHint(ResUtil.getString(R.string.ui_setting_modifypwdactivity_06)); + mBinding.edPwd.setTitleHint(ResUtil.getString(R.string.ui_setting_modifypwdactivity_07)); + mBinding.edPwd.setEditHint(ResUtil.getString(R.string.ui_setting_modifypwdactivity_08)); + mBinding.edSurePwd.setTitleHint(ResUtil.getString(R.string.ui_setting_modifypwdactivity_09)); + mBinding.edSurePwd.setEditHint(ResUtil.getString(R.string.ui_setting_modifypwdactivity_010)); + mBinding.tvPasswordTip.setText(ResUtil.getString(R.string.ui_setting_modifypwdactivity_011)); + } + + private void setLoginPwdUI() { + type = SET_LOGIN_PWD; + initWhiteTitleBar(ResUtil.getString(R.string.ui_setting_modifypwdactivity_012)); + + mBinding.edCurrentPwd.setVisibility(View.GONE); + mBinding.btnForget.setVisibility(View.GONE); + + mBinding.edPwd.setTitleHint(ResUtil.getString(R.string.ui_setting_modifypwdactivity_013)); + mBinding.edPwd.setEditHint(ResUtil.getString(R.string.ui_setting_modifypwdactivity_014)); + mBinding.edSurePwd.setTitleHint(ResUtil.getString(R.string.ui_setting_modifypwdactivity_015)); + mBinding.edSurePwd.setEditHint(ResUtil.getString(R.string.ui_setting_modifypwdactivity_016)); + mBinding.tvPasswordTip.setText(ResUtil.getString(R.string.ui_setting_modifypwdactivity_017)); + } + + private void setModifyPayPwdUI() { + initWhiteTitleBar(ResUtil.getString(R.string.ui_setting_modifypwdactivity_018)); + mBinding.btnForget.setVisibility(View.GONE); + mBinding.edCurrentPwd.setTitleHint(ResUtil.getString(R.string.ui_setting_modifypwdactivity_019)); + mBinding.edCurrentPwd.setEditHint(ResUtil.getString(R.string.ui_setting_modifypwdactivity_020)); + mBinding.edPwd.setTitleHint(ResUtil.getString(R.string.ui_setting_modifypwdactivity_021)); + mBinding.edPwd.setEditHint(ResUtil.getString(R.string.ui_setting_modifypwdactivity_022)); + mBinding.edSurePwd.setTitleHint(ResUtil.getString(R.string.ui_setting_modifypwdactivity_023)); + mBinding.edSurePwd.setEditHint(ResUtil.getString(R.string.ui_setting_modifypwdactivity_024)); + mBinding.tvPasswordTip.setText(ResUtil.getString(R.string.ui_setting_modifypwdactivity_025)); + + } + + private void setPayPwdUI(String title) { + initWhiteTitleBar(title); + mBinding.edCurrentPwd.setVisibility(View.GONE); + mBinding.btnForget.setVisibility(View.GONE); + mBinding.edPwd.setTitleHint(ResUtil.getString(R.string.ui_setting_modifypwdactivity_026)); + mBinding.edPwd.setEditHint(ResUtil.getString(R.string.ui_setting_modifypwdactivity_027)); + mBinding.edSurePwd.setTitleHint(ResUtil.getString(R.string.ui_setting_modifypwdactivity_028)); + mBinding.edSurePwd.setEditHint(ResUtil.getString(R.string.ui_setting_modifypwdactivity_029)); + mBinding.tvPasswordTip.setText(ResUtil.getString(R.string.ui_setting_modifypwdactivity_030)); + } + + private void setEditStyle() { + mBinding.edCurrentPwd.setIntegerType(); + mBinding.edPwd.setIntegerType(); + mBinding.edSurePwd.setIntegerType(); + mBinding.edPwd.getEditText().setFilters(new InputFilter[]{new InputFilter.LengthFilter(6)}); + mBinding.edSurePwd.getEditText().setFilters(new InputFilter[]{new InputFilter.LengthFilter(6)}); + mBinding.edCurrentPwd.setPay(true); + mBinding.edPwd.setPay(true); + mBinding.edSurePwd.setPay(true); + } + + @Override + public void onClick(View v) { + super.onClick(v); + switch (v.getId()) { + case R.id.btn_commit: + commit(); + break; + case R.id.btn_forget: + if (type == PAY_PWD) { + VerifyPhoneActivity.startForResult(this, true); + } else { + ResetPasswordActivity.start(context, ResetPasswordActivity.FROM_LOGIN); + } + break; + } + } + + @SuppressLint("CheckResult") + private void commit() { + if (TextUtils.isEmpty(mBinding.edCurrentPwd.getText()) && type == LOGIN_PWD) { + toast(ResUtil.getString(R.string.ui_setting_modifypwdactivity_032)); + return; + } + if ((TextUtils.isEmpty(mBinding.edPwd.getText()) && type != FOGERT_PAY_PWD && type != RESET_PAY_PWD) || + TextUtils.isEmpty(mBinding.edSurePwd.getText())) { + toast(ResUtil.getString(R.string.ui_setting_modifypwdactivity_033)); + return; + } + if (!mBinding.edPwd.getText().equals(mBinding.edSurePwd.getText())) { + toast(ResUtil.getString(R.string.ui_setting_modifypwdactivity_034)); + return; + } + if (type == PAY_PWD || type == FOGERT_PAY_PWD || type == RESET_PAY_PWD) { + if (mBinding.edPwd.getText().length() != 6) { + toast(ResUtil.getString(R.string.ui_setting_modifypwdactivity_035)); + return; + } + } else { + if (!passwordValidator.isValid(mBinding.edPwd.getText())) { + toast(passwordValidator.getErrorMessage()); + return; + } + } + + if (type == LOGIN_PWD) { + getDialogManager().showProgressDialog(ModifyPwdActivity.this, ResUtil.getString(R.string.ui_setting_modifypwdactivity_037)); + AuthModel.get().modifyLoginPwd( + UserModel.get().getCacheLoginUserInfo().getPhone(), + DESAndBase64(mBinding.edCurrentPwd.getText()), + DESAndBase64(mBinding.edPwd.getText()) + ) + .compose(bindToLifecycle()) + .subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onSuccess(String s) { + getDialogManager().dismissDialog(); + UserModel.get().updateCurrentUserInfo().subscribe(); + toast(ResUtil.getString(R.string.ui_setting_modifypwdactivity_038)); + finish(); + } + + @Override + public void onError(Throwable e) { + getDialogManager().dismissDialog(); + toast(e.getMessage()); + } + }); + + } else if (type == PAY_PWD) { + getDialogManager().showProgressDialog(ModifyPwdActivity.this, ResUtil.getString(R.string.ui_setting_modifypwdactivity_039)); + UserModel.get().resetPayPwd(mBinding.edCurrentPwd.getText(), + mBinding.edPwd.getText()) + .subscribe(new BeanObserver() { + @Override + public void onErrorMsg(String error) { + getDialogManager().dismissDialog(); + toast(error); + } + + @Override + public void onSuccess(String s) { + getDialogManager().dismissDialog(); + UserModel.get().updateCurrentUserInfo().subscribe(); + toast(ResUtil.getString(R.string.ui_setting_modifypwdactivity_040)); + finish(); + } + }); + } else if (type == FOGERT_PAY_PWD || type == RESET_PAY_PWD) { + getDialogManager().showProgressDialog(ModifyPwdActivity.this, ResUtil.getString(R.string.ui_setting_modifypwdactivity_041)); + UserModel.get().setPayPwd(mBinding.edPwd.getText()) + .subscribe(new BeanObserver() { + @Override + public void onErrorMsg(String error) { + getDialogManager().dismissDialog(); + toast(error); + } + + @Override + public void onSuccess(String s) { + getDialogManager().dismissDialog(); + UserModel.get().updateCurrentUserInfo().subscribe(); + toast(ResUtil.getString(R.string.ui_setting_modifypwdactivity_042)); + finish(); + } + }); + } else if (type == SET_LOGIN_PWD) { + getDialogManager().showProgressDialog(ModifyPwdActivity.this, ResUtil.getString(R.string.ui_setting_modifypwdactivity_043)); + AuthModel.get().setLoginPwd( + UserModel.get().getCacheLoginUserInfo().getPhone(), + DESAndBase64(mBinding.edPwd.getText()) + ) + .compose(bindToLifecycle()) + .subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onSuccess(String s) { + getDialogManager().dismissDialog(); + UserModel.get().updateCurrentUserInfo().subscribe(); + toast(ResUtil.getString(R.string.ui_setting_modifypwdactivity_044)); + finish(); + } + + @Override + public void onError(Throwable e) { + getDialogManager().dismissDialog(); + toast(e.getMessage()); + } + }); + + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == VerifyPhoneActivity.REQUEST_CHECK_VALID_PHONE && resultCode == RESULT_OK) { + type = FOGERT_PAY_PWD; + setPayPwdUI(ResUtil.getString(R.string.ui_setting_modifypwdactivity_045)); + setEditStyle(); + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onLogoutEvent(LogoutEvent event) { + finish(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + EventBus.getDefault().unregister(this); + } + + @Override + protected boolean needSteepStateBar() { + return true; + } + + @Override + protected void setStatusBar() { + super.setStatusBar(); + StatusBarUtil.transparencyBar(this); + StatusBarUtil.StatusBarLightMode(this); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/setting/NoticeSettingActivity.java b/app/src/main/java/com/chwl/app/ui/setting/NoticeSettingActivity.java new file mode 100644 index 0000000..b0c3691 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/setting/NoticeSettingActivity.java @@ -0,0 +1,158 @@ +package com.chwl.app.ui.setting; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.Intent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.netease.nim.uikit.StatusBarUtil; +import com.trello.rxlifecycle3.android.ActivityEvent; +import com.chwl.app.R; +import com.chwl.app.base.BaseViewBindingActivity; +import com.chwl.app.common.widget.TutuSwitchView; +import com.chwl.app.databinding.ActivityNoticeSettingBinding; +import com.chwl.core.settings.SettingsModel; +import com.chwl.core.utils.net.DontWarnObserver; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.widget.IOSSwitchView; + +/** + * create by lvzebiao @2019/12/23 + */ +public class NoticeSettingActivity extends BaseViewBindingActivity { + + private View systemNoticeView; + private TutuSwitchView switchSystemNotice; + private boolean notifyMsg = false; + private View attentionNoticeView; + private TutuSwitchView switchAttentionNotice; + private boolean notifyAttention = false; + + public static void start(Context context) { + Intent intent = new Intent(context, NoticeSettingActivity.class); + context.startActivity(intent); + } + + @SuppressLint("CheckResult") + @Override + public void init() { + initWhiteTitleBar(ResUtil.getString(R.string.ui_setting_noticesettingactivity_02)); + + SettingsModel.get().getSysMsgNotify() + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .subscribe(result -> { + + notifyMsg = result.isSysMsgNotify(); + initSystemNotice(); + + notifyAttention = result.isSingleBroadcastMsgNotify(); + initAttentionNotice(); + }); + } + + private void initSystemNotice() { + + if (systemNoticeView == null) { + systemNoticeView = LayoutInflater.from(context).inflate(R.layout.item_system_notice, null); + switchSystemNotice = systemNoticeView.findViewById(R.id.switch_notice); + binding.llContainer.addView(systemNoticeView, new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT) + ); + setName(systemNoticeView, ResUtil.getString(R.string.ui_setting_noticesettingactivity_03)); + setDesc(systemNoticeView, ResUtil.getString(R.string.ui_setting_noticesettingactivity_04)); + } + switchSystemNotice.setOn(notifyMsg); + + switchSystemNotice.setOnSwitchStateChangeListener(new IOSSwitchView.OnSwitchStateChangeListener() { + @Override + public void onStateSwitched(boolean isOn) { + SettingsModel.get().setSysMsgNotify(isOn) + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .subscribe(new DontWarnObserver() { + @Override + public void accept(String s, String error) { + super.accept(s, error); + if (error == null) { + notifyMsg = isOn; + } else { + toast(error); + } + } + }); + + } + }); + + } + + private void initAttentionNotice() { + if (attentionNoticeView == null) { + attentionNoticeView = LayoutInflater.from(context).inflate(R.layout.item_system_notice, null); + switchAttentionNotice = attentionNoticeView.findViewById(R.id.switch_notice); + binding.llContainer.addView(attentionNoticeView, new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT) + ); + setName(attentionNoticeView, ResUtil.getString(R.string.ui_setting_noticesettingactivity_06)); + setDesc(attentionNoticeView, ResUtil.getString(R.string.ui_setting_noticesettingactivity_07)); + } + switchAttentionNotice.setOn(notifyAttention); + + switchAttentionNotice.setOnSwitchStateChangeListener(new IOSSwitchView.OnSwitchStateChangeListener() { + @Override + public void onStateSwitched(boolean isOn) { + SettingsModel.get().setAttentionMsgNotify(isOn) + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .subscribe(new DontWarnObserver() { + @Override + public void accept(String s, String error) { + super.accept(s, error); + if (error == null) { + notifyAttention = isOn; + } else { + toast(error); + } + } + }); + + } + }); + } + + private void setName(View targetView, String name) { + if (targetView == null) { + return; + } + TextView tvName = targetView.findViewById(R.id.tv_name); + if (tvName != null) { + tvName.setText(name); + } + } + + private void setDesc(View targetView, String desc) { + if (targetView == null) { + return; + } + TextView tvDesc = targetView.findViewById(R.id.tv_desc); + if (tvDesc != null) { + tvDesc.setText(desc); + } + } + + @Override + protected boolean needSteepStateBar() { + return true; + } + + @Override + protected void setStatusBar() { + super.setStatusBar(); + StatusBarUtil.transparencyBar(this); + StatusBarUtil.StatusBarLightMode(this); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/setting/PermissionGuideActivity.kt b/app/src/main/java/com/chwl/app/ui/setting/PermissionGuideActivity.kt new file mode 100644 index 0000000..f33f1fc --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/setting/PermissionGuideActivity.kt @@ -0,0 +1,68 @@ +package com.chwl.app.ui.setting + +import android.content.Context +import android.content.Intent +import android.view.View +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.databinding.ActivityPermissionGuideBinding +import com.chwl.app.ui.webview.CommonWebViewActivity +import com.chwl.core.UriProvider +import com.chwl.library.utils.ResUtil + +class PermissionGuideActivity : BaseViewBindingActivity(), + View.OnClickListener { + + companion object { + fun start(context: Context) { + val intent = Intent(context, PermissionGuideActivity::class.java) + context.startActivity(intent) + } + } + + override fun init() { + initTitleBar(ResUtil.getString(R.string.ui_setting_permissionguideactivity_01)) + binding.click = this + } + + override fun onClick(v: View?) { + when (v?.id) { + R.id.tv_system_permission -> GrantedPermissionsActivity.start(this) + R.id.tv_privacy_guide -> CommonWebViewActivity.start( + this, UriProvider.getPrivacyUrl() + ) + R.id.tv_sdk_permission -> CommonWebViewActivity.start( + this, + UriProvider.getSDKPermissionUrl() + ) +// R.id.tv_device_permission -> CommonWebViewActivity.start( +// this, +// UriProvider.getDeivcePermissionUrl() +// ) +// R.id.tv_personal_permission -> CommonWebViewActivity.start( +// this, +// UriProvider.getPersonalInfoUrl() +// ) + R.id.tv_charge_agreement -> CommonWebViewActivity.start( + this, + UriProvider.getChargeAgreementUrl() + ) + R.id.tv_registration_agreement -> CommonWebViewActivity.start( + this, + UriProvider.getRegistrationAgreementUrl() + ) +// R.id.tv_live_service_agreement -> CommonWebViewActivity.start( +// this, +// UriProvider.getLiveServiceAgreementUrl() +// ) +// R.id.tv_community_specification -> CommonWebViewActivity.start( +// this, +// UriProvider.getCommunitySpecificationUrl() +// ) + R.id.tv_cancellation_agreement -> CommonWebViewActivity.start( + this, + UriProvider.getCancellationAgreementUrl() + ) + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/setting/PrivacySettingActivity.java b/app/src/main/java/com/chwl/app/ui/setting/PrivacySettingActivity.java new file mode 100644 index 0000000..c684955 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/setting/PrivacySettingActivity.java @@ -0,0 +1,144 @@ +package com.chwl.app.ui.setting; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.Intent; +import android.text.TextUtils; + +import com.netease.nim.uikit.StatusBarUtil; +import com.trello.rxlifecycle3.android.ActivityEvent; +import com.chwl.app.R; +import com.chwl.app.base.BaseViewBindingActivity; +import com.chwl.app.databinding.ActivityPrivacySettingBinding; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.settings.SettingsModel; +import com.chwl.core.user.UserModel; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.core.utils.net.RxHelper; +import com.chwl.library.widget.IOSSwitchView; + +import java.util.concurrent.CancellationException; + +import io.reactivex.Single; +import io.reactivex.SingleSource; +import io.reactivex.disposables.Disposable; +import io.reactivex.functions.BiConsumer; +import io.reactivex.functions.Function; + +/** + * create by lvzebiao @2019/12/23 + */ +public class PrivacySettingActivity extends BaseViewBindingActivity { + + private Disposable locationDisposable; + private Disposable ageDisposable; + private Disposable matchDisposable; + + public static void start(Context context) { + Intent intent = new Intent(context, PrivacySettingActivity.class); + context.startActivity(intent); + } + + @Override + public void init() { + initTitleBar(R.string.privacy_setting); + initData(); + initListener(); + } + + @SuppressLint("CheckResult") + private void initData() { + UserInfo userInfo = UserModel.get().getCacheLoginUserInfo(); + if (userInfo == null) { + finish(); + return; + } + boolean isShowAge = true; + boolean isMatchChat = true; + if (userInfo.getUserExpand() != null) { + isShowAge = userInfo.getUserExpand().isShowAge(); + isMatchChat = userInfo.getUserExpand().isMatchChat(); + } + if (ageDisposable == null || ageDisposable.isDisposed()) { + binding.switchAge.setOn(isShowAge); + } + if (matchDisposable == null || matchDisposable.isDisposed()) { + binding.switchMatchChat.setOn(isMatchChat); + } + } + + private void initListener() { + + binding.switchAge.setOnSwitchStateChangeListener(new IOSSwitchView.OnSwitchStateChangeListener() { + @Override + public void onStateSwitched(boolean isOn) { + long uid = AuthModel.get().getCurrentUid(); + //如果上一次正在请求,关闭上次请求 + if (ageDisposable != null && !ageDisposable.isDisposed()) { + ageDisposable.dispose(); + } + ageDisposable = Single.just(isOn) + .flatMap((Function>) b -> SettingsModel.get().showAge(uid, isOn) + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .compose(RxHelper.singleMainResult()) + .compose(RxHelper.handleSchAndExce())).subscribe((s, throwable) -> { + //过滤关闭请求 + if (throwable instanceof CancellationException) { + return; + } + if (throwable != null && !TextUtils.isEmpty(throwable.getMessage())) { + toast(throwable.getMessage()); + binding.switchAge.setOn(!isOn); + } + + }); + + + } + }); + + binding.switchMatchChat.setOnSwitchStateChangeListener(new IOSSwitchView.OnSwitchStateChangeListener() { + @Override + public void onStateSwitched(boolean isOn) { + long uid = AuthModel.get().getCurrentUid(); + //如果上一次正在请求,关闭上次请求 + if (matchDisposable != null && !matchDisposable.isDisposed()) { + matchDisposable.dispose(); + } + matchDisposable = Single.just(isOn) + .flatMap((Function>) b -> SettingsModel.get().showMatchChat(uid, isOn) + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .compose(RxHelper.singleMainResult()) + .compose(RxHelper.handleSchAndExce())).subscribe(new BiConsumer() { + @Override + public void accept(String s, Throwable throwable) throws Exception { + //过滤关闭请求 + if (throwable instanceof CancellationException) { + return; + } + if (throwable != null && !TextUtils.isEmpty(throwable.getMessage())) { + toast(throwable.getMessage()); + binding.switchMatchChat.setOn(!isOn); + } + } + }); + + + } + }); + } + + @Override + protected boolean needSteepStateBar() { + return true; + } + + @Override + protected void setStatusBar() { + super.setStatusBar(); + StatusBarUtil.transparencyBar(this); + StatusBarUtil.StatusBarLightMode(this); + StatusBarUtil.StatusBarLightMode(this); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/setting/ResetPasswordActivity.kt b/app/src/main/java/com/chwl/app/ui/setting/ResetPasswordActivity.kt new file mode 100644 index 0000000..080c2dd --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/setting/ResetPasswordActivity.kt @@ -0,0 +1,333 @@ +package com.chwl.app.ui.setting + +import android.annotation.SuppressLint +import android.content.Context +import android.content.Intent +import android.os.CountDownTimer +import android.text.Editable +import android.text.TextUtils +import android.text.TextWatcher +import android.view.View +import android.view.inputmethod.EditorInfo +import androidx.activity.result.ActivityResultLauncher +import androidx.activity.result.contract.ActivityResultContracts +import androidx.core.content.ContextCompat +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.databinding.ActivityResetLoginPwdBinding +import com.chwl.app.ui.login.AreaCodeActivity +import com.chwl.app.ui.login.BindPhoneActivity +import com.chwl.app.ui.login.LoginVerifyActivity +import com.chwl.app.ui.login.helper.LogoutHelper +import com.chwl.core.RegionHelper +import com.chwl.core.auth.AuthModel +import com.chwl.core.code.CodeType +import com.chwl.core.initial.InitialModel +import com.chwl.core.user.UserModel +import com.chwl.library.common.util.ClickUtils.click +import com.chwl.library.common.util.hasInput +import com.chwl.library.common.util.setRL +import com.chwl.library.common.util.setVis +import com.chwl.library.utils.ResUtil +import com.chwl.library.utils.TextWatcherWrapper +import com.coorchice.library.utils.LogUtils +import com.example.lib_utils.ktx.getColor +import com.example.lib_utils.ktx.getString +import com.netease.nim.uikit.StatusBarUtil +import com.trello.rxlifecycle3.android.ActivityEvent +import io.reactivex.SingleObserver +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable + +class ResetPasswordActivity : BaseViewBindingActivity(), + View.OnClickListener { + private var from = 0 + private var isEmail = true + private var cdt: CountDownTimer? = null + private val textWatcher: TextWatcher = object : TextWatcherWrapper() { + override fun afterTextChanged(s: Editable) { + checkInput() + } + } + + companion object { + const val FROM_NOT_LOGIN = 1 + const val FROM_LOGIN = 2 + + @JvmStatic + fun start(context: Context, type: Int) { + val intent = Intent(context, ResetPasswordActivity::class.java) + intent.putExtra("from", type) + context.startActivity(intent) + } + } + + private val mCodeResult: ActivityResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + if (result != null) { + val isVerify = result.resultCode == RESULT_OK + if (isVerify) { + getCode() + } + } + } + + override fun init() { + from = intent.getIntExtra("from", FROM_LOGIN) + + initWhiteTitleBar("") + initListener() + RegionHelper().loadRecommendRegion(lifecycle, binding.tvAreaCode) + + binding.loginBack.click { + finish() + } + + binding.switchType.click { + isEmail = !isEmail + setUI() + } + setUI() + + binding.bg.setRL() + } + + private fun initListener() { + + binding.tvAreaCode.setOnClickListener(this) + binding.tvGetCode.setOnClickListener(this) + binding.btnCommit.setOnClickListener(this) + + binding.etAccount.addTextChangedListener(textWatcher) + binding.etPassword.editText.addTextChangedListener(textWatcher) + binding.etCode.addTextChangedListener(textWatcher) + } + + private fun checkInput() { + val enabled = + !TextUtils.isEmpty(binding.etAccount.text) && binding.etAccount.text.toString() + .trim { it <= ' ' }.length >= 7 && !TextUtils.isEmpty(binding.etPassword.text) && binding.etPassword.text.trim { it <= ' ' }.length >= 6 && !TextUtils.isEmpty( + binding.etCode.text + ) && binding.etCode.text.toString().trim { it <= ' ' }.length >= 5 + binding.btnCommit.isEnabled = enabled + } + + override fun onClick(v: View) { + when (v.id) { + R.id.tv_area_code -> { + AreaCodeActivity.startForResult(this, BindPhoneActivity.REQUEST_AREA_CODE) + } + + R.id.tv_get_code -> { + + if (binding.etAccount.hasInput()) { + if (isEmail) { + getCode() + } else { + val initInfo = InitialModel.get().cacheInitInfo + if (initInfo != null && initInfo.isCaptchaSwitch) { + mCodeResult.launch(Intent(this, LoginVerifyActivity::class.java)) + } else { + getCode() + } + } + } + + } + + R.id.btn_commit -> commit() + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (requestCode == BindPhoneActivity.REQUEST_AREA_CODE && resultCode == RESULT_OK) { + val areaCode = data?.getStringExtra(AreaCodeActivity.COUNTRY_NUMBER) + if (areaCode != null) { + binding.tvAreaCode.text = areaCode + } + } + } + + private fun startCounter() { + stopCounter() + resetBtn() + //开始倒计时 60s 间隔1s + binding.tvGetCode.isEnabled = false + binding.tvGetCode.setTextColor(ContextCompat.getColor(this, R.color.color_9168FA)) + cdt = object : CountDownTimer(60 * 1000, 100) { + override fun onTick(text: Long) { + showTextDown(text) + } + + override fun onFinish() { + resetBtn() + } + } + cdt?.start() + } + + private fun showTextDown(text: Long) { + val time = (text / 1000).toString() + "s" + binding.tvGetCode.text = time + binding.tvGetCode.setTextColor(R.color.color_AFB1B3.getColor()) + } + + private fun stopCounter() { + cdt?.cancel() + cdt = null + } + + private fun resetBtn() { + stopCounter() + binding.tvGetCode.isEnabled = true + binding.tvGetCode.text = getString(R.string.get) + binding.tvGetCode.setTextColor(R.color.color_ff8c03.getColor()) + } + + + private fun setUI() { + if (isEmail) { + binding.etAccount.setHint(R.string._ver_24_input_hint_email.getString()) + binding.etAccount.inputType = EditorInfo.TYPE_CLASS_TEXT + binding.tvAreaCode.setVis(false) + binding.switchType.text = R.string._ver_24_reset_phone.getString() + } else { + binding.etAccount.setHint(R.string.hint_register_input_phone_number.getString()) + binding.tvAreaCode.setVis(true) + binding.etAccount.inputType = EditorInfo.TYPE_CLASS_NUMBER + binding.switchType.text = R.string._ver_24_reset_email.getString() + } + } + + private fun getCode() { + if (isEmail) { + dialogManager.showProgressDialog(this) + val email: String = binding.etAccount.getText().toString() + AuthModel.get() + .getEmailCode( + email, + CodeType.RESET_PSW + ) + .observeOn(AndroidSchedulers.mainThread()) + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .subscribe(object : SingleObserver { + override fun onSubscribe(d: Disposable) {} + override fun onSuccess(t: String) { + dialogManager.dismissDialog() + startCounter() + } + + override fun onError(e: Throwable) { + dialogManager.dismissDialog() + toast(e.message) + } + }) + } else { + dialogManager.showProgressDialog(this) + AuthModel.get() + .getSmsCode( + binding.tvAreaCode.text.toString().substring(1), + binding.tvAreaCode.text.toString() + .substring(1) + binding.etAccount.text.toString(), + if (from == FROM_LOGIN) CodeType.RESET_PSW_LOGIN else CodeType.RESET_PSW_NOT_LOGIN + ) + .observeOn(AndroidSchedulers.mainThread()) + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .subscribe(object : SingleObserver { + override fun onSubscribe(d: Disposable) {} + override fun onSuccess(t: String) { + dialogManager.dismissDialog() + startCounter() + } + + override fun onError(e: Throwable) { + dialogManager.dismissDialog() + toast(e.message) + LogUtils.e(ResUtil.getString(R.string.ui_setting_resetpasswordactivity_03)) + } + + }) + } + } + + @SuppressLint("CheckResult") + private fun commit() { + if (isEmail) { + dialogManager.showProgressDialog( + this@ResetPasswordActivity, + ResUtil.getString(R.string.ui_setting_resetpasswordactivity_07) + ) + AuthModel.get().requestResetPswByEmail( + binding.etAccount.text.toString(), + binding.etCode.text.toString().trim { it <= ' ' }, + binding.etPassword.text.trim { it <= ' ' } + ).compose(bindToLifecycle()) + .subscribe(object : SingleObserver { + override fun onSubscribe(d: Disposable) {} + override fun onSuccess(t: String) { + dialogManager.dismissDialog() + UserModel.get().updateCurrentUserInfo().subscribe() + toast(ResUtil.getString(R.string.ui_setting_resetpasswordactivity_08)) + if (from == FROM_LOGIN) { + LogoutHelper.logout() + } + finish() + } + + override fun onError(e: Throwable) { + dialogManager.dismissDialog() + toast(e.message) + } + + }) + + } else { + dialogManager.showProgressDialog( + this@ResetPasswordActivity, + ResUtil.getString(R.string.ui_setting_resetpasswordactivity_07) + ) + AuthModel.get().requestResetPsw( + binding.tvAreaCode.text.toString().substring(1), + binding.tvAreaCode.text.toString().substring(1) + binding.etAccount.text.toString().trim { it <= ' ' }, + binding.etCode.text.toString().trim { it <= ' ' }, + binding.etPassword.text.trim { it <= ' ' } + ).compose(bindToLifecycle()) + .subscribe(object : SingleObserver { + override fun onSubscribe(d: Disposable) {} + override fun onSuccess(t: String) { + dialogManager.dismissDialog() + UserModel.get().updateCurrentUserInfo().subscribe() + toast(ResUtil.getString(R.string.ui_setting_resetpasswordactivity_08)) + if (from == FROM_LOGIN) { + LogoutHelper.logout() + } + finish() + } + + override fun onError(e: Throwable) { + dialogManager.dismissDialog() + toast(e.message) + } + + }) + } + + } + + override fun needSteepStateBar(): Boolean { + return true + } + + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } + + override fun onDestroy() { + super.onDestroy() + dialogManager.dismissDialog() + stopCounter() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/setting/SettingActivity.kt b/app/src/main/java/com/chwl/app/ui/setting/SettingActivity.kt new file mode 100644 index 0000000..74a62dc --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/setting/SettingActivity.kt @@ -0,0 +1,265 @@ +package com.chwl.app.ui.setting + +import android.annotation.SuppressLint +import android.content.Intent +import android.os.Build +import android.os.Bundle +import android.os.Environment +import android.text.SpannableString +import android.view.View +import com.chwl.app.BuildConfig +import com.chwl.app.R +import com.chwl.app.UIHelper +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.common.widget.dialog.DialogManager.OkCancelDialogListener +import com.chwl.app.databinding.ActivitySettingBinding +import com.chwl.app.notify.RoomNotifyManager +import com.chwl.app.ui.game_team.record.GameTeamRecordActivity +import com.chwl.app.ui.im.avtivity.BlackListManageActivity +import com.chwl.app.ui.language.LanguageActivity +import com.chwl.app.ui.login.BindEmailActivity +import com.chwl.app.ui.login.BindPhoneActivity +import com.chwl.app.ui.login.ShowBindEmailActivity +import com.chwl.app.ui.login.ShowBindPhoneActivity +import com.chwl.app.ui.login.helper.LogoutHelper +import com.chwl.app.ui.user.activity.AboutActivity +import com.chwl.app.ui.webview.CommonWebViewActivity +import com.chwl.core.UriProvider +import com.chwl.core.auth.AuthModel +import com.chwl.core.auth.event.LogoutEvent +import com.chwl.core.user.UserModel +import com.chwl.core.user.bean.UserInfo +import com.chwl.core.utils.SharedPreferenceUtils +import com.chwl.library.common.SpConstants +import com.chwl.library.common.file.FileHelper +import com.chwl.library.common.util.SPUtils +import com.chwl.library.common.util.doLog +import com.chwl.library.common.util.isVerify +import com.chwl.library.utils.ResUtil +import com.chwl.library.utils.file.JXFileUtils +import com.example.lib_utils.log.ILog +import com.netease.nim.uikit.StatusBarUtil +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode +import java.io.File + + +/** + * 设置页 + * Created by wushaocheng on 2023/2/1. + */ +class SettingActivity : BaseViewBindingActivity(), View.OnClickListener, + ILog { + + private var notify: RoomNotifyManager? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + "SettingActivity onCreate()".doLog() + } + + override fun init() { + EventBus.getDefault().register(this) + initWhiteTitleBar(ResUtil.getString(R.string.me_setting)) + initView() + initListener() + notify = RoomNotifyManager(this) + notify?.start() + } + + @SuppressLint("SetTextI18n") + private fun initView() { + val cacheLoginUserInfo = UserModel.get().cacheLoginUserInfo ?: return + if (cacheLoginUserInfo.isBindPasswd) { + binding.tvLoginPwd.text = ResUtil.getString(R.string.text_reset_password) + } else { + binding.tvLoginPwd.text = ResUtil.getString(R.string.ui_setting_settingactivity_016) + } + } + + private fun initListener() { + binding.rlyBindEmail.setOnClickListener(this) + binding.rlyBindPhone.setOnClickListener(this) + binding.rlyContactUs.setOnClickListener(this) + binding.rlyHelp.setOnClickListener(this) + binding.rlyUpdate.setOnClickListener(this) + binding.tvBlackManager.setOnClickListener(this) + binding.rlyLoginPwd.setOnClickListener(this) + binding.btnLoginOut.setOnClickListener(this) + binding.tvCommunityNorms.setOnClickListener(this) + binding.rlyClearCache.setOnClickListener(this) + binding.tvNoticeSetting.setOnClickListener(this) + binding.tvVipSetting.setOnClickListener(this) + binding.tvShieldManager.setOnClickListener(this) + binding.rlyPermission.setOnClickListener(this) + binding.tvLanugage.setOnClickListener(this) + binding.rlyPayPwd.setOnClickListener(this) + + if (BuildConfig.DEBUG) { + binding.titleBar.setOnTitleClickListener { + debug() + } + } + } + + @SuppressLint("CheckResult") + override fun onResume() { + super.onResume() + val userInfo = UserModel.get().cacheLoginUserInfo + if (userInfo != null && userInfo.isBindPhone) { + binding.tvBindPhone.text = getString(R.string.text_modify_bind_phone) + if (userInfo.phone.isVerify()){ + binding.tvBindPhoneValue.text = "${userInfo.phoneAreaCode} ${userInfo.phone}" + }else{ + binding.tvBindPhoneValue.text = "" + } + } else { + binding.tvBindPhone.text = getString(R.string.text_bind_phone) + binding.tvBindPhoneValue.text = "" + } + + if (userInfo != null && userInfo.email.isVerify()) { + binding.tvBindEmail.text = getString(R.string._ver_24_text_change_email) + } else { + binding.tvBindEmail.text = getString(R.string._ver_24_text_bind_email) + } + + binding.tvBindEmailValue.text = userInfo?.email?:"" + UserModel.get().updateCurrentUserInfo() + .compose(bindToLifecycle()) + .subscribe { _: UserInfo? -> + //刷新下界面 + initView() + } + } + + override fun onClick(view: View) { + when (view.id) { + R.id.rly_bind_email -> { + val userInfo = UserModel.get().cacheLoginUserInfo + if (userInfo != null && userInfo.email.isVerify()) { + ShowBindEmailActivity.start(context) + } else { + BindEmailActivity.start(this) + } + } + R.id.rly_bind_phone -> { + val userInfo = UserModel.get().cacheLoginUserInfo + if (userInfo != null && userInfo.isBindPhone) { + ShowBindPhoneActivity.start(context) + } else { + BindPhoneActivity.start(this) + } + } + + R.id.rly_contact_us -> UIHelper.openContactUs(this) + R.id.rly_help -> UIHelper.showUsinghelp(this) + R.id.rly_update -> startActivity(Intent(applicationContext, AboutActivity::class.java)) + R.id.tv_black_manager -> BlackListManageActivity.start(this) + R.id.rly_login_pwd -> ModifyPwdActivity.start(this, ModifyPwdActivity.LOGIN_PWD) + R.id.rly_pay_pwd-> { + if (UserModel.get().cacheLoginUserInfo == null) { + toast(ResUtil.getString(R.string.ui_setting_settingactivity_06)) + return + } + ModifyPwdActivity.start(this, ModifyPwdActivity.PAY_PWD) + } + R.id.btn_login_out -> { + val cacheLoginUserInfo = UserModel.get().cacheLoginUserInfo ?: return + if (!cacheLoginUserInfo.isBindPasswd && !SPUtils.getBoolean( + SpConstants.SET_PASSWORD, + false + ) + ) { + dialogManager.showOkCancelWithTitleDialog(ResUtil.getString(R.string.set_login_password), + SpannableString(ResUtil.getString(R.string.set_login_password_tip)), + ResUtil.getString(R.string.login_fragment_adduserinfofragment_04), + ResUtil.getString(R.string.ui_setting_settingactivity_010), + object : OkCancelDialogListener { + override fun onCancel() {} + override fun onOk() { + SPUtils.putBoolean(SpConstants.SET_PASSWORD, true) + ModifyPwdActivity.start( + this@SettingActivity, + ModifyPwdActivity.LOGIN_PWD + ) + } + }) + } else { + dialogManager.showProgressDialog(this) + LogoutHelper.logout() + } + } + + R.id.tv_community_norms -> CommonWebViewActivity.start( + this, + UriProvider.getCommnunityNorms() + ) + + R.id.rly_clear_cache -> dialogManager.showOkCancelWithTitleDialog(ResUtil.getString(R.string.ui_setting_settingactivity_07), + SpannableString(ResUtil.getString(R.string.ui_setting_settingactivity_08)), + ResUtil.getString(R.string.ui_setting_settingactivity_09), + ResUtil.getString(R.string.ui_setting_settingactivity_010), + object : OkCancelDialogListener { + override fun onCancel() {} + override fun onOk() { + clearCache() + } + }) + R.id.tv_vip_setting -> VipSetActivity.start(context); + R.id.tv_notice_setting -> NoticeSettingActivity.start(context) + R.id.tv_shield_manager -> ShieldManageActivity.start(context) + R.id.rly_permission -> PermissionGuideActivity.start(context) + R.id.tv_lanugage -> startActivity(Intent(context,LanguageActivity::class.java)) + } + } + + private fun clearCache() { + try { + SharedPreferenceUtils.remove(SharedPreferenceUtils.SEARCH_HISTORY + AuthModel.get().currentUid) + val dataDir = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + File(File(FileHelper.getRootCacheDir().path, "Android"), "data") + } else { + File(File(Environment.getExternalStorageDirectory(), "Android"), "data") + } + val appCacheDir = File(File(dataDir, context.packageName), "cache") + JXFileUtils.deleteFile(appCacheDir) + toast(ResUtil.getString(R.string.ui_setting_settingactivity_011)) + } catch (ex: Exception) { + ex.printStackTrace() + } + } + + class MissingPermissionException(message: String?) : RuntimeException(message) + + override fun needSteepStateBar(): Boolean { + return true + } + + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onLogoutEvent(event: LogoutEvent?) { + dialogManager.dismissDialog() + finish() + } + + override fun onDestroy() { + "SettingActivity onDestroy()".doLog() + super.onDestroy() + dialogManager.dismissDialog() + EventBus.getDefault().unregister(this) + } + + private fun debug() { + startActivity(Intent(this, GameTeamRecordActivity::class.java)) +// CommonWebViewActivity.start(this,"http://beta.api.molistar.xyz/molistar/modules/order/index.html") +// PublicChatRoomMessageActivity.start(this) +// MyDecorationActivity.start(this,0) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/setting/ShieldManageActivity.kt b/app/src/main/java/com/chwl/app/ui/setting/ShieldManageActivity.kt new file mode 100644 index 0000000..ff7783c --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/setting/ShieldManageActivity.kt @@ -0,0 +1,110 @@ +package com.chwl.app.ui.setting + +import android.annotation.SuppressLint +import android.content.Context +import android.content.Intent +import androidx.activity.viewModels +import androidx.recyclerview.widget.LinearLayoutManager +import com.netease.nim.uikit.StatusBarUtil +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.common.EmptyViewHelper +import com.chwl.app.databinding.ActivityShieldManageBinding +import com.chwl.app.ui.setting.adapter.RoomShieldAdapter +import com.chwl.app.ui.setting.viewmodel.SetViewModel +import com.chwl.app.ui.utils.RVDelegate +import com.chwl.core.set.bean.ShieldInfo + +/** + * author: wushaocheng + * time: 2022/12/28 + * 屏蔽管理 + */ +class ShieldManageActivity : BaseViewBindingActivity() { + + private val setViewModel: SetViewModel by viewModels() + + private var pageNum: Int = 1 + private val pageSize = 20 + private var mPosition = -1 + + private val mAdapter: RoomShieldAdapter by lazy { RoomShieldAdapter() } + + companion object { + @JvmStatic + fun start(context: Context) { + val intent = Intent(context, ShieldManageActivity::class.java) + context.startActivity(intent) + } + } + + override fun init() { + initWhiteTitleBar(getString(R.string.shield_manager)) + + val rvDelegate = RVDelegate.Builder() + .setAdapter(mAdapter) + .setLayoutManager(LinearLayoutManager(this)) + .setPageSize(pageSize) + .setEmptyView( + EmptyViewHelper.createEmptyTextView( + this, + getString(R.string.your_shield_list_is_empty) + ) + ) + .setRefreshLayout(binding.mRefreshLayout) + .setRecyclerView(binding.mRecyclerView) + .build() + + mAdapter.setOnItemChildClickListener { adapter, view, position -> + mPosition = position + mAdapter.getItem(position)?.uid?.let { setViewModel.setUnMask(it,1) } + } + + mAdapter.setOnLoadMoreListener({ + loadData(false) + }, binding.mRecyclerView) + binding.mRefreshLayout.setOnRefreshListener { + loadData(true) + } + setViewModel.shieldRoomLiveData.observe(this) { + rvDelegate.loadData(it) + } + + setViewModel.unMaskLiveData.observe(this) { + if(mPosition != -1) { + mAdapter.remove(mPosition) + } + toast(getString(R.string.successfully_unmasking)) + } + + setViewModel.loadingLiveData.observe(this) { loading -> + if (loading) dialogManager.showProgressDialog(this) + else dialogManager.dismissDialog() + } + + loadData(true) + } + + @SuppressLint("CheckResult") + fun loadData(isRefresh: Boolean) { + binding.mRefreshLayout.isRefreshing = isRefresh + pageNum = if (isRefresh) 1 else (pageNum + 1) + setViewModel.getShieldRoom(pageNum, pageSize) + } + + override fun needSteepStateBar(): Boolean { + return true + } + + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } + + override fun onDestroy() { + super.onDestroy() + dialogManager.dismissDialog() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/setting/VerifyEmailActivity.kt b/app/src/main/java/com/chwl/app/ui/setting/VerifyEmailActivity.kt new file mode 100644 index 0000000..e9a6e83 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/setting/VerifyEmailActivity.kt @@ -0,0 +1,209 @@ +package com.chwl.app.ui.setting + +import android.annotation.SuppressLint +import android.app.Activity +import android.content.Context +import android.content.Intent +import android.os.CountDownTimer +import android.text.Editable +import android.text.TextUtils +import android.text.TextWatcher +import android.view.View +import androidx.core.content.ContextCompat +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.databinding.ActivityVerifyEmailBinding +import com.chwl.app.ui.login.AreaCodeActivity +import com.chwl.app.ui.login.BindEmailActivity +import com.chwl.app.ui.login.BindPhoneActivity +import com.chwl.core.auth.AuthModel +import com.chwl.core.code.CodeType +import com.chwl.core.pay.PayModel +import com.chwl.core.user.UserModel +import com.chwl.core.utils.net.BeanObserver +import com.chwl.library.utils.ResUtil +import com.netease.nim.uikit.StatusBarUtil + +class VerifyEmailActivity : BaseViewBindingActivity(), + View.OnClickListener, TextWatcher { + private var resetPwd = false + private var isForgetPwd = false + private var cdt: CountDownTimer? = null + private var type = CodeType.UNBIND_PHONE + + companion object { + const val REQUEST_CHECK_VALID_PHONE = 1001 + + @JvmStatic + fun start(context: Context, resetPwd: Boolean) { + val intent = Intent(context, VerifyEmailActivity::class.java) + intent.putExtra("resetPwd", resetPwd) + context.startActivity(intent) + } + + @JvmStatic + fun startForResult(context: Activity, isForgetPwd: Boolean) { + val intent = Intent(context, VerifyEmailActivity::class.java) + intent.putExtra("isForgetPwd", isForgetPwd) + context.startActivityForResult(intent, REQUEST_CHECK_VALID_PHONE) + } + } + + override fun init() { + initWhiteTitleBar(ResUtil.getString(R.string._ver_24_text_verify)) + isForgetPwd = intent.getBooleanExtra("isForgetPwd", false) + resetPwd = intent.getBooleanExtra("resetPwd", false) + val userInfo = UserModel.get().cacheLoginUserInfo + if (userInfo != null && !TextUtils.isEmpty(userInfo.email)) { + binding.tvEmail.text = userInfo.email + } + initListener() + } + + private fun initListener() { + binding.tvGetCode.setOnClickListener(this) + binding.btnNext.setOnClickListener(this) + binding.etCode.addTextChangedListener(this) + } + + override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { + + } + + override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { + + } + + override fun afterTextChanged(p0: Editable?) { + binding.btnNext.isEnabled = !TextUtils.isEmpty(binding.etCode.text.toString()) + } + + @SuppressLint("CheckResult") + override fun onClick(v: View) { + when (v.id) { + R.id.tv_area_code -> { + AreaCodeActivity.startForResult(this, BindPhoneActivity.REQUEST_AREA_CODE) + } + R.id.tv_get_code -> { + if (isForgetPwd) { + type = CodeType.RESET_PAY_PSW + } + + + AuthModel.get() + .getEmailCode( + UserModel.get().cacheLoginUserInfo?.email, + type + ) + .compose(bindToLifecycle()) + .doOnError { throwable -> toast(throwable.message) } + .doOnSubscribe { + dialogManager.showProgressDialog( + this@VerifyEmailActivity, + ResUtil.getString(R.string.ui_setting_verifyphoneactivity_02) + ) + } + .doAfterTerminate { dialogManager.dismissDialog() } + .subscribe { s: String?, throwable: Throwable? -> + if (throwable != null) { + return@subscribe + } + toast(ResUtil.getString(R.string._ver_24_text_send_email_tips)) + startCounter() + } + } + R.id.btn_next -> { + clickNextButton() + } + } + } + + private fun clickNextButton() { + dialogManager.showProgressDialog( + this, + ResUtil.getString(R.string.ui_setting_verifyphoneactivity_08) + ) + + PayModel.get().verifyCodeEmail( + UserModel.get().cacheLoginUserInfo?.email, + binding.etCode.text.toString(), + ) + .compose(bindToLifecycle()) + .subscribe(object : BeanObserver() { + override fun onErrorMsg(error: String) { + dialogManager.dismissDialog() + toast(error) + } + + override fun onSuccess(s: String) { + dialogManager.dismissDialog() + type = CodeType.BIND_PHONE + if (resetPwd) { + ModifyPwdActivity.start( + this@VerifyEmailActivity, + ModifyPwdActivity.RESET_PAY_PWD + ) + finish() + } else if (isForgetPwd) { + setResult(RESULT_OK) + finish() + } else { + BindEmailActivity.start(context) + finish() + } + } + }) + } + + + private fun startCounter() { + stopCounter() + //开始倒计时 60s 间隔1s + binding.tvGetCode.isEnabled = false + binding.tvGetCode.setTextColor(ContextCompat.getColor(this, R.color.color_AFB1B3)) + cdt = object : CountDownTimer(60 * 1000, 100) { + override fun onTick(text: Long) { + showTextDown(text) + } + + override fun onFinish() { + resetBtn() + } + } + cdt?.start() + } + + private fun showTextDown(text: Long) { + val time = (text / 1000).toString() + "s" + binding.tvGetCode.text = time + } + + private fun stopCounter() { + cdt?.cancel() + cdt = null + } + + private fun resetBtn() { + stopCounter() + binding.tvGetCode.setTextColor(ContextCompat.getColor(this, R.color.color_ff8c03)) + binding.tvGetCode.isEnabled = true + binding.tvGetCode.text = getString(R.string.get) + } + + override fun needSteepStateBar(): Boolean { + return true + } + + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } + + override fun onDestroy() { + super.onDestroy() + dialogManager.dismissDialog() + stopCounter() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/setting/VerifyPhoneActivity.kt b/app/src/main/java/com/chwl/app/ui/setting/VerifyPhoneActivity.kt new file mode 100644 index 0000000..1618c3c --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/setting/VerifyPhoneActivity.kt @@ -0,0 +1,223 @@ +package com.chwl.app.ui.setting + +import android.annotation.SuppressLint +import android.app.Activity +import android.content.Context +import android.content.Intent +import android.os.CountDownTimer +import android.text.Editable +import android.text.TextUtils +import android.text.TextWatcher +import android.view.View +import androidx.core.content.ContextCompat +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.databinding.ActivityVerifyPhoneBinding +import com.chwl.app.ui.login.BindPhoneActivity +import com.chwl.core.auth.AuthModel +import com.chwl.core.code.CodeType +import com.chwl.core.pay.PayModel +import com.chwl.core.user.UserModel +import com.chwl.core.utils.net.BeanObserver +import com.chwl.library.common.util.doToastDeBug +import com.chwl.library.common.util.isVerify +import com.chwl.library.utils.ResUtil +import com.netease.nim.uikit.StatusBarUtil + +class VerifyPhoneActivity : BaseViewBindingActivity(), + View.OnClickListener, TextWatcher { + private var resetPwd = false + private var isForgetPwd = false + private var cdt: CountDownTimer? = null + private var type = CodeType.UNBIND_PHONE + + private var mPhone = ""; + private var mAreaCode = ""; + + companion object { + const val REQUEST_CHECK_VALID_PHONE = 1001 + + @JvmStatic + fun start(context: Context, resetPwd: Boolean) { + val intent = Intent(context, VerifyPhoneActivity::class.java) + intent.putExtra("resetPwd", resetPwd) + context.startActivity(intent) + } + + @JvmStatic + fun startForResult(context: Activity, isForgetPwd: Boolean) { + val intent = Intent(context, VerifyPhoneActivity::class.java) + intent.putExtra("isForgetPwd", isForgetPwd) + context.startActivityForResult(intent, REQUEST_CHECK_VALID_PHONE) + } + } + + override fun init() { + initWhiteTitleBar(ResUtil.getString(R.string.ui_setting_verifyphoneactivity_01)) + isForgetPwd = intent.getBooleanExtra("isForgetPwd", false) + resetPwd = intent.getBooleanExtra("resetPwd", false) + + UserModel.get().getUserInfoFromServerUpdate(AuthModel.get().currentUid,true) + .compose(bindToLifecycle()) + .doOnSuccess { + mPhone = it.phone + mAreaCode = it.phoneAreaCode + binding.tvPhone.text = "$mAreaCode $mPhone" + } + .doOnError { + + }.subscribe() + + initListener() + } + + private fun initListener() { + binding.tvGetCode.setOnClickListener(this) + binding.btnNext.setOnClickListener(this) + binding.etCode.addTextChangedListener(this) + } + + override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { + + } + + override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { + + } + + override fun afterTextChanged(p0: Editable?) { + binding.btnNext.isEnabled = !TextUtils.isEmpty(binding.etCode.text.toString()) + } + + @SuppressLint("CheckResult") + override fun onClick(v: View) { + when (v.id) { + R.id.tv_get_code -> { + if (!mPhone.isVerify() || !mAreaCode.isVerify()) { + + "没获取到手机号".doToastDeBug() + return + } + + + if (isForgetPwd) { + type = CodeType.RESET_PAY_PSW + } + AuthModel.get() + .getSmsCode( + mAreaCode, + mAreaCode + mPhone, + type + ) + .compose(bindToLifecycle()) + .doOnError { throwable -> toast(throwable.message) } + .doOnSubscribe { + dialogManager.showProgressDialog( + this@VerifyPhoneActivity, + ResUtil.getString(R.string.ui_setting_verifyphoneactivity_02) + ) + } + .doAfterTerminate { dialogManager.dismissDialog() } + .subscribe { s: String?, throwable: Throwable? -> + if (throwable != null) { + return@subscribe + } + toast(ResUtil.getString(R.string.ui_setting_verifyphoneactivity_03)) + startCounter() + } + } + R.id.btn_next -> { + clickNextButton() + } + } + } + + private fun clickNextButton() { + dialogManager.showProgressDialog( + this, + ResUtil.getString(R.string.ui_setting_verifyphoneactivity_08) + ) + PayModel.get().verifyCode( + mAreaCode, + mAreaCode + mPhone, + binding.etCode.text.toString(), + ) + .compose(bindToLifecycle()) + .subscribe(object : BeanObserver() { + override fun onErrorMsg(error: String) { + dialogManager.dismissDialog() + toast(error) + } + + override fun onSuccess(s: String) { + dialogManager.dismissDialog() + type = CodeType.BIND_PHONE + if (resetPwd) { + ModifyPwdActivity.start( + this@VerifyPhoneActivity, + ModifyPwdActivity.RESET_PAY_PWD + ) + finish() + } else if (isForgetPwd) { + setResult(RESULT_OK) + finish() + } else { + BindPhoneActivity.start(context) + finish() + } + } + }) + } + + + private fun startCounter() { + stopCounter() + //开始倒计时 60s 间隔1s + binding.tvGetCode.isEnabled = false + binding.tvGetCode.setTextColor(ContextCompat.getColor(this, R.color.color_AFB1B3)) + cdt = object : CountDownTimer(60 * 1000, 100) { + override fun onTick(text: Long) { + showTextDown(text) + } + + override fun onFinish() { + resetBtn() + } + } + cdt?.start() + } + + private fun showTextDown(text: Long) { + val time = (text / 1000).toString() + "s" + binding.tvGetCode.text = time + } + + private fun stopCounter() { + cdt?.cancel() + cdt = null + } + + private fun resetBtn() { + stopCounter() + binding.tvGetCode.setTextColor(ContextCompat.getColor(this, R.color.color_ff8c03)) + binding.tvGetCode.isEnabled = true + binding.tvGetCode.text = getString(R.string.get) + } + + override fun needSteepStateBar(): Boolean { + return true + } + + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } + + override fun onDestroy() { + super.onDestroy() + dialogManager.dismissDialog() + stopCounter() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/setting/VipSetActivity.kt b/app/src/main/java/com/chwl/app/ui/setting/VipSetActivity.kt new file mode 100644 index 0000000..5be25ad --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/setting/VipSetActivity.kt @@ -0,0 +1,202 @@ +package com.chwl.app.ui.setting + +import android.content.Context +import android.content.Intent +import android.view.View +import android.widget.ImageView +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.databinding.VipSetActivityBinding +import com.chwl.core.auth.AuthModel +import com.chwl.core.bean.response.ServiceResult +import com.chwl.core.user.UserModel +import com.chwl.core.utils.net.RxHelper +import com.chwl.library.common.util.setMargin +import com.chwl.library.common.util.setViewWH +import com.chwl.library.net.rxnet.RxNet +import com.chwl.library.utils.ResUtil +import com.example.lib_utils.ktx.getDimension +import com.example.lib_utils.log.ILog +import com.google.gson.JsonElement +import com.hjq.toast.ToastUtils +import com.netease.nim.uikit.StatusBarUtil +import io.reactivex.Single +import retrofit2.http.GET +import retrofit2.http.Query + +class VipSetActivity : BaseViewBindingActivity(), ILog, View.OnClickListener { + + companion object { + var index = 0 + @JvmStatic + fun start(context: Context) { + val starter = Intent(context, VipSetActivity::class.java) + context.startActivity(starter) + } + } + + override fun init() { + binding.click = this + initTitleBar(ResUtil.getString(R.string.vipSetTitle)) + + initVipIcons(binding.vipSetIcons1 + , R.drawable.vip_icon_lv5 + , R.drawable.vip_icon_lv6 + , R.drawable.vip_icon_lv7 + , R.drawable.vip_icon_lv8 + , R.drawable.vip_icon_lv9 + ) + initVipIcons(binding.vipSetIcons2 + , R.drawable.vip_icon_lv6 + , R.drawable.vip_icon_lv7 + , R.drawable.vip_icon_lv8 + , R.drawable.vip_icon_lv9 + ) + initVipIcons(binding.vipSetIcons3 + , R.drawable.vip_icon_lv7 + , R.drawable.vip_icon_lv8 + , R.drawable.vip_icon_lv9 + ) + initVipIcons(binding.vipSetIcons4 + , R.drawable.vip_icon_lv8 + , R.drawable.vip_icon_lv9 + ) + initVipIcons(binding.vipSetIcons5 + , R.drawable.vip_icon_lv7 + , R.drawable.vip_icon_lv8 + , R.drawable.vip_icon_lv9 + ) + + initVipIcons(binding.vipSetIcons6 + , R.drawable.vip_icon_lv6 + , R.drawable.vip_icon_lv7 + , R.drawable.vip_icon_lv8 + , R.drawable.vip_icon_lv9 + ) + + if (AuthModel.get().isLogin) { + UserModel.get().getUserInfoFromServerUpdate(AuthModel.get().currentUid,true) + .compose(bindToLifecycle()) + .doOnSuccess { + setSwitchView(binding.vipSetSwitch1, it?.userVipInfoVO?.preventFollow?:false)//不被关注 + setSwitchView(binding.vipSetSwitch2, it?.userVipInfoVO?.preventTrace?:false)//防跟随 + setSwitchView(binding.vipSetSwitch3, it?.userVipInfoVO?.enterHide?:false)//开关隐身进房状态 + setSwitchView(binding.vipSetSwitch4, it?.userVipInfoVO?.preventKick?:false)//防踢 + setSwitchView(binding.vipSetSwitch5, it?.userVipInfoVO?.privateChatLimit?:false)//無打擾 + setSwitchView(binding.vipSetSwitch6, it?.userVipInfoVO?.visitListView?:false)//无痕浏览 + } + .doOnError { + + } + .subscribe() + } + + } + + override fun needSteepStateBar(): Boolean { + return true + } + + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } + + private fun initVipIcons(layout:android.widget.LinearLayout,vararg ids:Int){ + ids.forEach { + val icon = ImageView(context); + layout.addView(icon) + icon.setViewWH(R.dimen.dp_43.getDimension().toInt(),R.dimen.dp_20.getDimension().toInt(), isDP = false ) + icon.setMargin(end = R.dimen.dp_5.getDimension().toInt(), isDP = false) + icon.setBackgroundResource(it) + } + } + + private fun switchClick(view: View) { + val value = view.tag + if (value != null && value is Boolean && view is ImageView) { + switchApi(view,!value) + .doOnSuccess { + view.tag = !value + setSwitchView(view,!value) + UserModel.get().getUserInfoFromServerUpdate(AuthModel.get().currentUid,true).subscribe() + } + .doOnError { + it?.message?.let { + ToastUtils.show(it) + } + } + .compose(bindToLifecycle()) + .subscribe() + } + } + + private fun switchApi(view : ImageView,value:Boolean) : Single { + when (view.id) { + binding.vipSetSwitch1.id -> return api.notFollowed(value).compose(RxHelper.handleIgnoreData()).compose(RxHelper.handleSchedulers()) + binding.vipSetSwitch2.id -> return api.notTrace(value).compose(RxHelper.handleIgnoreData()).compose(RxHelper.handleSchedulers()) + binding.vipSetSwitch3.id -> return api.invisible(value).compose(RxHelper.handleIgnoreData()).compose(RxHelper.handleSchedulers()) + binding.vipSetSwitch4.id -> return api.notKick(value).compose(RxHelper.handleIgnoreData()).compose(RxHelper.handleSchedulers()) + binding.vipSetSwitch5.id -> return api.chatLimit(value).compose(RxHelper.handleIgnoreData()).compose(RxHelper.handleSchedulers()) + binding.vipSetSwitch6.id -> return api.visitHide(value).compose(RxHelper.handleIgnoreData()).compose(RxHelper.handleSchedulers()) + else -> return api.notFollowed(!value).compose(RxHelper.handleIgnoreData()).compose(RxHelper.handleSchedulers()) + } + } + + private fun setSwitchView(view: ImageView, isSwitch: Boolean) { + view.tag = isSwitch + view.setImageResource(if (isSwitch) R.drawable.icon_room_set_lock_true else R.drawable.icon_room_set_lock_false) + } + + private final val api = RxNet.create(Api::class.java); + interface Api{ + /** + * 不被关注 + */ + @GET("/vip/changePreventFollow") + fun notFollowed(@Query("open") open: Boolean): Single> + /** + * 防跟随 + */ + @GET("/vip/changePreventTrace") + fun notTrace(@Query("open") open: Boolean): Single> + /** + * 开关隐身进房状态 + */ + @GET("/vip/changeInvisibleInRoom") + fun invisible(@Query("open") open: Boolean): Single> + /** + * 防踢 + */ + @GET("/vip/changePreventKick") + fun notKick(@Query("open") open: Boolean): Single> + /** + * 無打擾 + */ + @GET("/vip/changePrivateChatLimit") + fun chatLimit(@Query("open") open: Boolean): Single> + + /** + * 无声浏览 + */ + @GET("/vip/visitHide") + fun visitHide(@Query("open") open: Boolean): Single> + } + + + override fun onClick(v: View?) { + v?.let { + when (it) { + binding.vipSetSwitch1, + binding.vipSetSwitch2, + binding.vipSetSwitch3, + binding.vipSetSwitch4, + binding.vipSetSwitch5, + binding.vipSetSwitch6 -> switchClick(it) + } + } + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/setting/adapter/RoomShieldAdapter.kt b/app/src/main/java/com/chwl/app/ui/setting/adapter/RoomShieldAdapter.kt new file mode 100644 index 0000000..45ebbf1 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/setting/adapter/RoomShieldAdapter.kt @@ -0,0 +1,25 @@ +package com.chwl.app.ui.setting.adapter + +import android.widget.ImageView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.ui.utils.ImageLoadUtilsV2 +import com.chwl.app.ui.utils.load +import com.chwl.core.set.bean.ShieldInfo +import com.chwl.core.utils.CoreTextUtils + +class RoomShieldAdapter : BaseQuickAdapter(R.layout.item_room_shield) { + + override fun convert(helper: BaseViewHolder, item: ShieldInfo) { + helper.apply { + getView(R.id.iv_room_image).load(item.avatar) + setText(R.id.tv_room_title, item.title) + setText(R.id.tv_id, "ID:${item.erbanNo}") + } + helper.setGone(R.id.iv_room_tag, !CoreTextUtils.isEmptyText(item.tagPict)) + ImageLoadUtilsV2.loadImage(helper.getView(R.id.iv_room_tag), item.tagPict) + helper.addOnClickListener(R.id.tv_unmask) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/setting/bean/PermissionEntity.kt b/app/src/main/java/com/chwl/app/ui/setting/bean/PermissionEntity.kt new file mode 100644 index 0000000..df75446 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/setting/bean/PermissionEntity.kt @@ -0,0 +1,50 @@ +package com.chwl.app.ui.setting.bean + +import android.Manifest +import android.os.Build +import com.chwl.app.R +import com.chwl.core.utils.CoreTextUtils +import com.chwl.library.utils.ResUtil + +enum class PermissionEntity( + val alias: String, + val description: String, + var icon: Int = R.drawable.icon_permission_common, + val permissionName: Array +) { + CONTACT( + ResUtil.getString(R.string.setting_bean_permissionentity_05), + ResUtil.getString(R.string.setting_bean_permissionentity_06), + R.drawable.icon_permission_common, + arrayOf( + Manifest.permission.READ_CONTACTS, + Manifest.permission.WRITE_CONTACTS, + Manifest.permission.GET_ACCOUNTS + ) + ), + MICROPHONE( + ResUtil.getString(R.string.setting_bean_permissionentity_07), + ResUtil.getString(R.string.setting_bean_permissionentity_08), + R.drawable.icon_permission_mic, + arrayOf(Manifest.permission.RECORD_AUDIO) + ), + STORAGE( + ResUtil.getString(R.string.setting_bean_permissionentity_011), ResUtil.getString(R.string.setting_bean_permissionentity_012), R.drawable.icon_permission_storage, + arrayOf( + Manifest.permission.READ_EXTERNAL_STORAGE + ) + ); + + + + companion object { + fun fetchPermission(name: String): PermissionEntity? { + if (CoreTextUtils.isEmptyText(name)) return null + + values().forEach { + if (it.permissionName.contains(name)) return it + } + return null + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/setting/viewmodel/SetViewModel.kt b/app/src/main/java/com/chwl/app/ui/setting/viewmodel/SetViewModel.kt new file mode 100644 index 0000000..b5bd65b --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/setting/viewmodel/SetViewModel.kt @@ -0,0 +1,41 @@ +package com.chwl.app.ui.setting.viewmodel + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import com.chwl.app.base.BaseViewModel +import com.chwl.core.bean.response.ListResult +import com.chwl.core.set.bean.ShieldInfo +import com.chwl.core.set.model.SetModel +import com.chwl.core.utils.extension.toast + +class SetViewModel : BaseViewModel() { + + private val _shieldRoomLiveData = MutableLiveData>() + val shieldRoomLiveData: LiveData> = _shieldRoomLiveData + + private val _unMaskLiveData = MutableLiveData() + val unMaskLiveData: LiveData = _unMaskLiveData + + fun getShieldRoom(pageNum: Int, pageSize: Int) { + safeLaunch( + onError = { + it.message.toast() + _shieldRoomLiveData.value = ListResult.failed(pageNum) + }, + block = { + val result = SetModel.getShieldRoom(pageNum, pageSize) + _shieldRoomLiveData.value = ListResult.success(result, pageNum) + } + ) + } + + fun setUnMask(roomUid: Long, type: Int) { + safeLaunch( + true, + block = { + _unMaskLiveData.value = SetModel.setUnMask(roomUid, type) + } + ) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/user/activity/AboutActivity.java b/app/src/main/java/com/chwl/app/ui/user/activity/AboutActivity.java new file mode 100644 index 0000000..4c885fa --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/activity/AboutActivity.java @@ -0,0 +1,51 @@ +package com.chwl.app.ui.user.activity; + +import android.content.Intent; +import android.os.Bundle; +import android.widget.TextView; + +import com.netease.nim.uikit.StatusBarUtil; +import com.chwl.app.BuildConfig; +import com.chwl.app.R; +import com.chwl.app.base.BaseActivity; +import com.chwl.app.ui.setting.LabActivity; +import com.chwl.library.utils.config.BasicConfig; + +public class AboutActivity extends BaseActivity { + + private TextView mTvVersions; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_about); + initWhiteTitleBar(getString(R.string.about_app)); + initView(); + initData(); + } + + private void initData() { + mTvVersions.setText(getString(R.string.setting_version, BasicConfig.getLocalVersionName(getApplicationContext()))); + } + + private void initView() { + mTvVersions = findViewById(R.id.versions); + + if (BuildConfig.DEBUG) { + findViewById(R.id.img_about_logo).setOnClickListener(v -> + startActivity(new Intent(this, LabActivity.class))); + } + } + + @Override + protected boolean needSteepStateBar() { + return true; + } + + @Override + protected void setStatusBar() { + super.setStatusBar(); + StatusBarUtil.transparencyBar(this); + StatusBarUtil.StatusBarLightMode(this); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/user/activity/ShowPhotoActivity.java b/app/src/main/java/com/chwl/app/ui/user/activity/ShowPhotoActivity.java new file mode 100644 index 0000000..d0ed4ae --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/activity/ShowPhotoActivity.java @@ -0,0 +1,112 @@ +package com.chwl.app.ui.user.activity; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.Nullable; +import androidx.viewpager.widget.ViewPager; + +import com.chwl.app.R; +import com.chwl.app.base.BaseActivity; +import com.chwl.app.ui.user.adapter.PhotoAdapter; +import com.chwl.core.user.bean.UserPhoto; + +import java.util.ArrayList; + +import io.realm.RealmList; + +public class ShowPhotoActivity extends BaseActivity { + private ImageView mImageView; + private TextView imgCount; + private ViewPager viewPager; + private UserPhoto userPhoto; + private PhotoAdapter photoAdapter; + private ShowPhotoActivity mActivity; + private int position; + private ArrayList photoUrls; + private RealmList userPhotos = new RealmList<>(); +// private RealmList userPhotoRealmList; + + public static void start(Context context,String url) { + //创建一个集合拿来做用户所有照片信息 + ArrayList userPhotos = new ArrayList<>(); + UserPhoto newPhoto = new UserPhoto(); + newPhoto.setPid(1); + newPhoto.setPhotoUrl(url); + userPhotos.add(newPhoto); + Intent intent = new Intent(context, ShowPhotoActivity.class); + intent.putExtra("position", 0); + intent.putExtra("photoList", userPhotos); + context.startActivity(intent); + } + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_show_photo); + mActivity = this; + initView(); + initData(); + setListener(); + } + + private void setListener() { +// mImageView.setOnTouchListener(new View.OnTouchListener() { +// @Override +// public boolean onTouch(View v, MotionEvent event) { +// return false; +// } +// }); + viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { +// viewPager.setCurrentItem(position); +// imgCount.setText((position + 1) + "/" + photoAdapter.getCount()); + } + + @Override + public void onPageSelected(int position) { + if (position == 0) { + imgCount.setText((position + 1) + "/" + photoAdapter.getCount()); + } + imgCount.setText((position + 1) + "/" + photoAdapter.getCount()); + + } + + @Override + public void onPageScrollStateChanged(int state) { + + } + }); + + photoAdapter.setmImageOnclickListener(() -> finish()); + } + + private void initData() { + position = getIntent().getIntExtra("position",1); + System.out.println("position==="+position); +// userPhoto = (UserPhoto) getIntent().getSerializableExtra("userPhoto"); + photoUrls = (ArrayList) getIntent().getSerializableExtra("photoList"); +// UserInfo userInfo = UserModel.get().getCacheUserInfoByUid(AuthModel.get().getCurrentUid()); +// RealmList userPhotos = userInfo.getPrivatePhoto(); + if (photoUrls != null) { + photoAdapter = new PhotoAdapter(mActivity, photoUrls); + viewPager.setAdapter(photoAdapter); + viewPager.setCurrentItem(position); + imgCount.setText((position + 1) + "/" + photoAdapter.getCount()); + } + } + private void initView() { +// mImageView = (ImageView) findViewById(R.id.photoview); + imgCount = (TextView) findViewById(R.id.tv_count); + viewPager = (ViewPager) findViewById(R.id.viewpager); + } + + @Override + protected boolean needSteepStateBar() { + return true; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/user/activity/UserCpListActivity.kt b/app/src/main/java/com/chwl/app/ui/user/activity/UserCpListActivity.kt new file mode 100644 index 0000000..eaad53c --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/activity/UserCpListActivity.kt @@ -0,0 +1,235 @@ +package com.chwl.app.ui.user.activity + +import android.content.Context +import android.content.Intent +import android.view.View +import androidx.core.view.isVisible +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.chwl.app.R +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.base.TitleBar +import com.chwl.app.base.TitleBar.ImageAction +import com.chwl.app.common.EmptyViewHelper +import com.chwl.app.common.widget.dialog.DialogManager +import com.chwl.app.common.widget.dialog.DialogManager.OkCancelDialogListener +import com.chwl.app.databinding.ActivityUserCpListBinding +import com.chwl.app.ui.user.adapter.UserCpListAdapter +import com.chwl.app.ui.user.dialog.CpRelationChangeDialog +import com.chwl.app.ui.webview.CommonWebViewActivity +import com.chwl.core.UriProvider +import com.chwl.core.bean.response.ServiceResult +import com.chwl.core.contacts.MyConstant +import com.chwl.core.user.bean.UserCPListBean +import com.chwl.core.utils.LogUtils +import com.chwl.core.utils.net.RxHelper +import com.chwl.library.common.util.doToast +import com.chwl.library.net.rxnet.RxNet +import com.chwl.library.utils.ResUtil +import com.example.lib_utils.ktx.getString +import com.google.gson.JsonElement +import com.netease.nim.uikit.StatusBarUtil +import io.reactivex.Single +import retrofit2.http.GET +import retrofit2.http.POST +import retrofit2.http.Query + +class UserCpListActivity : BaseViewBindingActivity() { + + lateinit var mAdapter : UserCpListAdapter + var mPageNum = 1; + var mPageSize = 20; + + companion object{ + fun start(context: Context) { + val intent = Intent(context, UserCpListActivity::class.java) + context.startActivity(intent) + } + } + + override fun init() { + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + initTitle() + initRvList() + loadData() + } + + private fun initTitle() { + initDarkTitleBar(ResUtil.getString(R.string.My_Cp)) + val titleBar = findViewById(R.id.title_bar) as TitleBar + titleBar.addAction(object : ImageAction(R.drawable.ic_cp_list_more) { + override fun performAction(view: View?) { + CommonWebViewActivity.start(this@UserCpListActivity, UriProvider.getCpRule()) + } + }) + } + + private fun initRvList(){ + mAdapter = UserCpListAdapter(R.layout.item_user_cp_list,1) + binding.rvList.layoutManager = GridLayoutManager(context,1,RecyclerView.VERTICAL,false) + binding.rvList.adapter = mAdapter + mAdapter.setOnItemChildClickListener { adapter, view, position -> + when (view.id) { + R.id.cancel -> { + mAdapter.data.getOrNull(position)?.let { + cancelCp(position, it) + } + } + + R.id.userAvatarCp -> { + mAdapter.data.getOrNull(position)?.let { + UserInfoActivity.Companion.start(context, it.cpUid) + } + } + + R.id.btnSwitch -> { + mAdapter.data.getOrNull(position)?.let { + changeCpRelationType(position, it) + } + } + else -> {} + } + } + mAdapter.setOnLoadMoreListener { + loadData(true) + } + mAdapter.setEmptyView(EmptyViewHelper.createEmptyTextView(this@UserCpListActivity,R.string.empty_data.getString())) + } + + private fun loadData(isAdd: Boolean = false) { + if (!isAdd) { + mPageNum = 1 + } + getCpList() + .compose(bindToLifecycle()) + .doOnSuccess { + if (mPageNum == 1) { + mAdapter.setNewData(it) + } else { + mAdapter.addData(it) + } + + if (it.size == mPageSize) { + mPageNum += 1 + mAdapter.setEnableLoadMore(true) + binding.noMore.isVisible = false + } else { + mAdapter.setEnableLoadMore(false) + if (mAdapter?.data?.isEmpty() == true){ + binding.noMore.isVisible = true + } + } + mAdapter.loadMoreComplete() + } + .doOnError { + LogUtils.d(" error = ${it.message}") + mAdapter.loadMoreEnd() + } + .subscribe() + } + + private fun cancelCp(position: Int, data: UserCPListBean) { + val mDialogManager = DialogManager(context) + mDialogManager?.showOkCancelDialog(ResUtil.getString(R.string.CP_Cancel,data.cancelGoldNum,data.cpNick), true, object : + OkCancelDialogListener { + override fun onCancel() { + mDialogManager?.dismissDialog() + } + + override fun onOk() { + postCpCancel(data.uid,data.cpUid,data.cancelGoldNum) + .compose(bindToLifecycle()) + .doOnSuccess { + mAdapter.remove(position) + toast(ResUtil.getString(R.string.CP_Cancel_Success,data.cpNick)) + } + .subscribe() + mDialogManager?.dismissDialog() + } + }) + } + + + private fun changeCpRelationType(position: Int, data: UserCPListBean) { + if (data.clickFlag == MyConstant.CP.clickFlag.def){ + val dialog = CpRelationChangeDialog.newInstance(data.relationNameType) + dialog.mActionCallBack = object : BaseDialogFragment.Action { + override fun onAction(type: Int, any: Any?) { + if (type != -1) { + changeCpRelationType(data.uid,data.cpUid,type) + .compose(bindToLifecycle()) + .doOnSuccess { +// mAdapter.data.getOrNull(position)?.let { +// data.relationType = type +// mAdapter.notifyItemChanged(position) +// } + R.string.v26_cp_relationship_change_tips.doToast() + } + .doOnError { + it?.message?.doToast() + }.subscribe() + dialog.dismiss() + } + } + } + dialog.show(context) + }else if(data.clickFlag == MyConstant.CP.clickFlag.applying){ + getString(R.string.v26_change_cp_limit_1).doToast() + }else if(data.clickFlag == MyConstant.CP.clickFlag.success){ + getString(R.string.v26_change_cp_limit_2).doToast() + } + } + + + /** + * 获-cp列表 + */ + private fun getCpList(): Single> { + return api.getCpList(mPageNum,mPageSize) + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()) + } + + private fun postCpCancel(uid: Long,loverUid: Long,goldNum: Long): Single { + return api.postCpCancel(uid,loverUid,goldNum) + .compose(RxHelper.handleIgnoreData()) + .compose(RxHelper.handleSchedulers()) + } + + private fun changeCpRelationType(uid: Long, loverUid: Long, relationType: Int): Single { + return api.changeCpRelationType(uid,loverUid,relationType) + .compose(RxHelper.handleIgnoreData()) + .compose(RxHelper.handleSchedulers()) + } + + + private val api: Api = RxNet.create(Api::class.java); + interface Api { + /** + * 获-cp列表 + * page=1 + * pageSize=10 + */ + @GET("/user/cp/list") + fun getCpList(@Query("page") page: Int,@Query("pageSize") pageSize: Int=20): Single>> + + /** + * 取消cp---- + * Long uid + * Long loverUid + * Long goldNum //金币(列表有返回该字段:cancelGoldNum) + */ + @POST("/user/cp/cancel") + fun postCpCancel(@Query("uid") uid: Long,@Query("loverUid") loverUid: Long,@Query("goldNum") goldNum: Long): Single> + + /** + * 切换cp关系---- + */ + @POST("/user/cp/nameChange") + fun changeCpRelationType(@Query("uid") uid: Long,@Query("loverUid") loverUid: Long,@Query("relationNameType") relationNameType: Int): Single> + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/user/activity/UserForbidActivity.kt b/app/src/main/java/com/chwl/app/ui/user/activity/UserForbidActivity.kt new file mode 100644 index 0000000..fb2c4ed --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/activity/UserForbidActivity.kt @@ -0,0 +1,145 @@ +package com.chwl.app.ui.user.activity + +import android.content.Context +import android.content.Intent +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.bindadapter.BaseBindingAdapter +import com.chwl.app.bindadapter.BaseBindingViewHolder +import com.chwl.app.constants.BundleKeys +import com.chwl.app.databinding.ActivityUserForbidBinding +import com.chwl.app.databinding.ItemForbidTimeBinding +import com.chwl.app.ui.utils.loadAvatar +import com.chwl.core.bean.response.ServiceResult +import com.chwl.core.utils.net.RxHelper +import com.chwl.library.common.util.ClickUtils.click +import com.chwl.library.common.util.doToast +import com.chwl.library.common.util.isVerify +import com.chwl.library.net.rxnet.RxNet +import com.example.lib_utils.ktx.getString +import com.google.gson.JsonElement +import io.reactivex.Single +import retrofit2.http.GET +import retrofit2.http.POST +import retrofit2.http.Query + +class UserForbidActivity : BaseViewBindingActivity() { + + + companion object{ + + fun start(context: Context,nick:String,avatar:String,erBanNo:Long,targetId:Long) { + val intent = Intent(context, UserForbidActivity::class.java) + intent.putExtra(BundleKeys.NICK,nick) + intent.putExtra(BundleKeys.AVATAR,avatar) + intent.putExtra(BundleKeys.ER_BAN_NO,erBanNo) + intent.putExtra(BundleKeys.TARGET_ID,targetId) + context.startActivity(intent) + } + + } + + val nick : String by lazy { intent.getStringExtra(BundleKeys.NICK)?:"" } + val avatar : String by lazy { intent.getStringExtra(BundleKeys.AVATAR)?:"" } + val erBanNo : Long by lazy { intent.getLongExtra(BundleKeys.ER_BAN_NO,0L) } + val targetId : Long by lazy { intent.getLongExtra(BundleKeys.TARGET_ID,0L) } + var mTime = 0 + lateinit var mAdapter:TimeAdapter + override fun init() { + + initLightTitleBar(R.string.forbid.getString()) + + binding.nick.text = nick + binding.avatar.loadAvatar(avatar) + binding.uid.text = "ID: ${erBanNo}" + + mAdapter = TimeAdapter() + + mAdapter.setOnItemClickListener { adapter, view, position -> + mAdapter.mPosition = position + mTime = mAdapter?.data?.get(position)?:0 + mAdapter.notifyDataSetChanged() + } + + binding.rvList.layoutManager = GridLayoutManager(context,2,RecyclerView.VERTICAL,false) + binding.rvList.adapter = mAdapter + + getBlockTime().compose(bindToLifecycle()) + .doOnSuccess { + if (it.isVerify()) { + mAdapter.setNewData(it) + } + } + .doOnError { + it?.message?.doToast() + }.subscribe() + + + binding.confirm.click { + val etDesc = binding.etDesc.text?.toString() ?: "" + if (targetId > 0) { + postBlock(targetId, mTime, etDesc).compose(bindToLifecycle()) + .doOnSuccess { + R.string.doSuccess.doToast() + finish() + } + .doOnError { + it?.message?.doToast() + }.subscribe() + } + } + + } + + class TimeAdapter : BaseBindingAdapter() { + + var mPosition = -1 + + override fun convert(helper: BaseBindingViewHolder, item: Int) { + helper?.binding?.time?.text = R.string.forbidTime.getString(item.toString()) + helper?.binding?.check?.isChecked = mPosition == helper.bindingAdapterPosition + + } + } + + + + /** + * 获-封禁时间 + */ + private fun getBlockTime(): Single> { + return api.getBlockTime() + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()) + } + + + private fun postBlock(uid: Long,hours: Int,blockReason: String): Single { + return api.postBlock(uid,hours,blockReason) + .compose(RxHelper.handleIgnoreData()) + .compose(RxHelper.handleSchedulers()) + } + + + private val api: Api = RxNet.create(Api::class.java); + interface Api { + + /** + * 获-封禁时间 + */ + @GET("/user/blockTime") + fun getBlockTime(): Single>> + + /** + * 封禁 + */ + @POST("/user/block") + fun postBlock(@Query("uid") uid: Long, @Query("hours") hours: Int, @Query("blockReason") blockReason: String): Single> + + } + + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/user/activity/UserGiftActivity.kt b/app/src/main/java/com/chwl/app/ui/user/activity/UserGiftActivity.kt new file mode 100644 index 0000000..0b64eb9 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/activity/UserGiftActivity.kt @@ -0,0 +1,56 @@ +package com.chwl.app.ui.user.activity + +import android.widget.LinearLayout +import android.widget.TextView +import androidx.fragment.app.Fragment +import androidx.viewpager.widget.ViewPager +import com.netease.nim.uikit.StatusBarUtil +import com.chwl.app.R +import com.chwl.app.avroom.adapter.CommonVPAdapter +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.databinding.ActivityUserGiftBinding +import com.chwl.app.ui.user.fragment.UserInfoGiftFragment +import com.chwl.app.ui.user.adapter.CommonWrapIndicatorAdapter +import com.chwl.app.ui.widget.magicindicator.MagicIndicator +import com.chwl.app.ui.widget.magicindicator.ViewPagerHelper +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.CommonNavigator +import com.chwl.library.utils.ResUtil + +class UserGiftActivity : BaseViewBindingActivity() { + + override fun init() { + initWhiteTitleBar(ResUtil.getString(R.string.ui_user_usergiftactivity_01)) + + val viewPager = binding.viewPager + val magicIndicator: MagicIndicator = binding.magicIndicator + val fragmentList: MutableList = ArrayList(2) + //礼物类型 1:普通礼物;2:辛运礼物 + fragmentList.add(UserInfoGiftFragment.newInstance(1, true)) + fragmentList.add(UserInfoGiftFragment.newInstance(2, true)) + val tagList: MutableList = ArrayList(2) + tagList.add(getString(R.string.me_ordinary_gift)) + tagList.add(getString(R.string.me_lucky_gift)) + val commonNavigator = CommonNavigator(context) + commonNavigator.setTitleWrapContent(true) + val magicIndicatorAdapter = CommonWrapIndicatorAdapter(context, tagList) + magicIndicatorAdapter.setOnItemSelectListener { position: Int, view: TextView? -> + viewPager.currentItem = position + } + commonNavigator.adapter = magicIndicatorAdapter + magicIndicator.navigator = commonNavigator + commonNavigator.titleContainer.showDividers = LinearLayout.SHOW_DIVIDER_MIDDLE + viewPager.offscreenPageLimit = 2 + viewPager.adapter = CommonVPAdapter(supportFragmentManager, lifecycle, fragmentList) + ViewPagerHelper.bind(magicIndicator, viewPager) + } + + override fun needSteepStateBar(): Boolean { + return true + } + + override fun setStatusBar() { + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/user/activity/UserInfoActivity.java b/app/src/main/java/com/chwl/app/ui/user/activity/UserInfoActivity.java new file mode 100644 index 0000000..0efeea0 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/activity/UserInfoActivity.java @@ -0,0 +1,955 @@ +package com.chwl.app.ui.user.activity; + +import static com.chwl.app.ui.user.activity.UserInfoActivity.IdentityState.OWN; + +import android.annotation.SuppressLint; +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; +import android.content.Intent; +import android.content.res.ColorStateList; +import android.graphics.Color; +import android.text.TextUtils; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.core.content.ContextCompat; +import androidx.core.widget.NestedScrollView; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.ViewModelProvider; +import androidx.viewpager2.widget.ViewPager2; + +import com.chwl.app.R; +import com.chwl.app.UIHelper; +import com.chwl.app.audio.helper.AudioPlayerHelper; +import com.chwl.app.avroom.ButtonItemFactory; +import com.chwl.app.avroom.activity.AVRoomActivity; +import com.chwl.app.avroom.adapter.CommonVPAdapter; +import com.chwl.app.base.BaseBindingActivity; +import com.chwl.app.common.widget.dialog.CommonPopupDialog; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.app.databinding.ActivityUserInfoBinding; +import com.chwl.app.databinding.LayoutOfficialMaskBinding; +import com.chwl.app.ui.im.avtivity.NimFriendModel; +import com.chwl.app.ui.im.avtivity.NimP2PMessageActivity; +import com.chwl.app.ui.user.adapter.UserInfoCpListAdapter; +import com.chwl.app.ui.user.adapter.UserInfoIndicatorAdapter; +import com.chwl.app.ui.user.adapter.UserInfoTopAlbumAdapter; +import com.chwl.app.ui.user.adapter.UserPhotoAdapter; +import com.chwl.app.ui.user.fragment.UserInfoDataFragment; +import com.chwl.app.ui.user.fragment.UserInfoDynamicFragment; +import com.chwl.app.ui.user.viewmodel.UserInfoViewModel; +import com.chwl.app.ui.utils.CpUtils; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.app.ui.utils.VipUtil; +import com.chwl.app.ui.widget.ButtonItem; +import com.chwl.app.ui.widget.ObservableScrollView; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.CommonNavigator; +import com.chwl.app.utils.AppBarStateChangeListener; +import com.chwl.app.utils.AvatarHelper; +import com.chwl.app.utils.RegexUtil; +import com.chwl.app.vip.util.VipHelper; +import com.chwl.core.XConstants; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.decoration.headwear.bean.HeadWearInfo; +import com.chwl.core.im.friend.IMFriendModel; +import com.chwl.core.level.UserLevelVo; +import com.chwl.core.praise.PraiseModel; +import com.chwl.core.praise.event.IsLikedEvent; +import com.chwl.core.praise.event.PraiseEvent; +import com.chwl.core.user.UserInfoUiMgr; +import com.chwl.core.user.UserModel; +import com.chwl.core.user.bean.NameplateInfo; +import com.chwl.core.user.bean.UserCPListBean; +import com.chwl.core.user.bean.UserDetailInfo; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.core.user.bean.UserPhoto; +import com.chwl.core.user.event.LoginUserInfoUpdateEvent; +import com.chwl.core.utils.CoreLogger; +import com.chwl.core.utils.LogUtils; +import com.chwl.library.annatation.ActLayoutRes; +import com.chwl.library.common.util.OtherExtKt; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.widget.SVGAView; +import com.example.lib_utils.AppUtils; +import com.example.lib_utils.UiUtils; +import com.google.android.material.appbar.AppBarLayout; +import com.netease.nim.uikit.StatusBarUtil; +import com.netease.nim.uikit.common.util.sys.TimeUtil; +import com.opensource.svgaplayer.SVGADrawable; +import com.opensource.svgaplayer.SVGAImageView; +import com.opensource.svgaplayer.SVGAParser; +import com.opensource.svgaplayer.SVGAVideoEntity; +import com.zhpan.bannerview.constants.IndicatorGravity; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * create by lvzebiao on 2018/8/31 + */ +@ActLayoutRes(R.layout.activity_user_info) +public class UserInfoActivity extends BaseBindingActivity + implements UserPhotoAdapter.ImageClickListener, ObservableScrollView.ScrollViewListener { + + public static final int REQUEST_CODE_UPDATE_VOICE = 1; + + private int identityState = IdentityState.NON; + private UserInfoActivity mActivity; + private long userId = 0; + private UserInfo userInfo; + private boolean mIslike = false; + private int flag = 0; + + private LinearLayout bottomViewLayout = null; + private LinearLayout sendMsgLayout; + private LinearLayout attentionLayout; + private TextView attentionText; + private ImageView attentionImg; + + private UserInfoViewModel viewModel; + private boolean isFirst = true; + + private UserInfoCpListAdapter mCpListAdapter ; + + @SuppressLint("CheckResult") + @Override + protected void init() { + mActivity = this; + userId = getIntent().getLongExtra("userId", 0); + viewModel = new ViewModelProvider(this).get(UserInfoViewModel.class); + viewModel.setUserId(userId); + UserInfoUiMgr.get().setUid(userId); + + onFindViews(); + onSetListener(); + initTopAlbumView(); + EventBus.getDefault().register(this); + initUserInfoDetailObserver(); + initAttentionView(); + initNestScrollView(); + setEditButton(identityState, false); + setTitleVisible(false); + initViewPager(); + if (userId != AuthModel.get().getCurrentUid()) { + UserModel.get().visitUserDetail(userId).subscribe(); + } + viewModel.getUserInfoData().observe(this, infoBean -> { + LogUtils.d("个人主页 viewModel.getUserInfoData() 加载成功 "); + userInfo = infoBean; + initData(userInfo); + viewModel.getUserInfoDetail(); + }); + } + + @Override + protected void onResume() { + super.onResume(); + viewModel.getUserInfo(); + + } + + private void initAttentionView() { + if (AuthModel.get().getCurrentUid() == userId) { + identityState = OWN; + mBinding.layoutLive.setVisibility(View.GONE); + if (bottomViewLayout != null) + bottomViewLayout.setVisibility(View.GONE); + } else { + if (String.valueOf(userId).equals(XConstants.SECRETARY_UID) || + String.valueOf(userId).equals(XConstants.SYSTEM_MESSAGE_UID)) { + identityState = IdentityState.NON; + } else { + identityState = IdentityState.OTHER; + } + if (bottomViewLayout == null) { + View view = mBinding.vsBottomLayout.getViewStub().inflate(); + bottomViewLayout = view.findViewById(R.id.bottom_view_layout); + sendMsgLayout = view.findViewById(R.id.sendMsgLayout); + attentionLayout = view.findViewById(R.id.attentionLayout); + attentionText = view.findViewById(R.id.attentionText); + attentionImg = view.findViewById(R.id.attentionImg); + sendMsgLayout.setOnClickListener(this); + attentionLayout.setOnClickListener(this); + } + + bottomViewLayout.setVisibility(View.VISIBLE); + } + } + + private void onSetListener() { + mBinding.ivUserBack.setOnClickListener(this); + mBinding.ivEdit.setOnClickListener(this); + mBinding.tvEdit.setOnClickListener(this); + mBinding.layoutLive.setOnClickListener(this); + mBinding.cpCardMore.setOnClickListener(this); + mBinding.userInfoAnim.setOnClickListener(this); +// mBinding.ivTagArrow.setOnClickListener(this); + } + + /** + * 找到TA, 主态不展示 + */ + private void setWhereVisible() { + + if (VipHelper.notTrace(userInfo) || VipHelper.enterHide(userInfo)){ + mBinding.layoutLive.setVisibility(View.GONE); + mBinding.svgLive.stopAnimation(); + }else { + if (viewModel.getMRoomUid() != 0) { + mBinding.layoutLive.setVisibility(View.VISIBLE); + playSvgaBg(mBinding.svgLive, "svga/user_in_live.svga"); + } else { + mBinding.layoutLive.setVisibility(View.GONE); + mBinding.svgLive.stopAnimation(); + } + } + + } + + private static void playSvgaBg(SVGAImageView svgaRoomBg, String asstets) { + SVGAParser mSVGAParser = new SVGAParser(svgaRoomBg.getContext()); + mSVGAParser.decodeFromAssets(asstets, new SVGAParser.ParseCompletion() { + @Override + public void onComplete(SVGAVideoEntity svgaVideoEntity) { + SVGADrawable drawable = new SVGADrawable(svgaVideoEntity); + svgaRoomBg.setImageDrawable(drawable); + svgaRoomBg.stepToFrame(0, true); + } + + @Override + public void onError() { + } + }, null); + } + + private void initViewPager() { + List fragmentList = new ArrayList<>(2); + fragmentList.add(new UserInfoDataFragment()); + fragmentList.add(new UserInfoDynamicFragment()); + final List tagList = new ArrayList<>(2); + tagList.add(getString(R.string.me_data)); + tagList.add(getString(R.string.me_dynamic)); + CommonNavigator commonNavigator = new CommonNavigator(context); + commonNavigator.setTitleWrapContent(false); + UserInfoIndicatorAdapter magicIndicatorAdapter = new UserInfoIndicatorAdapter(context, tagList); + magicIndicatorAdapter.setOnItemSelectListener((position, view) -> { + mBinding.viewPager.setCurrentItem(position); + }); + commonNavigator.setAdapter(magicIndicatorAdapter); + mBinding.magicIndicator.setNavigator(commonNavigator); + mBinding.viewPager.setOffscreenPageLimit(fragmentList.size()); + mBinding.viewPager.setAdapter(new CommonVPAdapter(getSupportFragmentManager(), getLifecycle(), fragmentList)); + mBinding.viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() { + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + mBinding.magicIndicator.onPageScrolled(position, positionOffset, positionOffsetPixels); + } + + @Override + public void onPageSelected(int position) { + mBinding.magicIndicator.onPageSelected(position); + mBinding.viewPager.requestLayout(); + } + + @Override + public void onPageScrollStateChanged(int state) { + mBinding.magicIndicator.onPageScrollStateChanged(state); + } + }); + mBinding.viewPager.setUserInputEnabled(false); + } + + private void initUserInfoDetailObserver() { + viewModel.getUserInfoDetailData().observe(this, dataBean -> { + LogUtils.d("个人主页 viewModel.getUserInfoDetailData() 加载成功 "); + if (dataBean == null) return; + initPhoto(dataBean.getPrivatePhoto()); + setWhereVisible(); + setCpInfo(dataBean); + setUserBgInfo(dataBean); + setUserNameplateList(dataBean); + }); + + viewModel.getUserInfoDetailError().observe(this, String -> { + finish(); + }); + + + } + + private void setTitleVisible(boolean visible) { + mBinding.tvUserInfoTitle.setVisibility(visible ? View.VISIBLE : View.GONE); + } + + private void onFindViews() { + mBinding.tbUserInfo.setTitle(""); + mBinding.ivHeadWear.bindCache(SVGAView.newCache(1)); + + if (userId == AuthModel.get().getCurrentUid()) { + mBinding.cpCardMore.setVisibility(View.VISIBLE); + } + + mCpListAdapter = new UserInfoCpListAdapter(); + mBinding.cpList.setAdapter(mCpListAdapter); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onCurrentUserInfoUpdate(LoginUserInfoUpdateEvent event) { + if (UserModel.get().getCacheLoginUserInfo() == null) return; + if (UserModel.get().getCacheLoginUserInfo().getUid() != userId) return; + userInfo = UserModel.get().getCacheLoginUserInfo(); + initData(userInfo); + } + + private void initData(UserInfo userInfo) { + LogUtils.d(" userinfo initData "); + if (null != userInfo) { + ImageLoadUtils.loadAvatar(userInfo.getAvatar(),mBinding.ivUserHead); + + //设置昵称 + String nick = RegexUtil.getPrintableString(userInfo.getNick()); + mBinding.tvNick.setText(nick); + //设置签名 + UserInfoUiMgr.get().setValue(userInfo); + mBinding.tvDesc.setText(userInfo.getUserDesc() != null ? userInfo.getUserDesc() : ""); + + mBinding.tvGenderAge.setGender(userInfo.getGender()); + mBinding.tvGenderAge.setBirthDay(userInfo.getBirth()); + + mBinding.tvFansCount.setText(String.valueOf(userInfo.getFansNum())); + mBinding.tvFollowCount.setText(String.valueOf(userInfo.getFollowNum())); + mBinding.tvErbanId.setText(String.valueOf(userInfo.getErbanNo())); + if (userInfo.isHasPrettyErbanNo()) { + mBinding.tvErbanId.setTextColor(ContextCompat.getColor(context, R.color.white)); + mBinding.tvErbanId.setBackgroundResource(R.drawable.user_info_bg_good_id); + setMarginTop(mBinding.layoutRegion, getResources().getDimensionPixelOffset(R.dimen.dp_5)); + } else { + mBinding.tvErbanId.setTextColor(ContextCompat.getColor(context, R.color.white)); + mBinding.tvErbanId.setBackgroundDrawable(null); + setMarginTop(mBinding.layoutRegion, getResources().getDimensionPixelOffset(R.dimen.dp_8)); + } + + String birth = TimeUtil.getChinaDateTimeString(userInfo.getBirth(), "yyyy-MM-dd"); + mBinding.tvRegion.setText(userInfo.getRegion()); + mBinding.tvBirthday.setText(birth); + if (mBinding.tvRegion.getText().length() == 0 || mBinding.tvBirthday.getText().length() == 0) { + mBinding.vRegionBirthdayLine.setVisibility(View.GONE); + } else { + mBinding.vRegionBirthdayLine.setVisibility(View.VISIBLE); + } + if (mBinding.tvRegion.getText().length() == 0 && mBinding.tvBirthday.getText().length() == 0) { + mBinding.layoutRegion.setVisibility(View.GONE); + } else { + mBinding.layoutRegion.setVisibility(View.VISIBLE); + } + + //等级魅力值 + setUserLevel(userInfo.getUserLevelVo()); + + //VIP铭牌 + if (userInfo.getUserVipInfoVO() != null && !TextUtils.isEmpty(userInfo.getUserVipInfoVO().getNameplateUrl())){ + setOfficialMask("",userInfo.getUserVipInfoVO().getNameplateUrl()); + } + + //工会长铭牌 + if (userInfo.getGuildNameplateIcon() != null && !TextUtils.isEmpty(userInfo.getGuildNameplateIcon())){ + setOfficialMaskGuild("",userInfo.getGuildNameplateIcon()); + } + + + if (AuthModel.get().getCurrentUid() != userInfo.getUid()) { + PraiseModel.get().isPraised(AuthModel.get().getCurrentUid(), userInfo.getUid()).subscribe(); + } + + + mBinding.idLayout.setOnClickListener(view -> { + copyName(); + }); + } + } + + private void setUserNameplateList(UserDetailInfo.DataBean dataBean) { + if (OtherExtKt.isVerify(dataBean.getUserNameplateList())) { + mBinding.boxNameplate.removeAllViews(); + for (int i = 0; i < dataBean.getUserNameplateList().size(); i++) { + NameplateInfo iconInfo = dataBean.getUserNameplateList().get(i); + if (iconInfo != null) { + LayoutOfficialMaskBinding maskView = LayoutOfficialMaskBinding.inflate(getLayoutInflater()); + + if (!TextUtils.isEmpty(iconInfo.getNameplateImage())) { + maskView.ivOfficialMask.setVisibility(View.VISIBLE); + ImageLoadUtils.load(iconInfo.getNameplateImage(), maskView.ivOfficialMask); + } else { + maskView.ivOfficialMask.setVisibility(View.GONE); + } + + if (iconInfo.isCustomWord()) { + if (!TextUtils.isEmpty(iconInfo.getWord())) { + maskView.tvOfficialMask.setVisibility(View.VISIBLE); + maskView.tvOfficialMask.setText(iconInfo.getWord()); + maskView.tvOfficialMask.setGravity(Gravity.CENTER); + } else { + maskView.tvOfficialMask.setVisibility(View.GONE); + } + } else { + maskView.tvOfficialMask.setVisibility(View.GONE); + } + + mBinding.boxNameplate.addView(maskView.getRoot()); + + ViewGroup.LayoutParams lp = maskView.getRoot().getLayoutParams(); + lp.height = (int) AppUtils.getApp().getResources().getDimension(R.dimen.dp_20); + maskView.getRoot().setLayoutParams(lp); + + } + } + mBinding.boxNameplate.setVisibility(View.VISIBLE); + } else { + mBinding.boxNameplate.setVisibility(View.GONE); + } + } + + //cp + private void setCpInfo(UserDetailInfo.DataBean dataBean) { + if (dataBean == null) return; + UserDetailInfo.DataBean.RelationUserVO cpInfo = dataBean.getRelationUserVO(); + + //头像 + if (cpInfo != null && cpInfo.cpAvatar != null && !cpInfo.cpAvatar.isEmpty() && cpInfo.showCpAvatar){ + //cp 头像 + mBinding.cpViews.setVisibility(View.VISIBLE); + mBinding.ivHeadWear.loadFile(CpUtils.INSTANCE.getHeadSvga(cpInfo.cpLevel)); + mBinding.ivHeadWearCp.loadFile(CpUtils.INSTANCE.getHeadSvga(cpInfo.cpLevel)); + mBinding.ivHeadWearCpFlag.setImageResource(CpUtils.INSTANCE.getFlag(cpInfo.cpLevel)); + ImageLoadUtils.loadAvatar( cpInfo.cpAvatar,mBinding.ivUserHeadCp); + mBinding.ivUserHeadCp.setOnClickListener(v -> { + UserInfoActivity.Companion.start(context,cpInfo.cpUid); + }); + + }else { + mBinding.cpViews.setVisibility(View.INVISIBLE); + + //正常头像 + if (userInfo != null && userInfo.getUserHeadwear() != null && userInfo.getUserHeadwear().getFirstUrl() != null) { + HeadWearInfo headWearInfo = userInfo.getUserHeadwear(); + AvatarHelper.loadAvatarFrame(mBinding.ivHeadWear, headWearInfo.getFirstUrl(), headWearInfo.getType()); + mBinding.ivUserHead.setPadding(0, 0, 0, 0); + mBinding.ivHeadWear.setVisibility(View.VISIBLE); + }else { + int padding = getResources().getDimensionPixelOffset(R.dimen.dp_0_5); + mBinding.ivUserHead.setPadding(padding, padding, padding, padding); + mBinding.cpViews.setVisibility(View.INVISIBLE); + mBinding.ivHeadWear.setVisibility(View.INVISIBLE); + } + } + + //cp 动画 + if (cpInfo != null && cpInfo.avatar != null && cpInfo.cpAvatar != null && cpInfo.showCpAnim && isFirst) { + String animUrl = CpUtils.INSTANCE.getUserInfoAnim(cpInfo.cpLevel); + HashMap imgMap = new HashMap<>(); + imgMap.put("avatar1", cpInfo.avatar); + imgMap.put("avatar2", cpInfo.cpAvatar); + if (animUrl != null) { + CpUtils.INSTANCE.loadVap( + mBinding.userInfoAnim, + animUrl, + imgMap, null + ); + } else { + mBinding.userInfoAnim.setVisibility(View.GONE); + } + }else { + mBinding.userInfoAnim.setVisibility(View.GONE); + } + + //cp卡片 + viewModel.getNameTypeTopList(userId) + .compose(bindToLifecycle()) + .doOnSuccess(userCPListBeans -> { + if (OtherExtKt.isVerify(userCPListBeans)) { + mCpListAdapter.setNewData(userCPListBeans); + } else { + ArrayList def = new ArrayList<>(); + UserCPListBean userCPListBean = new UserCPListBean(); + userCPListBean.avatar = dataBean.getAvatar(); + def.add(userCPListBean); + mCpListAdapter.setNewData(def); + } + }) + .doOnError(throwable -> { + if (throwable != null && throwable.getMessage() != null) { + OtherExtKt.doToast(throwable.getMessage()); + } + }).subscribe(); + + isFirst = false; + + } + + //userBg + private void setUserBgInfo(UserDetailInfo.DataBean dataBean) { + if (dataBean != null && dataBean.getUsingPersonalBackground() != null) { + VipUtil.INSTANCE.setUserBg(dataBean.getUsingPersonalBackground(),mBinding.userInfoLayoutBg,aBoolean -> { + return null; + }); + } + } + + private void setMarginTop(View view, int top) { + if (view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) { + ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) view.getLayoutParams(); + layoutParams.setMargins(layoutParams.leftMargin, top, layoutParams.rightMargin, layoutParams.bottomMargin); + view.requestLayout(); + } + } + + private void copyName() { + try { + ClipboardManager cm = (ClipboardManager) UserInfoActivity.this.getSystemService(Context.CLIPBOARD_SERVICE); + cm.setPrimaryClip(ClipData.newPlainText("text", String.valueOf(userInfo.getErbanNo()))); + toast(getString(R.string.have_copy)); + } catch (Exception e) { + CoreLogger.info("copyText", e.toString()); + toast(e.toString()); + } + } + +// /** +// * 标签 +// * +// * @param labels +// */ +// private void initLabel(List labels) { +// if (labels == null || labels.isEmpty()) { +// if (AuthModel.get().getCurrentUid() != userId) { +// mBinding.groupLabel.setVisibility(View.GONE); +// mBinding.tvEditLabel.setVisibility(View.GONE); +// } else { +// mBinding.groupLabel.setVisibility(View.GONE); +// mBinding.tvEditLabel.setVisibility(View.VISIBLE); +// mBinding.tvEditLabel.setOnClickListener(view -> { +// EditUserLabelActivity.start(this); +// }); +// } +// return; +// } else { +// mBinding.groupLabel.setVisibility(View.VISIBLE); +// mBinding.tvEditLabel.setVisibility(View.GONE); +// } +// UserInfoLabelAdapter userInfoLabelAdapter = new UserInfoLabelAdapter(); +// +// LinesFlexBoxLayoutManager labelLayoutManager = new LinesFlexBoxLayoutManager(this); +// labelLayoutManager.setFlexDirection(FlexDirection.ROW); +// labelLayoutManager.setAlignItems(AlignItems.FLEX_START); +// labelLayoutManager.setMaxLines(1); +// mBinding.mLabelRecyclerView.setLayoutManager(labelLayoutManager); +// mBinding.mLabelRecyclerView.setAdapter(userInfoLabelAdapter); +// +// userInfoLabelAdapter.setNewData(labels); +// } + + private void initTopAlbumView() { + UserInfoTopAlbumAdapter adapter = new UserInfoTopAlbumAdapter(viewModel.isMe()); + int width = context.getResources().getDimensionPixelOffset(R.dimen.dp_5); + boolean isRTL = UiUtils.INSTANCE.isRtl(this); + int marginEnd = context.getResources().getDimensionPixelOffset(R.dimen.dp_8); + mBinding.bannerView + .setLifecycleRegistry(getLifecycle()) + .setOnPageClickListener((clickedView, position) -> { + showUserPhoto(position); + }) + .registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() { + @Override + public void onPageSelected(int position) { + try { + if (mBinding.bannerViewIndex.getTag() != null) { + int itemCount = (int) mBinding.bannerViewIndex.getTag(); + mBinding.bannerViewIndex.setText((position+1)+"/"+itemCount); + } + } catch (Exception e) { + } + } + }) + .setRTLMode(isRTL) + .setIndicatorHeight(width) + .setIndicatorGravity(isRTL ? IndicatorGravity.START : IndicatorGravity.END) + .setIndicatorSliderWidth(width, width * 2) + .setIndicatorSliderGap(context.getResources().getDimensionPixelOffset(R.dimen.dp_6)) + .setIndicatorMargin(isRTL ? marginEnd : 0, 0, isRTL ? 0 : marginEnd, context.getResources().getDimensionPixelOffset(R.dimen.dp_71)) + .setAdapter(adapter) + .create(); + } + + /** + * 相册 + */ + private void initPhoto(List list) { + if (list == null) { + mBinding.bannerView.refreshData(new ArrayList()); + mBinding.bannerViewIndex.setTag(0); + mBinding.bannerViewIndex.setVisibility(View.INVISIBLE); + } else { + mBinding.bannerView.refreshData(list); + mBinding.bannerViewIndex.setTag(list.size()); + mBinding.bannerViewIndex.setText(1+"/"+list.size()); + mBinding.bannerViewIndex.setVisibility(View.VISIBLE); + } + } + + private void setUserLevel(UserLevelVo userLevelVo) { + mBinding.ivUserCharm.setVisibility(View.GONE); + mBinding.ivUserLevel.setVisibility(View.GONE); + if (userLevelVo != null) { + String userLevelUrl = userLevelVo.getExperUrl(); + String userCharmUrl = userLevelVo.getCharmUrl(); + if (!TextUtils.isEmpty(userLevelUrl)) { + mBinding.ivUserLevel.setVisibility(View.VISIBLE); + ImageLoadUtils.loadImage(this, userLevelUrl, mBinding.ivUserLevel); + } + if (!TextUtils.isEmpty(userCharmUrl)) { + mBinding.ivUserCharm.setVisibility(View.VISIBLE); + ImageLoadUtils.loadImage(this, userCharmUrl, mBinding.ivUserCharm); + } + } + } + + @Override + public void onScrollChanged(NestedScrollView view, int x, int y, int oldx, int oldy) { + + } + + private void initNestScrollView() { + mBinding.appBarLayout.addOnOffsetChangedListener(new AppBarStateChangeListener() { + @Override + protected float getBias() { + return 0.6f; + } + + @Override + public void onStateChanged(AppBarLayout appBarLayout, State state) { + if (state == State.COLLAPSED) { +// mBinding.ivUserBack.setImageResource(R.drawable.icon_user_back_black); + mBinding.ivUserBack.setImageResource(R.drawable.icon_user_back); + mBinding.tbUserInfo.setBackgroundColor(getResources().getColor(R.color.color_08151a)); + setTitleVisible(true); + setEditButton(identityState, false); + }else{ + mBinding.ivUserBack.setImageResource(R.drawable.icon_user_back); + mBinding.tbUserInfo.setBackgroundColor(getResources().getColor(R.color.transparent)); + setTitleVisible(false); + setEditButton(identityState, false); + } + } + }); +// mBinding.appBarLayout.addOnOffsetChangedListener((appBarLayout, verticalOffset) -> { +// LogUtils.d("verticalOffset=" + verticalOffset); +// if (flag == 0 && Math.abs(verticalOffset) > SizeUtils.dp2px(context, 200)) { +// //展开 +// flag = 1; +// mBinding.ivUserBack.setImageResource(R.drawable.icon_user_back_black); +// mBinding.tbUserInfo.setBackgroundColor(getResources().getColor(R.color.white)); +// setTitleVisible(true); +// setEditButton(identityState, true); +// } else if (flag == 1 && Math.abs(verticalOffset) <= 200) { +// //合起来 +// flag = 0; +// mBinding.ivUserBack.setImageResource(R.drawable.icon_user_back); +// mBinding.tbUserInfo.setBackgroundColor(getResources().getColor(R.color.transparent)); +// setTitleVisible(false); +// setEditButton(identityState, false); +// } +// }); + } + + private void setEditButton(int identityState, boolean isExpanded) { + if (identityState == OWN) { + mBinding.ivEdit.setVisibility(View.GONE); + mBinding.tvEdit.setVisibility(View.VISIBLE); + } else if (identityState == IdentityState.OTHER) { + mBinding.ivEdit.setVisibility(View.VISIBLE); + mBinding.tvEdit.setVisibility(View.GONE); + } else { + mBinding.ivEdit.setVisibility(View.GONE); + mBinding.tvEdit.setVisibility(View.GONE); + } + if (isExpanded) { + mBinding.ivEdit.setImageTintList(ColorStateList.valueOf(Color.BLACK)); + mBinding.tvEdit.setImageTintList(ColorStateList.valueOf(Color.BLACK)); +// mBinding.ivEdit.setImageResource(R.drawable.user_info_ic_more_black); +// mBinding.tvEdit.setImageResource(R.drawable.user_info_ic_edit_black); + } else { +// mBinding.ivEdit.setImageResource(R.drawable.user_info_ic_more); +// mBinding.tvEdit.setImageResource(R.drawable.user_info_ic_edit); + mBinding.ivEdit.setImageTintList(ColorStateList.valueOf(Color.WHITE)); + mBinding.tvEdit.setImageTintList(ColorStateList.valueOf(Color.WHITE)); + } + } + + @Override + public void click(int position, UserPhoto userPhoto, boolean isOwner) { + if (isOwner) { + if (position > 0) { + showUserPhoto(position - 1); + } else { + + UIHelper.showModifyPhotosAct(this, userId); + } + } else { + //创建一个集合拿来做用户所有照片信息 + showUserPhoto(position); + } + } + + private void showUserPhoto(int position) { + if (userInfo == null) { + return; + } + //创建一个集合拿来做用户所有照片信息 + ArrayList userPhotos = new ArrayList<>(); + List realmList = userInfo.getPrivatePhoto(); + if (realmList == null) { + return; + } + for (UserPhoto photo : realmList) { + UserPhoto newPhoto = new UserPhoto(); + newPhoto.setPid(photo.getPid()); + newPhoto.setPhotoUrl(photo.getPhotoUrl()); + userPhotos.add(newPhoto); + } + Intent intent = new Intent(mActivity, ShowPhotoActivity.class); + intent.putExtra("position", position); + intent.putExtra("photoList", userPhotos); + startActivity(intent); + } + + private void editClick(int identityState) { + if (identityState == OWN) { + UIHelper.showUserInfoModifyAct(this, REQUEST_CODE_UPDATE_VOICE, userId); + } else if (identityState == IdentityState.OTHER) { + if (userInfo != null) { + String account = String.valueOf(userInfo.getUid()); + boolean inMyBlackList = NimFriendModel.get().isInMyBlackList(account); + List buttonItems = new ArrayList<>(); + if (!inMyBlackList) { + ButtonItem blackListItem = ButtonItemFactory.createAddToBlackListItem(getDialogManager(), account); + buttonItems.add(blackListItem); + } + ButtonItem reportItem = ButtonItemFactory.createReportItem(context, userInfo.getUid(), XConstants.REPORT_TYPE_PERSONAL); + buttonItems.add(reportItem); + + if (UserModel.get().getCacheLoginUserInfo().hasSuperRole){ + ButtonItem forbidItem = new ButtonItem(ResUtil.getString(R.string.forbid), () -> { + UserForbidActivity.Companion.start(context,userInfo.getNick(),userInfo.getAvatar(), userInfo.getErbanNo(),userId); + }); + buttonItems.add(forbidItem); + } + + new CommonPopupDialog(this, "", buttonItems, getString(R.string.cancel), false).show(); + } + + } + } + + @Override + public void onClick(View v) { + switch (v.getId()) { +// case R.id.ivTagArrow: +// UserLabelDialog.newInstance(userInfo.getLabels(), userId).show(this); +// break; + + case R.id.ivUserBack: + finish(); + break; + + + + case R.id.tvEdit: + case R.id.ivEdit: + editClick(identityState); + break; + + case R.id.sendMsgLayout: + if (userInfo == null) return; +// NimUserInfo nimUserInfo = NimUserInfoCache.getInstance().getUserInfo(String.valueOf(userId)); +// if (nimUserInfo != null && nimUserInfo.getName() != null && nimUserInfo.getName().equals(userInfo.getNick())) { +// NimP2PMessageActivity.start(this, String.valueOf(userId)); +// } else { +// NimUserInfoCache.getInstance().getUserInfoFromRemote(String.valueOf(userId), new RequestCallbackWrapper() { +// @Override +// public void onResult(int code, NimUserInfo result, Throwable exception) { +// if (code == 200) { +// NimP2PMessageActivity.start(mActivity, String.valueOf(userId)); +// } else { +// toast(getString(R.string.network_is_abnormal)); +// } +// } +// }); +// } + NimP2PMessageActivity.start(mActivity, String.valueOf(userId)); + break; + + case R.id.attentionLayout: + if (userInfo == null) { + toast(getString(R.string.me_user_information_is_empty)); + return; + } + + if (mIslike) { + boolean isMyFriend = IMFriendModel.get().isMyFriend(String.valueOf(userInfo.getUid())); + String tip = (isMyFriend) ? getString(R.string.me_unfollow_is_no_longer_a_friend) : getString(R.string.me_decide_to_unfollow); + getDialogManager().showOkCancelDialog(tip, true, new DialogManager.OkCancelDialogListener() { + + @Override + public void onCancel() { + getDialogManager().dismissDialog(); + } + + @Override + public void onOk() { + getDialogManager().dismissDialog(); + getDialogManager().showProgressDialog(mActivity, getString(R.string.waiting_text)); + PraiseModel.get().praise(userInfo.getUid(), false).subscribe(); + } + }); + } else { + getDialogManager().showProgressDialog(mActivity, getString(R.string.waiting_text)); + PraiseModel.get().praise(userInfo.getUid(), true).subscribe(); + } + break; + case R.id.layoutLive: + if (userInfo == null) { + toast(getString(R.string.me_user_information_is_empty)); + return; + } + if (viewModel.getMRoomUid() != 0) { + AVRoomActivity.startForFromType(this, viewModel.getMRoomUid(), + AVRoomActivity.FROM_TYPE_USER, userInfo.getNick(), String.valueOf(userInfo.getUid())); + } + break; + + case R.id.cpCardMore: + UserCpListActivity.Companion.start(this); + break; + case R.id.userInfoAnim: + mBinding.userInfoAnim.stopPlay(); + mBinding.userInfoAnim.clearAnimation(); + mBinding.userInfoAnim.setVisibility(View.GONE); + break; + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onIsLiked(IsLikedEvent event) { + setLikedText(event.isLiked); + } + + private void setLikedText(boolean isliked) { + mIslike = isliked; + attentionLayout.setBackgroundResource((isliked) ? R.drawable.user_info_follow_ed : R.drawable.user_info_follow_n); + attentionText.setText(getString((isliked) ? R.string.already_attention : R.string.follow)); + attentionImg.setBackgroundResource((isliked) ? R.drawable.ic_user_info_followed : R.drawable.ic_user_info_follow); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onPraise(PraiseEvent event) { + getDialogManager().dismissDialog(); + if (event.getLikedUid() != userId || + userId == AuthModel.get().getCurrentUid()) { + return; + } + if (event.isFailed()) { + toast(event.getError()); + return; + } + toast(event.isPraise() ? R.string.fan_success : R.string.cancel_fan_success); + setLikedText(event.isPraise()); + } + + private void setOfficialMask(String name, String icon) { +// if( userInfo.isCustomWord() && !TextUtils.isEmpty(icon)){ + if(!TextUtils.isEmpty(icon)){ + mBinding.inOfficialMask.getRoot().setVisibility(View.VISIBLE); + ImageLoadUtils.loadImage(this, icon, mBinding.inOfficialMask.ivOfficialMask); + }else if (!TextUtils.isEmpty(name) && !TextUtils.isEmpty(icon)) { + mBinding.inOfficialMask.getRoot().setVisibility(View.VISIBLE); + mBinding.inOfficialMask.tvOfficialMask.setText(name); + ImageLoadUtils.loadImage(this, icon, mBinding.inOfficialMask.ivOfficialMask); + } else { + mBinding.inOfficialMask.getRoot().setVisibility(View.GONE); + } + } + private void setOfficialMaskGuild(String name, String icon) { +// if( userInfo.isCustomWord() && !TextUtils.isEmpty(icon)){ + if(!TextUtils.isEmpty(icon)){ + mBinding.inOfficialMaskGuild.getRoot().setVisibility(View.VISIBLE); + ImageLoadUtils.loadImage(this, icon, mBinding.inOfficialMaskGuild.ivOfficialMask); + }else if (!TextUtils.isEmpty(name) && !TextUtils.isEmpty(icon)) { + mBinding.inOfficialMaskGuild.getRoot().setVisibility(View.VISIBLE); + mBinding.inOfficialMaskGuild.tvOfficialMask.setText(name); + ImageLoadUtils.loadImage(this, icon, mBinding.inOfficialMaskGuild.ivOfficialMask); + } else { + mBinding.inOfficialMaskGuild.getRoot().setVisibility(View.GONE); + } + } + + @Override + protected void onPause() { + super.onPause(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + EventBus.getDefault().unregister(this); + AudioPlayerHelper.get().onDestroy(); + } + + @Override + protected boolean needSteepStateBar() { + return true; + } + + @Override + protected void setStatusBar() { + super.setStatusBar(); + StatusBarUtil.transparencyBar(this); + StatusBarUtil.StatusBarLightMode(this); + } + + public interface IdentityState { + int NON = 0; // 无法识别 + int OWN = 1; // 自己 + int OTHER = 2; // 其他人 + } + + /** + * static静态代码 + */ + + public final static class Companion { + public final static String TAG = UserInfoActivity.class.getSimpleName(); + + static final int FROM_TYPE_NORMAL = 1; + static final int FROM_TYPE_FAMILY = 2; + + public static void start(Context context, long userId) { + Intent intent = new Intent(context, UserInfoActivity.class); + intent.putExtra("userId", userId); + int from = FROM_TYPE_NORMAL; + intent.putExtra("from", from); + context.startActivity(intent); + + } + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/user/activity/UserInfoModifyActivity.kt b/app/src/main/java/com/chwl/app/ui/user/activity/UserInfoModifyActivity.kt new file mode 100644 index 0000000..42f4470 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/activity/UserInfoModifyActivity.kt @@ -0,0 +1,696 @@ +package com.chwl.app.ui.user.activity + +import android.annotation.SuppressLint +import android.content.Intent +import android.graphics.Bitmap +import android.net.Uri +import android.os.Bundle +import android.text.TextUtils +import android.view.View +import android.widget.ImageView +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.LinearLayoutManager +import com.chwl.app.R +import com.chwl.app.UIHelper +import com.chwl.app.application.App +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.base.PhotoPickActivity +import com.chwl.app.common.util.BitmapUtil +import com.chwl.app.common.widget.dialog.DialogManager +import com.chwl.app.constants.UserInfoConstants +import com.chwl.app.databinding.ActivityUserInfoModifyBinding +import com.chwl.app.ui.login.ModifyInfoActivity +import com.chwl.app.ui.user.adapter.UserPhotoAdapter +import com.chwl.app.ui.user.adapter.UserPhotoAdapter.ImageClickListener +import com.chwl.app.ui.user.dialog.UserAreaDialog +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.app.ui.widget.ButtonItem +import com.chwl.app.utils.RegexUtil +import com.chwl.core.auth.AuthModel +import com.chwl.core.file.FileModel +import com.chwl.core.pay.PayModel +import com.chwl.core.user.UserModel +import com.chwl.core.user.bean.RegionInfoBean +import com.chwl.core.user.bean.UserInfo +import com.chwl.core.user.bean.UserPhoto +import com.chwl.core.utils.CoreLogger +import com.chwl.core.utils.myutil.MyUriUtils +import com.chwl.library.common.file.FileHelper +import com.chwl.library.common.util.ClickUtils.click +import com.chwl.library.common.util.PhotoCompressCallback +import com.chwl.library.common.util.PhotoCompressUtil +import com.chwl.library.common.util.doToast +import com.chwl.library.utils.ResUtil +import com.chwl.library.utils.TimeUtils +import com.example.lib_utils.ktx.getString +import com.fourmob.datetimepicker.date.DatePickerDialog +import com.hjq.toast.ToastUtils +import com.netease.nim.uikit.StatusBarUtil +import com.netease.nim.uikit.common.util.sys.TimeUtil +import com.sleepbot.datetimepicker.time.RadialPickerLayout +import com.sleepbot.datetimepicker.time.TimePickerDialog +import com.trello.rxlifecycle3.android.ActivityEvent +import com.yalantis.ucrop.UCrop +import io.reactivex.Completable +import io.reactivex.SingleObserver +import io.reactivex.disposables.Disposable +import kotlinx.coroutines.Job +import java.io.FileNotFoundException +import java.text.SimpleDateFormat +import java.util.Calendar +import java.util.Date +import java.util.concurrent.TimeUnit + + +/** + * @author zhouxiangfeng + */ +class UserInfoModifyActivity : BaseViewBindingActivity(), + View.OnClickListener, + TimePickerDialog.OnTimeSetListener, DatePickerDialog.OnDateSetListener, ImageClickListener { + private var datePickerDialog: DatePickerDialog? = null + private var mUserInfo: UserInfo? = null + private var userId: Long = 0 + + private var mUri: Uri? = null + private var mJob: Job? = null + + private var isAvatar = false + private var isGif = false + + private var mUpLoadGifAvatarPrice = -1 + + companion object { + private const val TAG = "UserInfoModifyActivity" + private const val PERMISSION_CODE_STORAGE = 12 + private const val REQUEST_CODE_STORAGE = 42 + private const val REQUEST_CODE_OPEN_PHOTO_PROVIDER = 111 // 从相册中选择 + private const val MAX_BITMAP_SIZE = 100 * 1024 * 1024 // 剪切的图片最大为100 MB + private const val MIN_HEAD_PHOTO_SIZE = 20 * 1024 // 剪切的图片最小为20kb + + //头像压缩后的大小不能超过大小 200KB + private const val IMAGE_MOST_COMPRESS_SIZE = 200 + } + + override fun init() { + initWhiteTitleBar(getString(R.string.label_title_modify_info)) + findViews() + initView() + userId = intent.getLongExtra("userId", 0) + } + + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + UserModel.get().getUserInfo(userId).subscribe(userInfoUpdateObserver) + PhotoCompressUtil.clearCompressCache() + } + + override fun click(position: Int, userPhoto: UserPhoto, isOwner: Boolean) { + UserModifyPhotosActivity.startForResult( + this@UserInfoModifyActivity, + userId, + Method.PHOTO + ) + } + + private fun initData(userInfo: UserInfo?) { + if (null != userInfo) { + ImageLoadUtils.loadAvatar( + if (!TextUtils.isEmpty(userInfo.newAvatar)) userInfo.newAvatar else userInfo.avatar, + binding.civAvatar + ) + binding.tvAvatarAuditing.visibility = if (userInfo.isReview) View.VISIBLE else View.GONE + binding.ivAvatarAuditing.visibility = if (userInfo.isReview) View.VISIBLE else View.GONE + val birth = TimeUtil.getChinaDateTimeString(userInfo.birth, "yyyy-MM-dd") + binding.tvBirth.text = birth + binding.tvNick.text = RegexUtil.getPrintableString(userInfo.nick) + setTvDesc(userInfo.userDesc) + val adapter = UserPhotoAdapter( + userInfo.privatePhoto, + 1, + userInfo.uid + ) + adapter.setSmall(true) + adapter.setImageClickListener(this) + binding.rvPhotos.adapter = adapter + if (userInfo.privatePhoto != null && userInfo.privatePhoto.size > 0) { + binding.rvPhotos.visibility = View.VISIBLE + } else { + binding.rvPhotos.visibility = View.GONE + } + binding.tvArea.text = userInfo.region + + //cp 设置获取 + UserModel.get().getUserInfoDetail(userId).compose(bindToLifecycle()).doOnSuccess { + setSwitchView(binding.swCpShow, it?.data?.relationUserVO?.showCpAvatar ?: false) + setSwitchView(binding.swCpAnim, it?.data?.relationUserVO?.showCpAnim ?: false) + }.subscribe() + } + } + + private fun findViews() { + binding.layoutAvatar.setOnClickListener(this) + binding.tvBirth.setOnClickListener(this) + binding.tvNick.setOnClickListener(this) + binding.layoutPhotos.setOnClickListener(this) + binding.llDesc.setOnClickListener(this) + binding.layoutArea.setOnClickListener(this) + binding.swCpAnim.setOnClickListener(this) + binding.swCpShow.setOnClickListener(this) + val mLayoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, true) + binding.rvPhotos.layoutManager = mLayoutManager + } + + private fun setTvDesc(desc: String?) { + binding.tvDesc.text = + if (TextUtils.isEmpty(desc)) getString(R.string.label_hint_desc_setting) else desc + } + + private fun initView() { + val calendar = Calendar.getInstance() + datePickerDialog = DatePickerDialog.newInstance( + this, calendar[Calendar.YEAR], + calendar[Calendar.MONTH], calendar[Calendar.DAY_OF_MONTH], true + ) + } + + override fun onDateSet(datePickerDialog: DatePickerDialog, year: Int, month: Int, day: Int) { + val monthStr: String = if (month + 1 < 10) { + "0" + (month + 1) + } else { + (month + 1).toString() + } + val dayStr: String = if (day < 10) { + "0$day" + } else { + day.toString() + } + val birth = "$year-$monthStr-$dayStr" + val user = UserInfo() + user.uid = AuthModel.get().currentUid + user.birthStr = birth + UserModel.get().requestUpdateUserInfo(user).subscribe(userInfoUpdateObserver) + } + + override fun onTimeSet(view: RadialPickerLayout, hourOfDay: Int, minute: Int) {} + interface Method { + companion object { + /** + * 录音 + */ + const val AUDIO = 2 + + /** + * 昵称 + */ + const val NICK = 3 + + /** + * 个人介绍 + */ + const val DESC = 4 + + /** + * 拍照 + */ + const val PHOTO = 5 + + /** + * 标签 + */ + const val LABEL = 6 + } + } + + override fun onClick(v: View) { + when (v.id) { + R.id.layout_avatar -> { + if (mUserInfo != null && mUserInfo?.isReview == true) { + toast(ResUtil.getString(R.string.ui_user_userinfomodifyactivity_03)) + return + } + selectAvatarType() + } + + R.id.tv_birth -> { + if (mUserInfo != null) { + var year = TimeUtils.getYear( + mUserInfo?.birth ?: 0L + ) + val month = TimeUtils.getMonth( + mUserInfo?.birth ?: 0L + ) + val day = TimeUtils.getDayOfMonth( + mUserInfo?.birth ?: 0L + ) + if (year < 1902 || year > 2037) { + year = 1970 + } + datePickerDialog = + DatePickerDialog.newInstance(this, year, month - 1, day, true) + } + val calendar = Calendar.getInstance() + datePickerDialog?.apply { + setVibrate(true) + setYearRange(1945, calendar[Calendar.YEAR] - 18) + show(supportFragmentManager, "DATEPICKER_TAG_1") + } + } + + R.id.tv_nick -> UIHelper.showModifyInfoAct( + this@UserInfoModifyActivity, + Method.NICK, + ModifyInfoActivity.NICK_MODIFY + ) + + R.id.ll_desc -> UIHelper.showModifyInfoAct( + this@UserInfoModifyActivity, + Method.DESC, + ModifyInfoActivity.CONTENT_MODIFY + ) + + R.id.layout_photos -> UserModifyPhotosActivity.startForResult( + this@UserInfoModifyActivity, + userId, + Method.PHOTO + ) + + R.id.layout_area -> { + dialogManager.showProgressDialog( + this@UserInfoModifyActivity, + ResUtil.getString(R.string.ui_user_userinfomodifyactivity_02) + ) + UserModel.get().areaInfo.subscribe(object : SingleObserver> { + override fun onSubscribe(d: Disposable) { + mCompositeDisposable.add(d) + } + + override fun onSuccess(areaList: List) { + dialogManager.dismissDialog() + if (areaList.isNotEmpty()) { + val newList = areaList.map { + it.name + } + UserAreaDialog.newInstance(newList) + .apply { + setAction { + val find = areaList.find { data -> data.name == it } + if (find != null) { + reportArea(it, find.id) + } + } + }.show(this@UserInfoModifyActivity) + } + } + + override fun onError(e: Throwable) { + dialogManager.dismissDialog() + toast(e.message) + } + }) + } + + R.id.swCpAnim -> { + postUpDateCpSwitch(binding.swCpAnim, UserInfoConstants.CpSet.cpAnim) + } + + R.id.swCpShow -> { + postUpDateCpSwitch(binding.swCpShow, UserInfoConstants.CpSet.cpAvatar) + } + + else -> {} + } + } + + //post update set + private fun postUpDateCpSwitch(view: ImageView, type: Int) { + val tag = view.tag + if (tag != null && tag is Boolean) { + val tagVal = !tag + UserModel.get().userCpSettingUpdate(type, tagVal) + .compose(bindToLifecycle()) + .doOnSuccess { + setSwitchView(view, tagVal, true) + }.subscribe() + } + } + + // set view + private fun setSwitchView(view: ImageView, on: Boolean, notify: Boolean = false) { + view.setImageResource(if (on) R.drawable.ic_user_edit_sw_on else R.drawable.ic_user_edit_sw_off) + view.tag = on + if (notify) { + //通知 cp设置改变 + + } + } + + private fun reportArea(area: String, id: Long) { + binding.tvArea.text = area + dialogManager.showProgressDialog( + this@UserInfoModifyActivity, + ResUtil.getString(R.string.ui_user_userinfomodifyactivity_02) + ) + UserModel.get().saveArea(id).subscribe(object : SingleObserver { + override fun onSubscribe(d: Disposable) { + mCompositeDisposable.add(d) + } + + override fun onSuccess(areaList: String) { + dialogManager.dismissDialog() + } + + override fun onError(e: Throwable) { + dialogManager.dismissDialog() + toast(e.message) + } + + }) + } + + override fun onResume() { + super.onResume() + UserModel.get().getUserInfoDetail(AuthModel.get().currentUid) + .compose(bindToLifecycle()) + .doOnSuccess { + mUpLoadGifAvatarPrice = it?.data?.uploadGifAvatarPrice ?: -1 + } + .doOnError { + it?.message?.doToast() + } + .subscribe() + } + + + private fun selectAvatarType() { + val list = ArrayList() + + list.add(ButtonItem(R.string.avatar2.getString()) { + isGif = false + isAvatar = true + checkStoragePermission() + }) + + + val gifItem = ButtonItem(R.string.avatar1.getString()) { + + } + val inflate = layoutInflater.inflate(R.layout.layout_common_popup_dialog_button_gif_avatar, null) +// val moreBtn = inflate.findViewById(R.id.more) +// moreBtn.click { +// dialogManager.showOkCancelDialog(R.string._ver_24_Rules.getString(),R.string._ver_24_gifAvatar_rule.getString(),R.string.ok.getString(),R.string.cancel.getString(),true, DialogManager.OkCancelDialogListener { +// +// }) +// } + inflate.click { + if (mUpLoadGifAvatarPrice == 0) { + isGif = true + isAvatar = true + checkStoragePermission() + } else { + dialogManager?.showOkCancelDialog(R.string._ver_24_Rules.getString(),R.string._ver_24_gifAvatar_rule.getString(mUpLoadGifAvatarPrice,mUpLoadGifAvatarPrice),R.string.ok.getString(),R.string.cancel.getString(),false, DialogManager.OkCancelDialogListener { + PayModel.get().getWalletInfo(AuthModel.get().currentUid) + .compose(bindToLifecycle()) + .doOnSuccess { + if (it.diamonds >= mUpLoadGifAvatarPrice) { + isGif = true + isAvatar = true + checkStoragePermission() + } else { + R.string.treasure_diamond_balance_is_insufficient.doToast() + } + }.doOnError { + R.string.retryTips.doToast() + }.subscribe() + }) + } + } + gifItem.mView = inflate + list.add(gifItem) + + dialogManager.showCommonPopupDialog(list, getString(R.string.cancel)) + } + + + + private fun checkStoragePermission() { + PhotoPickActivity.start(this, if (isGif) PhotoPickActivity.GIF else PhotoPickActivity.IMG) + } + + private fun getNowTime(): String { + val date = Date(System.currentTimeMillis()) + val dateFormat = SimpleDateFormat("MMddHHmmssSS") + return dateFormat.format(date) + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (resultCode == RESULT_OK) { + when (requestCode) { + Method.NICK -> { + data?.let { + dialogManager.showProgressDialog( + this@UserInfoModifyActivity, + ResUtil.getString(R.string.ui_user_userinfomodifyactivity_01) + ) + val stringExtra = it.getStringExtra(ModifyInfoActivity.CONTENT_NICK) + binding.tvNick.text = stringExtra + val user = UserInfo() + user.uid = AuthModel.get().currentUid + user.nick = stringExtra + UserModel.get().requestUpdateUserInfo(user) + .subscribe(userInfoUpdateObserver) + } + } + + Method.DESC -> { + data?.let { + dialogManager.showProgressDialog( + this@UserInfoModifyActivity, + ResUtil.getString(R.string.ui_user_userinfomodifyactivity_02) + ) + val stringExtra = it.getStringExtra(ModifyInfoActivity.CONTENT) + setTvDesc(stringExtra) + val user = UserInfo() + user.uid = AuthModel.get().currentUid + user.userDesc = stringExtra + UserModel.get().requestUpdateUserInfo(user) + .subscribe(userInfoUpdateObserver) + } + } + + Method.PHOTO -> { + data?.let { + val isChanged = + it.getBooleanExtra(UserModifyPhotosActivity.FLAG_CHANGE, false) + if (isChanged) UserModel.get().getUserInfo(userId) + .subscribe(userInfoUpdateObserver) + } + } + + PhotoPickActivity.PICK_ACT_RESULT -> { + val uri = data?.data + if (uri != null) { + val fileWith = if (isGif) ".gif" else ".jpg" + mUri = + Uri.parse("file://${FileHelper.getRootCacheDir()?.path}/${getNowTime()}$fileWith") + if (isGif) { + if (MyUriUtils.isGif(context, uri)) { + val isCopy = MyUriUtils.copyFileToUrl(this, uri, mUri!!) + if (isCopy) { + onActivityResult(UCrop.REQUEST_CROP, RESULT_OK, null) + } else { + ToastUtils.show(R.string.exception_try_again) + } + } else { + ToastUtils.show(R.string.error_file_type) + } + } else { + val copyFileToUrl = MyUriUtils.copyFileToUrl(this, uri, mUri!!) + if (copyFileToUrl) { + crop(mUri, 1, mUri) + } else { + ToastUtils.show(R.string.exception_try_again) + } + } + } + + } + + UCrop.REQUEST_CROP -> mUri?.path?.let { + try { + mJob?.cancel() + mJob = PhotoCompressUtil.compress( + this, + it, + PhotoCompressUtil.getCompressCachePath(), + object : PhotoCompressCallback { + @SuppressLint("CheckResult") + override fun onSuccess(compressedImg: String) { + dialogManager.showProgressDialog( + this@UserInfoModifyActivity, + ResUtil.getString(R.string.ui_user_userinfomodifyactivity_09) + ) + FileModel.get() + .uploadFile(compressedImg) + .compose(bindToLifecycle()) + .subscribe { url: String?, throwable: Throwable? -> + if (throwable != null) { + onUploadFail(throwable) + } else { + onUpload(url) + } + } + } + + override fun onFail(e: Throwable) { + toast(e.message) + } + }, + mostCompressSize = IMAGE_MOST_COMPRESS_SIZE + ) + } catch (e: FileNotFoundException) { + CoreLogger.error(TAG, e.message) + } + } + } + } + } + + /** + * 第三方图片裁剪框架Ucrop + */ + private fun crop(sourceUri: Uri?, sourceSize: Long, destinationUri: Uri?) { + if (sourceUri == null || destinationUri == null) { + return + } //防止too large导致oom,大于100m不处理,内存大小 + if (BitmapUtil.getSdBitmapSize(sourceUri) >= MAX_BITMAP_SIZE) { + toast(R.string.text_bitmap_too_large) + return + } + +// if (sourceSize > 0) { +// //不能上传图片的最小文件大小 +// CoreLogger.debug(TAG, "sourceSize: $sourceSize") +// if (sourceSize < MIN_HEAD_PHOTO_SIZE) { +// toast(R.string.text_bitmap_too_small) +// return +// } +// } + + val options = UCrop.Options().apply { + setCompressionQuality(100) + setShowCropGrid(false) + setToolbarColor( + ContextCompat.getColor( + App.gContext, + android.R.color.black + ) + ) + setStatusBarColor( + ContextCompat.getColor( + App.gContext, + android.R.color.black + ) + ) + setHideBottomControls(true) + setCompressionFormat(Bitmap.CompressFormat.JPEG) + setToolbarCancelDrawable(R.drawable.user_ucrop_ic_closs) + setToolbarCropDrawable(R.drawable.user_ucrop_ic_sure) + setToolbarWidgetColor( + ContextCompat.getColor( + App.gContext, + R.color.color_white + ) + ) + } + UCrop.of(sourceUri, destinationUri).withOptions(options).withAspectRatio(1f, 1f) + .withMaxResultSize(800, 800).start(this) + } + + private fun onUpload(url: String?) { + if (isAvatar) { + val user = UserInfo() + user.uid = AuthModel.get().currentUid + user.avatar = url + UserModel.get().upLoadAvatar(url,isGif) + .compose(bindToLifecycle()) + .doOnSuccess { + dialogManager.dismissDialog() + showAvatarAuditingDialog() + UserModel.get().updateCurrentUserInfo().compose(bindToLifecycle()) + .doOnSuccess { info-> + if (info.uid == userId) { + mUserInfo = info + initData(mUserInfo) + } + }.subscribe() + } + .doOnError { + dialogManager.dismissDialog() + it?.message?.doToast() + }.subscribe() + } + } + + private fun onUploadFail(throwable: Throwable) { + toast(ResUtil.getString(R.string.ui_user_userinfomodifyactivity_08) + ":${throwable.message}") + dialogManager.dismissDialog() + } + + /** + * 观察用户信息 + */ + private val userInfoUpdateObserver: SingleObserver = + object : SingleObserver { + override fun onSubscribe(d: Disposable) { + mCompositeDisposable.add(d) + } + + override fun onSuccess(info: UserInfo) { + if (info.uid == userId) { + mUserInfo = info + initData(mUserInfo) + } + dialogManager.dismissDialog() + } + + override fun onError(e: Throwable) { + dialogManager.dismissDialog() + toast(e.message) + } + } + + private fun showAvatarAuditingDialog() { + if (isGif) { + dialogManager?.showOkCancelDialog(R.string.tip_tips.getString(),R.string._ver_24_gifAvatar_Success.getString(),R.string.ok.getString(),"",false, DialogManager.OkCancelDialogListener {}) + } else { + toast(R.string.avatar_auditing) + } + //延迟3秒重新获取用户信息更新状态 + binding.ivAvatarAuditing.visibility = View.VISIBLE + Completable.timer(3000, TimeUnit.MILLISECONDS) + .compose(bindUntilEvent(ActivityEvent.STOP)) + .doOnComplete { + UserModel.get().updateCurrentUserInfo().subscribe(userInfoUpdateObserver) + } + .doOnError { throwable: Throwable -> throwable.printStackTrace() }.subscribe() + } + + override fun needSteepStateBar(): Boolean { + return true + } + + override fun setStatusBar() { + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } + + override fun onDestroy() { + super.onDestroy() + dialogManager.dismissDialog() + mJob?.cancel() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/user/activity/UserModifyPhotosActivity.kt b/app/src/main/java/com/chwl/app/ui/user/activity/UserModifyPhotosActivity.kt new file mode 100644 index 0000000..e701b64 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/activity/UserModifyPhotosActivity.kt @@ -0,0 +1,337 @@ +package com.chwl.app.ui.user.activity + +import android.annotation.SuppressLint +import android.app.Activity +import android.content.Intent +import android.graphics.Bitmap +import android.net.Uri +import android.os.Bundle +import android.view.View +import android.widget.GridView +import androidx.core.content.ContextCompat +import com.chwl.app.R +import com.chwl.app.application.App +import com.chwl.app.base.BaseActivity +import com.chwl.app.base.PhotoPickActivity +import com.chwl.app.base.TitleBar +import com.chwl.app.common.util.BitmapUtil +import com.chwl.app.ui.user.adapter.UserModifyPhotosAdapter +import com.chwl.app.ui.user.adapter.UserModifyPhotosAdapter.PhotoItemClickListener +import com.chwl.core.file.FileModel +import com.chwl.core.user.UserModel +import com.chwl.core.user.bean.UserInfo +import com.chwl.core.user.bean.UserPhoto +import com.chwl.core.utils.CoreLogger +import com.chwl.core.utils.myutil.MyUriUtils +import com.chwl.core.utils.net.BeanObserver +import com.chwl.library.common.file.FileHelper +import com.chwl.library.common.util.PhotoCompressCallback +import com.chwl.library.common.util.PhotoCompressUtil +import com.chwl.library.utils.ResUtil +import com.hjq.toast.ToastUtils +import com.netease.nim.uikit.StatusBarUtil +import com.orhanobut.logger.Logger +import com.trello.rxlifecycle3.android.ActivityEvent +import com.yalantis.ucrop.UCrop +import kotlinx.coroutines.Job +import java.io.FileNotFoundException +import java.text.SimpleDateFormat +import java.util.Date + +/** + * Created by chenran on 2017/7/24. + */ +class UserModifyPhotosActivity : BaseActivity(), PhotoItemClickListener { + private var userId: Long = 0 + private var userInfo: UserInfo? = null + private var photoGridView: GridView? = null + private var isEditMode = false + private var adapter: UserModifyPhotosAdapter? = null + private var mActivity: UserModifyPhotosActivity? = null + + private var mUri: Uri? = null + private var mJob: Job? = null + + + companion object { + const val FLAG_CHANGE = "isChanged" + private const val TAG = "UserModifyPhotosActivit" + fun startForResult(activity: Activity, userId: Long, requestCode: Int) { + val intent = Intent(activity, UserModifyPhotosActivity::class.java) + intent.putExtra("userId", userId) + activity.startActivityForResult(intent, requestCode) + } + + private const val PERMISSION_CODE_STORAGE = 12 + private const val REQUEST_CODE_STORAGE = 42 + private const val REQUEST_CODE_OPEN_PHOTO_PROVIDER = 111 // 从相册中选择 + private const val MAX_BITMAP_SIZE = 100 * 1024 * 1024 // 剪切的图片最大为100 MB + private const val MIN_HEAD_PHOTO_SIZE = 20 * 1024 // 剪切的图片最小为20kb + + //头像压缩后的大小不能超过大小 200KB + private const val IMAGE_MOST_COMPRESS_SIZE = 200 + } + + // 判断相册是否做过增减操作 + private var isChanged = false + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_user_photos_modify) + PhotoCompressUtil.clearCompressCache() + initView() + mActivity = this + userId = intent.getLongExtra("userId", 0) + userInfo = UserModel.get().cacheLoginUserInfo + adapter = UserModifyPhotosAdapter( + this, + ArrayList(), + this + ) + photoGridView!!.adapter = adapter + if (userInfo != null) { + updateView() + } + } + + private fun initView() { + initWhiteTitleBar(ResUtil.getString(R.string.ui_user_usermodifyphotosactivity_01)) + val titleBar = findViewById(R.id.title_bar) + titleBar.addAction(object : TitleBar.TextAction( + ResUtil.getString(R.string.ui_user_usermodifyphotosactivity_02), + resources.getColor(R.color.text_normal_c6c6e9) + ) { + override fun performAction(view: View) { + notifyEditMode() + } + }) + photoGridView = findViewById(R.id.gridView) + } + + override fun onLeftClickListener() { + onBackPressed() + } + + private fun updateView() { + adapter!!.setData(userInfo!!.privatePhoto) + adapter!!.notifyDataSetChanged() + } + + private fun notifyEditMode() { + adapter!!.setEditMode(!isEditMode) + isEditMode = !isEditMode + adapter!!.notifyDataSetChanged() + } + + override fun onPhotoDeleteClick(position: Int) { + dialogManager.showProgressDialog( + this, + ResUtil.getString(R.string.ui_user_usermodifyphotosactivity_03) + ) + if (position != 0) { + val userPhoto = userInfo!!.privatePhoto[position - 1] + UserModel.get().requestDeletePhoto(userPhoto.pid) + .subscribe(object : BeanObserver() { + override fun onErrorMsg(error: String) { + toast(ResUtil.getString(R.string.ui_user_usermodifyphotosactivity_04)) + dialogManager.dismissDialog() + } + + override fun onSuccess(info: UserInfo) { + isChanged = true + dialogManager.dismissDialog() + if (info.uid == userId) { + userInfo = info + updateView() + } + } + }) + } + } + + override fun onPhotoItemClick(position: Int) { + if (userInfo == null) { + return + } + if (position == 0) { + if (userInfo!!.privatePhoto != null && userInfo!!.privatePhoto.size == 8) { + toast(ResUtil.getString(R.string.ui_user_usermodifyphotosactivity_05)) + return + } + checkStoragePermission() + } else { + val userPhotos1 = ArrayList() + userPhotos1.addAll(userInfo!!.privatePhoto) + val intent = Intent(mActivity, ShowPhotoActivity::class.java) + val position1 = position - 1 + intent.putExtra("position", position1) + intent.putExtra("photoList", userPhotos1) + startActivity(intent) + } + } + + private fun checkStoragePermission() { + PhotoPickActivity.start(this@UserModifyPhotosActivity, PhotoPickActivity.IMG) + } + + private fun getNowTime(): String { + val date = Date(System.currentTimeMillis()) + val dateFormat = SimpleDateFormat("MMddHHmmssSS") + return dateFormat.format(date) + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (resultCode == RESULT_OK) { + when (requestCode) { + + PhotoPickActivity.PICK_ACT_RESULT -> data?.data?.let { uri -> + mUri = + Uri.parse("file://${FileHelper.getRootCacheDir()?.path}/${getNowTime()}.jpg") + val isCopy = + MyUriUtils.copyFileToUrl(this@UserModifyPhotosActivity, uri, mUri!!) + if (isCopy) { + crop(mUri, 0, mUri) + } else { + ToastUtils.show(R.string.exception_try_again) + } + } + + + UCrop.REQUEST_CROP -> mUri?.path?.let { + try { + mJob?.cancel() + mJob = PhotoCompressUtil.compress( + App.gContext, + it, + PhotoCompressUtil.getCompressCachePath(), + object : PhotoCompressCallback { + @SuppressLint("CheckResult") + override fun onSuccess(compressedImg: String) { + dialogManager.showProgressDialog( + this@UserModifyPhotosActivity, + ResUtil.getString(R.string.ui_user_userinfomodifyactivity_09) + ) + FileModel.get() + .uploadFile(compressedImg) + .compose(bindToLifecycle()) + .subscribe { url: String?, throwable: Throwable? -> + if (throwable != null) { + onUploadFail() + } else { + onUpload(url) + } + } + } + + override fun onFail(e: Throwable) { + toast(e.message) + } + }, + mostCompressSize = IMAGE_MOST_COMPRESS_SIZE + ) + } catch (e: FileNotFoundException) { + CoreLogger.error(TAG, e.message) + } + } + } + } + } + + /** + * 第三方图片裁剪框架Ucrop + */ + private fun crop(sourceUri: Uri?, sourceSize: Long, destinationUri: Uri?) { + if (sourceUri == null || destinationUri == null) { + return + } //防止too large导致oom,大于100m不处理,内存大小 + if (BitmapUtil.getSdBitmapSize(sourceUri) >= MAX_BITMAP_SIZE) { + toast(R.string.text_bitmap_too_large) + return + } +// if (sourceSize > 0) { +// //不能上传图片的最小文件大小 +// CoreLogger.debug(TAG, "sourceSize: $sourceSize") +// if (sourceSize < MIN_HEAD_PHOTO_SIZE) { +// toast(R.string.text_bitmap_too_small) +// return +// } +// } + val options = UCrop.Options().apply { + setCompressionQuality(100) + setShowCropGrid(false) + setToolbarColor( + ContextCompat.getColor( + App.gContext, + android.R.color.black + ) + ) + setStatusBarColor( + ContextCompat.getColor( + App.gContext, + android.R.color.black + ) + ) + setHideBottomControls(true) + setCompressionFormat(Bitmap.CompressFormat.JPEG) + setToolbarCancelDrawable(R.drawable.user_ucrop_ic_closs) + setToolbarCropDrawable(R.drawable.user_ucrop_ic_sure) + setToolbarWidgetColor( + ContextCompat.getColor( + App.gContext, + R.color.color_white + ) + ) + } + UCrop.of(sourceUri, destinationUri).withOptions(options).withAspectRatio(1f, 1f) + .withMaxResultSize(800, 800).start(this) + } + + private fun onUpload(url: String?) { + Logger.d("onUploadPhoto:$url") + UserModel.get().requestAddPhoto(url) + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .subscribe(object : BeanObserver() { + override fun onErrorMsg(error: String) { + toast(ResUtil.getString(R.string.ui_user_usermodifyphotosactivity_09)) + dialogManager.dismissDialog() + } + + override fun onSuccess(info: UserInfo) { + toast(ResUtil.getString(R.string.ui_user_usermodifyphotosactivity_010)) + isChanged = true + dialogManager.dismissDialog() + if (info.uid == userId) { + userInfo = info + updateView() + } + } + }) + } + + private fun onUploadFail() { + toast(ResUtil.getString(R.string.ui_user_usermodifyphotosactivity_011)) + dialogManager.dismissDialog() + } + + override fun onBackPressed() { + val intent = Intent() + intent.putExtra(FLAG_CHANGE, isChanged) + setResult(RESULT_OK, intent) + super.onBackPressed() + } + + override fun needSteepStateBar(): Boolean { + return true + } + + override fun setStatusBar() { + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } + + override fun onDestroy() { + super.onDestroy() + mJob?.cancel() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/user/adapter/ArrayWheelAdapter.java b/app/src/main/java/com/chwl/app/ui/user/adapter/ArrayWheelAdapter.java new file mode 100644 index 0000000..c109516 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/adapter/ArrayWheelAdapter.java @@ -0,0 +1,44 @@ +package com.chwl.app.ui.user.adapter; + +import com.contrarywind.adapter.WheelAdapter; + +import java.util.List; + +/** + * The simple Array wheel adapter + * @param the element type + */ +public class ArrayWheelAdapter implements WheelAdapter { + + + // items + private List items; + + /** + * Constructor + * @param items the items + */ + public ArrayWheelAdapter(List items) { + this.items = items; + + } + + @Override + public Object getItem(int index) { + if (index >= 0 && index < items.size()) { + return items.get(index); + } + return ""; + } + + @Override + public int getItemsCount() { + return items.size(); + } + + @Override + public int indexOf(Object o){ + return items.indexOf(o); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/user/adapter/CommonWrapIndicatorAdapter.java b/app/src/main/java/com/chwl/app/ui/user/adapter/CommonWrapIndicatorAdapter.java new file mode 100644 index 0000000..85c5341 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/adapter/CommonWrapIndicatorAdapter.java @@ -0,0 +1,104 @@ +package com.chwl.app.ui.user.adapter; + +import android.content.Context; +import android.view.Gravity; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.TextView; + +import androidx.core.content.ContextCompat; + +import com.chwl.app.R; +import com.chwl.app.ui.widget.XRecyclerView.ScaleTransitionPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.CommonNavigatorAdapter; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.indicators.GradientLinePagerIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.indicators.GradientLineRoundPagerIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.indicators.LinePagerIndicator; + +import java.util.List; + +public class CommonWrapIndicatorAdapter extends CommonNavigatorAdapter { + private final Context mContext; + private final List mTitleList; + + private int textSize = 14; + private float minScale = 1f; + private boolean showIndicator = true; + private OnItemSelectListener mOnItemSelectListener; + + public CommonWrapIndicatorAdapter(Context context, List charSequences) { + this.mContext = context; + this.mTitleList = charSequences; + } + + @Override + public int getCount() { + return mTitleList == null ? 0 : mTitleList.size(); + } + + @Override + public IPagerTitleView getTitleView(Context context, final int i) { + ScaleTransitionPagerTitleView scaleTransitionPagerTitleView = new ScaleTransitionPagerTitleView(context, true); + scaleTransitionPagerTitleView.setNormalColor(ContextCompat.getColor(context, R.color.color_6D6B89)); + scaleTransitionPagerTitleView.setSelectedColor(ContextCompat.getColor(context, R.color.color_1F1A4E)); + scaleTransitionPagerTitleView.setMinScale(minScale); + scaleTransitionPagerTitleView.setTextSize(textSize); + int padding = UIUtil.dip2px(context, 12); + scaleTransitionPagerTitleView.setPadding(padding, 0, padding, 0); + scaleTransitionPagerTitleView.setText(mTitleList.get(i)); + scaleTransitionPagerTitleView.setOnClickListener(view -> { + if (mOnItemSelectListener != null) { + mOnItemSelectListener.onItemSelect(i, scaleTransitionPagerTitleView); + } + + }); + return scaleTransitionPagerTitleView; + } + + @Override + public IPagerIndicator getIndicator(Context context) { + if (!showIndicator) return null; + GradientLineRoundPagerIndicator indicator = new GradientLineRoundPagerIndicator(context); + indicator.setMode(LinePagerIndicator.MODE_EXACTLY); + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + lp.gravity = Gravity.END; + lp.bottomMargin = UIUtil.dip2px(mContext, 0); + indicator.setLayoutParams(lp); + return indicator; + } + + public int getTextSize() { + return textSize; + } + + public void setTextSize(int textSize) { + this.textSize = textSize; + } + + public float getMinScale() { + return minScale; + } + + public void setMinScale(float minScale) { + this.minScale = minScale; + } + + public boolean isShowIndicator() { + return showIndicator; + } + + public void setShowIndicator(boolean showIndicator) { + this.showIndicator = showIndicator; + } + + public void setOnItemSelectListener(OnItemSelectListener onItemSelectListener) { + mOnItemSelectListener = onItemSelectListener; + } + + public interface OnItemSelectListener { + void onItemSelect(int position, TextView view); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/user/adapter/ContactsIndicatorAdapter.java b/app/src/main/java/com/chwl/app/ui/user/adapter/ContactsIndicatorAdapter.java new file mode 100644 index 0000000..2eaee2c --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/adapter/ContactsIndicatorAdapter.java @@ -0,0 +1,105 @@ +package com.chwl.app.ui.user.adapter; + +import android.content.Context; +import android.view.Gravity; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.TextView; + +import androidx.core.content.ContextCompat; + +import com.chwl.app.R; +import com.chwl.app.ui.widget.XRecyclerView.ScaleTransitionPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.CommonNavigatorAdapter; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerTitleView; +import com.chwl.library.language.LanguageHelper; + +import java.util.List; + +public class ContactsIndicatorAdapter extends CommonNavigatorAdapter { + private final List mTitleList; + + private int textSize = 20; + private float minScale = 0.8f; + private boolean showIndicator = true; + private OnItemSelectListener mOnItemSelectListener; + + public ContactsIndicatorAdapter(Context context, List charSequences) { + this.mTitleList = charSequences; + } + + @Override + public int getCount() { + return mTitleList == null ? 0 : mTitleList.size(); + } + + @Override + public IPagerTitleView getTitleView(Context context, final int i) { + ScaleTransitionPagerTitleView scaleTransitionPagerTitleView = new ScaleTransitionPagerTitleView(context, true); + scaleTransitionPagerTitleView.setNormalColor(ContextCompat.getColor(context, R.color.color_313131)); + scaleTransitionPagerTitleView.setSelectedColor(ContextCompat.getColor(context, R.color.color_313131)); + scaleTransitionPagerTitleView.setMinScale(minScale); + if (LanguageHelper.INSTANCE.getCurrentLanguageType().equals("EN")) { + scaleTransitionPagerTitleView.setTextSize(textSize); + } else { + scaleTransitionPagerTitleView.setTextSize(textSize-2); + } + int padding = UIUtil.dip2px(context, 10); + scaleTransitionPagerTitleView.setPadding(padding, 0, padding, 0); + scaleTransitionPagerTitleView.setText(mTitleList.get(i)); + scaleTransitionPagerTitleView.setOnClickListener(view -> { + if (mOnItemSelectListener != null) { + mOnItemSelectListener.onItemSelect(i, scaleTransitionPagerTitleView); + } + }); + return scaleTransitionPagerTitleView; + } + + @Override + public IPagerIndicator getIndicator(Context context) { + if (!showIndicator) return null; + DrawableIndicator indicator = new DrawableIndicator(context); + indicator.setMode(DrawableIndicator.MODE_EXACTLY); + indicator.setDrawableWidth(context.getResources().getDimensionPixelOffset(R.dimen.dp_24)); + indicator.setDrawableHeight(context.getResources().getDimensionPixelOffset(R.dimen.dp_7)); +// indicator.setIndicatorDrawable(context.getResources().getDrawable(R.drawable.base_ic_indicator)); + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + lp.gravity = Gravity.END; + indicator.setLayoutParams(lp); + return indicator; + } + + public int getTextSize() { + return textSize; + } + + public void setTextSize(int textSize) { + this.textSize = textSize; + } + + public float getMinScale() { + return minScale; + } + + public void setMinScale(float minScale) { + this.minScale = minScale; + } + + public boolean isShowIndicator() { + return showIndicator; + } + + public void setShowIndicator(boolean showIndicator) { + this.showIndicator = showIndicator; + } + + public void setOnItemSelectListener(OnItemSelectListener onItemSelectListener) { + mOnItemSelectListener = onItemSelectListener; + } + + public interface OnItemSelectListener { + void onItemSelect(int position, TextView view); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/user/adapter/DrawableIndicator.java b/app/src/main/java/com/chwl/app/ui/user/adapter/DrawableIndicator.java new file mode 100644 index 0000000..6692bd1 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/adapter/DrawableIndicator.java @@ -0,0 +1,177 @@ +package com.chwl.app.ui.user.adapter; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.view.View; +import android.view.animation.Interpolator; +import android.view.animation.LinearInterpolator; + + +import com.chwl.app.ui.widget.magicindicator.FragmentContainerHelper; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.model.PositionData; + +import java.util.List; + +public class DrawableIndicator extends View implements IPagerIndicator { + public static final int MODE_MATCH_EDGE = 0; // drawable宽度 == title宽度 - 2 * mXOffset + public static final int MODE_WRAP_CONTENT = 1; // drawable宽度 == title内容宽度 - 2 * mXOffset + public static final int MODE_EXACTLY = 2; + + private int mMode; // 默认为MODE_MATCH_EDGE模式 + private Drawable mIndicatorDrawable; + + // 控制动画 + private Interpolator mStartInterpolator = new LinearInterpolator(); + private Interpolator mEndInterpolator = new LinearInterpolator(); + + private float mDrawableHeight; + private float mDrawableWidth; + private float mYOffset; + private float mXOffset; + + private List mPositionDataList; + private Rect mDrawableRect = new Rect(); + + public DrawableIndicator(Context context) { + super(context); + } + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + if (mIndicatorDrawable == null) { + return; + } + + if (mPositionDataList == null || mPositionDataList.isEmpty()) { + return; + } + + // 计算锚点位置 + PositionData current = FragmentContainerHelper.getImitativePositionData(mPositionDataList, position); + PositionData next = FragmentContainerHelper.getImitativePositionData(mPositionDataList, position + 1); + + float leftX; + float nextLeftX; + float rightX; + float nextRightX; + if (mMode == MODE_MATCH_EDGE) { + leftX = current.mLeft + mXOffset; + nextLeftX = next.mLeft + mXOffset; + rightX = current.mRight - mXOffset; + nextRightX = next.mRight - mXOffset; + mDrawableRect.top = (int) mYOffset; + mDrawableRect.bottom = (int) (getHeight() - mYOffset); + } else if (mMode == MODE_WRAP_CONTENT) { + leftX = current.mContentLeft + mXOffset; + nextLeftX = next.mContentLeft + mXOffset; + rightX = current.mContentRight - mXOffset; + nextRightX = next.mContentRight - mXOffset; + mDrawableRect.top = (int) (current.mContentTop - mYOffset); + mDrawableRect.bottom = (int) (current.mContentBottom + mYOffset); + } else { // MODE_EXACTLY + leftX = current.mLeft + (current.width() - mDrawableWidth) / 2; + nextLeftX = next.mLeft + (next.width() - mDrawableWidth) / 2; + rightX = current.mLeft + (current.width() + mDrawableWidth) / 2; + nextRightX = next.mLeft + (next.width() + mDrawableWidth) / 2; + mDrawableRect.top = (int) (getHeight() - mDrawableHeight - mYOffset); + mDrawableRect.bottom = (int) (getHeight() - mYOffset); + } + + mDrawableRect.left = (int) (leftX + (nextLeftX - leftX) * mStartInterpolator.getInterpolation(positionOffset)); + mDrawableRect.right = (int) (rightX + (nextRightX - rightX) * mEndInterpolator.getInterpolation(positionOffset)); + mIndicatorDrawable.setBounds(mDrawableRect); + + invalidate(); + } + + @Override + public void onPageSelected(int position) { + } + + @Override + public void onPageScrollStateChanged(int state) { + } + + @Override + protected void onDraw(Canvas canvas) { + if (mIndicatorDrawable != null) { + mIndicatorDrawable.draw(canvas); + } + } + + @Override + public void onPositionDataProvide(List dataList) { + mPositionDataList = dataList; + } + + public Drawable getIndicatorDrawable() { + return mIndicatorDrawable; + } + + public void setIndicatorDrawable(Drawable indicatorDrawable) { + mIndicatorDrawable = indicatorDrawable; + } + + public Interpolator getStartInterpolator() { + return mStartInterpolator; + } + + public void setStartInterpolator(Interpolator startInterpolator) { + mStartInterpolator = startInterpolator; + } + + public Interpolator getEndInterpolator() { + return mEndInterpolator; + } + + public void setEndInterpolator(Interpolator endInterpolator) { + mEndInterpolator = endInterpolator; + } + + public int getMode() { + return mMode; + } + + public void setMode(int mode) { + if (mode == MODE_EXACTLY || mode == MODE_MATCH_EDGE || mode == MODE_WRAP_CONTENT) { + mMode = mode; + } else { + throw new IllegalArgumentException("mode " + mode + " not supported."); + } + } + + public float getDrawableHeight() { + return mDrawableHeight; + } + + public void setDrawableHeight(float drawableHeight) { + mDrawableHeight = drawableHeight; + } + + public float getDrawableWidth() { + return mDrawableWidth; + } + + public void setDrawableWidth(float drawableWidth) { + mDrawableWidth = drawableWidth; + } + + public float getYOffset() { + return mYOffset; + } + + public void setYOffset(float yOffset) { + mYOffset = yOffset; + } + + public float getXOffset() { + return mXOffset; + } + + public void setXOffset(float xOffset) { + mXOffset = xOffset; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/user/adapter/GiftAdapter.java b/app/src/main/java/com/chwl/app/ui/user/adapter/GiftAdapter.java new file mode 100644 index 0000000..7b89aa3 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/adapter/GiftAdapter.java @@ -0,0 +1,46 @@ +package com.chwl.app.ui.user.adapter; + +import android.content.Context; +import android.widget.ImageView; + +import androidx.annotation.Nullable; + +import com.chad.library.adapter.base.BaseMultiItemQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.user.bean.UserDetailInfo; + +import java.util.List; + +public class GiftAdapter extends BaseMultiItemQuickAdapter { + + + public GiftAdapter(Context context,@Nullable List data) { + super(data); + addItemType(UserDetailInfo.DataBean.UserGiftWallBean.TYPE_NORMAL,R.layout.item_userinfo_gift); + addItemType(UserDetailInfo.DataBean.UserGiftWallBean.TYPE_EMPTY,R.layout.item_userinfo_gift_empty); + this.mContext = context; + } + + @Override + protected void convert(BaseViewHolder helper, UserDetailInfo.DataBean.UserGiftWallBean item) { + if (item == null) { + return; + } + + switch (helper.getItemViewType()){ + case UserDetailInfo.DataBean.UserGiftWallBean.TYPE_NORMAL: + helper.setText(R.id.tv_title, "x" + item.getReciveCount()); + ImageView ivIcon = helper.getView(R.id.iv_icon); + ImageLoadUtils.loadImageWithPlaceholder(mContext, item.getPicUrl(), ivIcon); + break; + + case UserDetailInfo.DataBean.UserGiftWallBean.TYPE_EMPTY: + + break; + } + + + } +} diff --git a/app/src/main/java/com/chwl/app/ui/user/adapter/HomeRecommendIndicatorAdapter.java b/app/src/main/java/com/chwl/app/ui/user/adapter/HomeRecommendIndicatorAdapter.java new file mode 100644 index 0000000..3178710 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/adapter/HomeRecommendIndicatorAdapter.java @@ -0,0 +1,104 @@ +package com.chwl.app.ui.user.adapter; + +import android.content.Context; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.TextView; + +import androidx.core.content.ContextCompat; + +import com.chwl.app.R; +import com.chwl.app.ui.widget.XRecyclerView.ScaleTransitionPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.CommonNavigatorAdapter; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerTitleView; + +import java.util.List; + +public class HomeRecommendIndicatorAdapter extends CommonNavigatorAdapter { + private final Context mContext; + private final List mTitleList; + + private int textSize = 14; + private float minScale = 1f; + private boolean showIndicator = true; + private OnItemSelectListener mOnItemSelectListener; + + public HomeRecommendIndicatorAdapter(Context context, List charSequences) { + this.mContext = context; + this.mTitleList = charSequences; + } + + @Override + public int getCount() { + return mTitleList == null ? 0 : mTitleList.size(); + } + + @Override + public IPagerTitleView getTitleView(Context context, final int i) { + ScaleTransitionPagerTitleView scaleTransitionPagerTitleView = new ScaleTransitionPagerTitleView(context, true); + scaleTransitionPagerTitleView.setNormalColor(ContextCompat.getColor(context, R.color.color_767585)); + scaleTransitionPagerTitleView.setSelectedColor(ContextCompat.getColor(context, R.color.color_1E1E1F)); + scaleTransitionPagerTitleView.setMinScale(minScale); + scaleTransitionPagerTitleView.setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources().getDimensionPixelSize(R.dimen.sp_14)); + int padding = UIUtil.dip2px(context, 12); + scaleTransitionPagerTitleView.setPadding(padding, 0, padding, 0); + scaleTransitionPagerTitleView.setText(mTitleList.get(i)); + scaleTransitionPagerTitleView.setOnClickListener(view -> { + if (mOnItemSelectListener != null) { + mOnItemSelectListener.onItemSelect(i, scaleTransitionPagerTitleView); + } + + }); + return scaleTransitionPagerTitleView; + } + + @Override + public IPagerIndicator getIndicator(Context context) { + if (!showIndicator) return null; + DrawableIndicator indicator = new DrawableIndicator(context); + indicator.setMode(DrawableIndicator.MODE_EXACTLY); + indicator.setDrawableWidth(context.getResources().getDimensionPixelOffset(R.dimen.dp_24)); + indicator.setDrawableHeight(context.getResources().getDimensionPixelOffset(R.dimen.dp_7)); +// indicator.setIndicatorDrawable(context.getResources().getDrawable(R.drawable.base_ic_indicator)); + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + lp.gravity = Gravity.END; + indicator.setLayoutParams(lp); + return indicator; + } + + public int getTextSize() { + return textSize; + } + + public void setTextSize(int textSize) { + this.textSize = textSize; + } + + public float getMinScale() { + return minScale; + } + + public void setMinScale(float minScale) { + this.minScale = minScale; + } + + public boolean isShowIndicator() { + return showIndicator; + } + + public void setShowIndicator(boolean showIndicator) { + this.showIndicator = showIndicator; + } + + public void setOnItemSelectListener(OnItemSelectListener onItemSelectListener) { + mOnItemSelectListener = onItemSelectListener; + } + + public interface OnItemSelectListener { + void onItemSelect(int position, TextView view); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/user/adapter/PhotoAdapter.java b/app/src/main/java/com/chwl/app/ui/user/adapter/PhotoAdapter.java new file mode 100644 index 0000000..c994616 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/adapter/PhotoAdapter.java @@ -0,0 +1,68 @@ +package com.chwl.app.ui.user.adapter; + +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; + +import androidx.viewpager.widget.PagerAdapter; + +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.user.bean.UserPhoto; + +import java.util.ArrayList; + +/** + * Created by ${Seven} on 2017/8/14. + */ + +public class PhotoAdapter extends PagerAdapter { + private final Context context; + private final ArrayList bigImagesList; + + private PhotoAdapter.imageOnclickListener mImageOnclickListener; + + public void setmImageOnclickListener(PhotoAdapter.imageOnclickListener imageOnclickListener){ + mImageOnclickListener=imageOnclickListener; + } + public interface imageOnclickListener{ + void onClick(); + } + + //传进来的photolist用于设置进imageview里面去 + public PhotoAdapter(Context Context, ArrayList photoList) { + context = Context; + this.bigImagesList = photoList; + } + @Override + public int getCount() { + return bigImagesList == null ? 0 : bigImagesList.size(); + } + + @Override + public boolean isViewFromObject(View view, Object object) { + return view == object; + } + @Override + public void destroyItem(ViewGroup container, int position, Object object) { + container.removeView((View) object); + } + + @Override + public Object instantiateItem(ViewGroup container, int position) { + final ImageView imageView = new ImageView(context); + //拿到userphoto对象 + UserPhoto userPhoto = bigImagesList.get(position); + //把对象设置到imageview里面去 + ImageLoadUtils.load(userPhoto.getPhotoUrl(), imageView); + //然后把imageview添加到容器里面去 + container.addView(imageView); + imageView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mImageOnclickListener.onClick(); + } + }); + return imageView; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/user/adapter/SkillPicsAdapter.kt b/app/src/main/java/com/chwl/app/ui/user/adapter/SkillPicsAdapter.kt new file mode 100644 index 0000000..ebd8880 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/adapter/SkillPicsAdapter.kt @@ -0,0 +1,12 @@ +package com.chwl.app.ui.user.adapter + +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.ui.utils.ImageLoadUtilsV2 + +class SkillPicsAdapter: BaseQuickAdapter(R.layout.item_userinfo_skill_abspicture) { + override fun convert(helper: BaseViewHolder, item: String) { + ImageLoadUtilsV2.loadImage(helper.getView(R.id.iv_skill_picture),item) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/user/adapter/UserCpListAdapter.kt b/app/src/main/java/com/chwl/app/ui/user/adapter/UserCpListAdapter.kt new file mode 100644 index 0000000..5f6ccab --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/adapter/UserCpListAdapter.kt @@ -0,0 +1,59 @@ +package com.chwl.app.ui.user.adapter + +import androidx.core.view.isVisible +import com.chwl.app.R +import com.chwl.app.bindadapter.BaseAdapter +import com.chwl.app.bindadapter.BindingViewHolder +import com.chwl.app.databinding.ItemUserCpListBinding +import com.chwl.app.ui.utils.CpUtils +import com.chwl.app.ui.utils.CpUtils.getCpListCardBg +import com.chwl.app.ui.utils.CpUtils.getLevelImg +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.app.utils.NumberUtils +import com.chwl.core.contacts.MyConstant +import com.chwl.core.user.bean.UserCPListBean +import com.chwl.library.utils.ResUtil +import com.example.lib_utils.ktx.getDrawable +import com.example.lib_utils.ktx.getString + +class UserCpListAdapter : BaseAdapter { + + constructor(layoutResId: Int, brid: Int) : super(layoutResId, brid) + + + override fun convert(helper: BindingViewHolder, data: UserCPListBean?) { + super.convert(helper, data) + if (data == null ) return + val mViewBinding = helper.binding as ItemUserCpListBinding + + mViewBinding.cpLevel.setImageResource(getLevelImg(data.cpLevel)) + + ImageLoadUtils.loadAvatar(data.avatar,mViewBinding.userAvatar) + ImageLoadUtils.loadAvatar(data.cpAvatar, mViewBinding.userAvatarCp) + + val max = (data.endExp - data.startExp) + val current = (data.currentExp.toFloat() / max.toFloat()) * 100f + + mViewBinding.cpPro.max = 100 + mViewBinding.cpPro.progress = current.toInt() + + mViewBinding.cpProVal.text = "${NumberUtils.format(data.currentExp)} / ${NumberUtils.format(data.endExp)}" + mViewBinding.cpNeedVal.text = ResUtil.getString(R.string.CP_Need_tips,NumberUtils.format((data.endExp - data.currentExp))) + + mViewBinding.cpDay.text = "${data.cpDay}${R.string.days.getString()}" + mViewBinding.cpDay.isVisible = data.cpDay > 0 + + + helper.addOnClickListener(mViewBinding.cancel.id) + helper.addOnClickListener(mViewBinding.userAvatarCp.id) + helper.addOnClickListener(mViewBinding.btnSwitch.id) + + mViewBinding.bg.setBackgroundResource(getCpListCardBg(data.relationNameType)) + + mViewBinding.btnSwitch.setAlpha(if(data.clickFlag == MyConstant.CP.clickFlag.def) 1f else 0.5f) + + mViewBinding.cpPro.progressDrawable = CpUtils.getListCardProgressDrawables(data.relationNameType).getDrawable() + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/user/adapter/UserGiftAdapter.java b/app/src/main/java/com/chwl/app/ui/user/adapter/UserGiftAdapter.java new file mode 100644 index 0000000..aa5ccab --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/adapter/UserGiftAdapter.java @@ -0,0 +1,76 @@ +package com.chwl.app.ui.user.adapter; + +import android.content.Context; +import android.view.View; +import android.widget.ImageView; + +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.bean.UserInfoItem; +import com.chwl.core.user.bean.GiftWallInfo; + +import java.util.List; + +public class UserGiftAdapter extends UserTabBaseAdapter { + + private final boolean isDetails; + + public UserGiftAdapter(Context context, List data, boolean isDetails) { + super(context, data); + addItemType(UserInfoItem.TYPE_GIFT_ITEM_TOP, R.layout.list_item_gift_wall_info); + addItemType(UserInfoItem.TYPE_GIFT_ITEM, R.layout.list_item_gift_wall_info); + addItemType(UserInfoItem.TYPE_GIFT_EMPTY, R.layout.layout_gift_empty); + this.isDetails = isDetails; + } + + @Override + protected void convert(BaseViewHolder helper, UserInfoItem item) { + if (item == null) { + return; + } + + super.convert(helper, item); + + switch (item.getItemType()) { + case UserInfoItem.TYPE_GIFT_ITEM_TOP: + setGiftItem(helper, item, UserInfoItem.TYPE_GIFT_ITEM_TOP); + + case UserInfoItem.TYPE_GIFT_ITEM: + setGiftItem(helper, item, UserInfoItem.TYPE_GIFT_ITEM); + break; + + case UserInfoItem.TYPE_GIFT_EMPTY: + break; + } + + } + + private void setGiftItem(BaseViewHolder helper, UserInfoItem item, int type) { + GiftWallInfo giftWallInfo = (GiftWallInfo) item.getData(); + + if (giftWallInfo != null) { + + helper.setText(R.id.gift_name, giftWallInfo.getGiftName()) + .setGone(R.id.gift_name, isDetails) + .setText(R.id.gift_num, "x" + giftWallInfo.getReciveCount()) + .setText(R.id.gift_price, giftWallInfo.getGiftPrice() + "") + .setGone(R.id.gift_price, isDetails); + + ImageView giftPic = helper.itemView.findViewById(R.id.gift_img); + ImageLoadUtils.loadImage(mContext, giftWallInfo.getPicUrl(), giftPic); + + ImageView giftLevel = helper.itemView.findViewById(R.id.iv_gift_level); + if(type == UserInfoItem.TYPE_GIFT_ITEM_TOP){ + if(helper.getAdapterPosition() == 0) { + giftLevel.setImageResource(R.drawable.ic_gift_one); + }else if(helper.getAdapterPosition() == 1){ + giftLevel.setImageResource(R.drawable.ic_gift_two); + }else if(helper.getAdapterPosition() == 2){ + giftLevel.setImageResource(R.drawable.ic_gift_three); + } + } + } + + } +} diff --git a/app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoAlbumAdapter.kt b/app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoAlbumAdapter.kt new file mode 100644 index 0000000..d8b0eb7 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoAlbumAdapter.kt @@ -0,0 +1,17 @@ +package com.chwl.app.ui.user.adapter + +import android.widget.ImageView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.ui.utils.load +import com.chwl.core.user.bean.UserDetailInfo +import com.chwl.core.user.bean.UserPhoto + +class UserInfoAlbumAdapter : + BaseQuickAdapter(R.layout.user_info_item_album) { + override fun convert(helper: BaseViewHolder, item: UserPhoto) { + val imageView = helper.getView(R.id.iv_image) + imageView.load(item.photoUrl) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoCpListAdapter.kt b/app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoCpListAdapter.kt new file mode 100644 index 0000000..a11c101 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoCpListAdapter.kt @@ -0,0 +1,49 @@ +package com.chwl.app.ui.user.adapter + +import android.view.View +import com.chwl.app.R +import com.chwl.app.bindadapter.BaseBindingAdapter +import com.chwl.app.databinding.ItemUserInfoCpListBinding +import com.chwl.app.ui.user.activity.UserInfoActivity +import com.chwl.app.ui.utils.CpUtils.getCpUserInfoCardBg +import com.chwl.app.ui.utils.CpUtils.getLevelImg +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.core.user.bean.UserCPListBean +import com.chwl.library.utils.ResUtil + +class UserInfoCpListAdapter : BaseBindingAdapter() { + + override fun onBindView( + mBinding: ItemUserInfoCpListBinding, + cpInfo: UserCPListBean, + pos: Int + ) { + + //cp 卡片 + if (cpInfo?.cpAvatar != null && cpInfo.cpAvatar.isNotEmpty()) { + mBinding.cpCardDay.setText(cpInfo.cpDay.toString() + "" + ResUtil.getString(R.string.days)) + mBinding.cpCardDay.setVisibility(if (cpInfo.cpDay > 0) View.VISIBLE else View.INVISIBLE) + + mBinding.cpCardLevel.setImageResource(getLevelImg(cpInfo.cpLevel)) + mBinding.cpCardLevel.setVisibility(View.VISIBLE) + mBinding.cpCardLevelEmpty.setVisibility(View.INVISIBLE) + ImageLoadUtils.loadAvatar(cpInfo.avatar, mBinding.cpCardUserAvatar) + ImageLoadUtils.loadAvatar(cpInfo.cpAvatar, mBinding.cpCardUserAvatarCp) + mBinding.cpCardUserHeadCp.setVisibility(View.VISIBLE) + mBinding.cpCardUserAvatarCp.setOnClickListener { v -> + UserInfoActivity.Companion.start(mContext, cpInfo.cpUid) + } + mBinding.cpCardBg.setBackgroundResource(getCpUserInfoCardBg(cpInfo.relationNameType)) + } else { + mBinding.cpCardDay.setVisibility(View.INVISIBLE) + mBinding.cpCardLevelEmpty.setVisibility(View.VISIBLE) + mBinding.cpCardLevel.setVisibility(View.INVISIBLE) + mBinding.cpCardUserAvatarCp.setImageResource(R.drawable.ic_user_info_cp_def_avatar) + mBinding.cpCardUserAvatarCp.setOnClickListener(null) + mBinding.cpCardUserHeadCp.setVisibility(View.INVISIBLE) + ImageLoadUtils.loadAvatar(cpInfo.avatar, mBinding.cpCardUserAvatar) + mBinding.cpCardBg.setBackgroundResource(getCpUserInfoCardBg(null)) + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoDynamicAdapter.java b/app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoDynamicAdapter.java new file mode 100644 index 0000000..06b5a2c --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoDynamicAdapter.java @@ -0,0 +1,262 @@ +package com.chwl.app.ui.user.adapter; + + +import android.app.Activity; +import android.content.Context; +import android.text.TextUtils; +import android.util.SparseBooleanArray; +import android.util.SparseIntArray; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.core.content.ContextCompat; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.app.community.dynamic.view.DynamicDetailActivity; +import com.chwl.app.community.helper.CalcSize; +import com.chwl.app.community.helper.DynamicUiHelper; +import com.chwl.app.community.helper.ImageUiHelper; +import com.chwl.app.photo.DynamicImageAdapter; +import com.chwl.app.community.utils.ObjectTypeHelper; +import com.chwl.app.community.widget.ExpandableTextView; +import com.chwl.app.photo.BigPhotoActivity; +import com.chwl.app.photo.PagerOption; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.utils.TimeUiUtils; +import com.chwl.core.community.bean.DynamicMedia; +import com.chwl.core.community.bean.WorldDynamicBean; +import com.chwl.core.community.dynamic.DynamicModel; +import com.chwl.core.utils.net.DontWarnObserver; +import com.chwl.core.utils.net.RxHelper; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; +import com.netease.nim.uikit.common.util.log.LogUtil; + +import java.util.List; + +/** + * create by lvzebiao @2019/11/13 + */ +public class UserInfoDynamicAdapter extends BaseQuickAdapter { + + private SparseBooleanArray mCollapsedStatus = new SparseBooleanArray(); + private SparseIntArray mCollapsedHeightStatus = new SparseIntArray(2); + + private Context context; + + private long worldId; + + private int iconWidth; + + private int iconHeight; + + /** + * 单图情况下的边界 + */ + private int imageBorder; + /** + * 图片的边界值 + */ + private int divider; + + public boolean isUserInfo = false; + + public UserInfoDynamicAdapter(Context context) { + super(R.layout.item_userinfo_dynamic); + this.context = context; + iconWidth = UIUtil.dip2px(context, 32); + iconHeight = UIUtil.dip2px(context, 15); + //0.68 + imageBorder = UIUtil.getScreenWidth(context) * ImageUiHelper.BORDER_MIN / ImageUiHelper.BORDER_MAX; + divider = UIUtil.dip2px(context, 10); + } + + @Override + protected void convert(BaseViewHolder helper, WorldDynamicBean item) { + //这个值,有没有文本UI部分,改变图片部分的margin + boolean noTextUi = TextUtils.isEmpty(item.getContent()); + RecyclerView rvImage = helper.getView(R.id.rv_image); + List dynamicMediaList = item.getDynamicResList(); + if (item.getType() == WorldDynamicBean.TYPE_IMAGE + && dynamicMediaList != null && dynamicMediaList.size() > 0) { + rvImage.setVisibility(View.VISIBLE); + initRecyclerView(rvImage, dynamicMediaList, noTextUi); + } else { + rvImage.setVisibility(View.GONE); + } + + //时间 + helper.setText(R.id.tv_time, TimeUiUtils.getDynamicUi(item.getPublishTime())); + + ExpandableTextView etvContent = helper.getView(R.id.etv_content); + etvContent.setEventType(1); + if (noTextUi) { + etvContent.setVisibility(View.GONE); + } else { + etvContent.setVisibility(View.VISIBLE); + CharSequence formatText = DynamicUiHelper.formatFirstDynamicContent( + item, etvContent.mTv, iconWidth, iconHeight); + etvContent.setText(formatText, mCollapsedStatus, helper.getAdapterPosition(), mCollapsedHeightStatus); + } + + helper.setGone(R.id.layout_root_mini_world, item.getTag() != null); + helper.setText(R.id.tv_mini_world_name, "#" + item.getTag()); + + //评论 + setCommentCount(helper, item.getCommentCount()); + + //点赞 + setLikeCount(helper, item.getLikeCount(), item.isLike(), false); + LinearLayout llLike = helper.getView(R.id.ll_like); + llLike.setEnabled(true); + llLike.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (item.getDynamicId() == 0) { + SingleToastUtil.showToast(ResUtil.getString(R.string.the_default_dynamic_cannot_be_liked)); + return; + } + llLike.setEnabled(false); + int status = item.isLike() ? 0 : 1; + DynamicModel.get().like(worldId, item.getDynamicId(), item.getUid(), status, 1) + .compose(RxHelper.bindContext(context)) + .subscribe(new DontWarnObserver() { + @Override + public void accept(String s, String error) { + super.accept(s, error); + llLike.setEnabled(true); + if (error != null) { + SingleToastUtil.showToast(error); + } else { + LogUtil.print(mContext.getString(R.string.me_call_the_like_interface_to_complete)); + if (status == 1) { + item.setLikeCount(item.getLikeCount() + 1); + } else { + item.setLikeCount(item.getLikeCount() - 1); + } + item.setLike(status == 1); + setLikeCount(helper, item.getLikeCount(), item.isLike(), true); + } + } + }); + } + }); + //评论 + helper.getView(R.id.ll_comment).setOnClickListener(v -> { + if (item.getDynamicId() == 0) { + SingleToastUtil.showToast(ResUtil.getString(R.string.the_default_dynamic_cannot_be_commented)); + return; + } + DynamicDetailActivity.start(context, item.getDynamicId(), worldId, + helper.getAdapterPosition(), true, 1); + } + ); + helper.setVisible(R.id.iv_more, item.getDynamicId() != 0); + if (item.getDynamicId() != 0) { + helper.addOnClickListener(R.id.iv_more).addOnClickListener(R.id.ll_share); + } + + View.OnClickListener toDetailListener = v -> { + if (item.getDynamicId() == 0) { + return; + } + DynamicDetailActivity.start(context, item.getDynamicId(), worldId, + helper.getAdapterPosition(), false, 1); + }; + + if (etvContent.mTv != null) { + etvContent.mTv.setOnClickListener(toDetailListener); + } + //跳转去详情 + helper.itemView.setOnClickListener(toDetailListener); + helper.setGone(R.id.line_bottom, getItemCount() - 1 != helper.getLayoutPosition()); + + + if (isUserInfo) { + helper.setTextColor(R.id.tv_time, ContextCompat.getColor(context,R.color.white)); + helper.setTextColor(R.id.expandable_text, ContextCompat.getColor(context,R.color.white)); + helper.setTextColor(R.id.tv_mini_world_name, ContextCompat.getColor(context,R.color.white)); + helper.setTextColor(R.id.tv_like, ContextCompat.getColor(context,R.color.white_tran_60)); + helper.setTextColor(R.id.tv_comment, ContextCompat.getColor(context,R.color.white_tran_60)); + helper.setVisible(R.id.line_bottom, false); + } + } + + private void setLikeCount(BaseViewHolder helper, int likeCount, boolean isLike, boolean isAnim) { + TextView tvLike = helper.getView(R.id.tv_like); + String likeCountStr; + if (likeCount < 0) { + likeCountStr = "0"; + } else if (likeCount >= 1000) { + likeCountStr = "999+"; + } else { + likeCountStr = String.valueOf(likeCount); + } + tvLike.setText(likeCountStr); + + ImageView ivLikeAnim = helper.getView(R.id.iv_like_pic); + if (isLike) { + ivLikeAnim.setImageResource(R.drawable.icon_dy_list_like); + } else { + ivLikeAnim.setImageResource(R.drawable.icon_dy_list_like_false); + } + + } + + private void initRecyclerView(RecyclerView rvImage, List imageUrl, boolean noTextUi) { + if (imageUrl == null) { + return; + } + CalcSize calcSize = new CalcSize(imageBorder); + ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) rvImage.getLayoutParams(); + if (imageUrl.size() > 1) { + params.width = ViewGroup.LayoutParams.MATCH_PARENT; + params.height = ViewGroup.LayoutParams.WRAP_CONTENT; + } else { + //单图的情况,按比例显示 + DynamicMedia media = null; + if (imageUrl.size() > 0) { + media = imageUrl.get(0); + } + if (media == null) { + return; + } + calcSize = ImageUiHelper.calcImage(media, imageBorder); + params.width = calcSize.width + divider; + params.height = calcSize.height + divider; + } + rvImage.setLayoutParams(params); + rvImage.setNestedScrollingEnabled(false); + rvImage.setLayoutManager(new GridLayoutManager(mContext, imageUrl.size() > 2 ? 3 : imageUrl.size())); + DynamicImageAdapter adapter = new DynamicImageAdapter(R.layout.item_dynamic_image, imageUrl); + adapter.setSingleImageHeight(calcSize.height); + adapter.setOnItemClickListener((adapter1, view, position) -> { + PagerOption option = new PagerOption().setSave(true); + BigPhotoActivity.start((Activity) mContext, ObjectTypeHelper.mediaToCustomList(imageUrl), + position, option); + } + ); + rvImage.setAdapter(adapter); + } + + private void setCommentCount(BaseViewHolder helper, int commentCount) { + TextView tvComment = helper.getView(R.id.tv_comment); + String commentCountStr; + if (commentCount < 0) { + commentCountStr = "0"; + } else if (commentCount >= 1000) { + commentCountStr = "999+"; + } else { + commentCountStr = String.valueOf(commentCount); + } + tvComment.setText(commentCountStr); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoGameTeamAdapter.kt b/app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoGameTeamAdapter.kt new file mode 100644 index 0000000..0c3f9ec --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoGameTeamAdapter.kt @@ -0,0 +1,31 @@ +package com.chwl.app.ui.user.adapter + +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.core.view.isVisible +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.ui.utils.load +import com.chwl.core.game_team.UserGameTeamInfo + +class UserInfoGameTeamAdapter(private val isMe: Boolean) : + BaseQuickAdapter(R.layout.user_info_item_game_team) { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder { + return super.onCreateViewHolder(parent, viewType).apply { + addOnClickListener(R.id.layout_play) + getView(R.id.layout_play).isVisible = !isMe + } + } + + override fun convert(helper: BaseViewHolder, item: UserGameTeamInfo) { + helper.setText(R.id.tv_name, item.gameName) + helper.setText(R.id.tv_level, item.proficiency) + helper.setText(R.id.tv_price, item.price?.toString() ?: "") + helper.getView(R.id.iv_icon).load(item.logo) + helper.getView(R.id.iv_bg) + .load(item.background, defaultRes = R.color.color_66000000) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoGiftAdapter.kt b/app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoGiftAdapter.kt new file mode 100644 index 0000000..71dcf6f --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoGiftAdapter.kt @@ -0,0 +1,34 @@ +package com.chwl.app.ui.user.adapter + +import android.view.ViewGroup +import android.widget.ImageView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.ui.utils.load +import com.chwl.core.bean.UserInfoItem +import com.chwl.core.user.bean.GiftWallInfo + +class UserInfoGiftAdapter(private val itemBgRes: Int = R.drawable.user_info_bg_gift) : + BaseQuickAdapter(R.layout.user_info_item_gift) { + override fun onCreateDefViewHolder(parent: ViewGroup?, viewType: Int): BaseViewHolder { + return super.onCreateDefViewHolder(parent, viewType) + } + + override fun convert(helper: BaseViewHolder, item: GiftWallInfo) { + helper.setText(R.id.tv_name, item.giftName) + helper.setText(R.id.tv_count, "x${item.reciveCount}") + val iconView = helper.getView(R.id.iv_icon) + iconView.load(item.picUrl,0f,R.drawable.transparent_draw) + val rankView = helper.itemView.findViewById(R.id.iv_rank) + if (helper.bindingAdapterPosition == 0) { + rankView.setImageResource(R.drawable.ic_gift_one) + } else if (helper.bindingAdapterPosition == 1) { + rankView.setImageResource(R.drawable.ic_gift_two) + } else if (helper.bindingAdapterPosition == 2) { + rankView.setImageResource(R.drawable.ic_gift_three) + } else { + rankView.setImageDrawable(null) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoIndicatorAdapter.java b/app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoIndicatorAdapter.java new file mode 100644 index 0000000..4bfe0c4 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoIndicatorAdapter.java @@ -0,0 +1,102 @@ +package com.chwl.app.ui.user.adapter; + +import android.content.Context; +import android.graphics.Color; +import android.view.Gravity; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.TextView; + +import androidx.core.content.ContextCompat; + +import com.chwl.app.R; +import com.chwl.app.ui.widget.XRecyclerView.ScaleTransitionPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.CommonNavigatorAdapter; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.indicators.LinePagerIndicator; + +import java.util.List; + +public class UserInfoIndicatorAdapter extends CommonNavigatorAdapter { + private final List mTitleList; + + private int textSize = 18; + private float minScale = 0.9f; + private boolean showIndicator = true; + private OnItemSelectListener mOnItemSelectListener; + + public UserInfoIndicatorAdapter(Context context, List charSequences) { + this.mTitleList = charSequences; + } + + @Override + public int getCount() { + return mTitleList == null ? 0 : mTitleList.size(); + } + + @Override + public IPagerTitleView getTitleView(Context context, final int i) { + ScaleTransitionPagerTitleView scaleTransitionPagerTitleView = new ScaleTransitionPagerTitleView(context, true); + scaleTransitionPagerTitleView.setNormalColor(ContextCompat.getColor(context, R.color.white_tran_60)); + scaleTransitionPagerTitleView.setSelectedColor(ContextCompat.getColor(context, R.color.white)); + scaleTransitionPagerTitleView.setMinScale(minScale); + scaleTransitionPagerTitleView.setTextSize(textSize); + int padding = context.getResources().getDimensionPixelOffset(R.dimen.dp_12); + scaleTransitionPagerTitleView.setPadding(padding, 0, padding, 0); + scaleTransitionPagerTitleView.setText(mTitleList.get(i)); + scaleTransitionPagerTitleView.setOnClickListener(view -> { + if (mOnItemSelectListener != null) { + mOnItemSelectListener.onItemSelect(i, scaleTransitionPagerTitleView); + } + }); + return scaleTransitionPagerTitleView; + } + + @Override + public IPagerIndicator getIndicator(Context context) { + LinePagerIndicator indicator = new LinePagerIndicator(context); + indicator.setMode(LinePagerIndicator.MODE_EXACTLY); + indicator.setLineHeight(UIUtil.dip2px(context, 3)); + indicator.setRoundRadius(UIUtil.dip2px(context, 1.5)); + indicator.setLineWidth(UIUtil.dip2px(context, 17)); + indicator.setColors(Color.parseColor("#04d5c6")); + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); +// lp.bottomMargin = mBottomMargin; + indicator.setLayoutParams(lp); + return indicator; + } + + public int getTextSize() { + return textSize; + } + + public void setTextSize(int textSize) { + this.textSize = textSize; + } + + public float getMinScale() { + return minScale; + } + + public void setMinScale(float minScale) { + this.minScale = minScale; + } + + public boolean isShowIndicator() { + return showIndicator; + } + + public void setShowIndicator(boolean showIndicator) { + this.showIndicator = showIndicator; + } + + public void setOnItemSelectListener(OnItemSelectListener onItemSelectListener) { + mOnItemSelectListener = onItemSelectListener; + } + + public interface OnItemSelectListener { + void onItemSelect(int position, TextView view); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoLabelAdapter.kt b/app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoLabelAdapter.kt new file mode 100644 index 0000000..77b4613 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoLabelAdapter.kt @@ -0,0 +1,20 @@ +package com.chwl.app.ui.user.adapter + +import androidx.appcompat.widget.AppCompatTextView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R + +/** + * author: wushaocheng + * Created by wushaocheng on 2023/2/16. + * desc: 用户标签 + */ +class UserInfoLabelAdapter : + BaseQuickAdapter(R.layout.item_user_info_label) { + + override fun convert(helper: BaseViewHolder, item: String) { + helper.setText(R.id.tv_user_tag, item) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoMedalAdapter.kt b/app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoMedalAdapter.kt new file mode 100644 index 0000000..c1732ff --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoMedalAdapter.kt @@ -0,0 +1,53 @@ +package com.chwl.app.ui.user.adapter + +import android.widget.ImageView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.ui.utils.load +import com.chwl.app.ui.utils.loadAnim2 +import com.chwl.core.user.bean.MedalBean +import com.tencent.qgame.animplayer.AnimConfig +import com.tencent.qgame.animplayer.AnimView +import com.tencent.qgame.animplayer.inter.IAnimListener +import com.tencent.qgame.animplayer.util.ScaleType +import java.io.File + +class UserInfoMedalAdapter : + BaseQuickAdapter(R.layout.user_info_item_medal) { + override fun convert(helper: BaseViewHolder, item: MedalBean) { + item.picUrl?.let { + if (it.replace("\n", "").lowercase().endsWith("mp4")) { + val mp4View = helper.getView(R.id.iv_mp4) + mp4View.setScaleType(ScaleType.FIT_XY) + mp4View.setLoop(Int.MAX_VALUE) + mp4View.setAnimListener(object : IAnimListener { + override fun onFailed(errorType: Int, errorMsg: String?) { + + } + + override fun onVideoComplete() { + + } + + override fun onVideoDestroy() { + + } + + override fun onVideoRender(frameIndex: Int, config: AnimConfig?) { + + } + + override fun onVideoStart() { + + } + }) + mp4View.loadAnim2(it) + } else { + val imageView = helper.getView(R.id.iv_image) + imageView.load(item.picUrl,0f,R.drawable.transparent_draw) + } + } + helper.setText(R.id.medalName,item.medalName) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoTopAlbumAdapter.kt b/app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoTopAlbumAdapter.kt new file mode 100644 index 0000000..b4c1ade --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/adapter/UserInfoTopAlbumAdapter.kt @@ -0,0 +1,27 @@ +package com.chwl.app.ui.user.adapter + +import android.view.View +import androidx.core.view.isVisible +import com.chwl.app.R +import com.chwl.app.ui.utils.ImageLoadUtilsV2 +import com.chwl.core.user.bean.UserDetailInfo +import com.zhpan.bannerview.BaseBannerAdapter +import com.zhpan.bannerview.BaseViewHolder + +class UserInfoTopAlbumAdapter(private val reviewStateEnabled: Boolean) : + BaseBannerAdapter() { + override fun getLayoutId(viewType: Int): Int { + return R.layout.user_info_item_top_album + } + + override fun bindData( + helper: BaseViewHolder, + item: UserDetailInfo.DataBean.PrivatePhotoBean?, + position: Int, + pageSize: Int + ) { + ImageLoadUtilsV2.loadImage(helper.findViewById(R.id.iv_image), item?.photoUrl) + val reviewView = helper.findViewById(R.id.iv_review) + reviewView.isVisible = reviewStateEnabled && item?.isReview == true + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/user/adapter/UserJoinWorldAdapter.java b/app/src/main/java/com/chwl/app/ui/user/adapter/UserJoinWorldAdapter.java new file mode 100644 index 0000000..a9603e8 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/adapter/UserJoinWorldAdapter.java @@ -0,0 +1,26 @@ +package com.chwl.app.ui.user.adapter; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.app.common.widget.RectRoundImageView; +import com.chwl.app.ui.utils.ImageLoadUtilsV2; +import com.chwl.core.user.bean.JoinWorldInfo; + +public class UserJoinWorldAdapter extends BaseQuickAdapter { + + public UserJoinWorldAdapter() { + super(R.layout.item_user_join_world); + } + + @Override + protected void convert(BaseViewHolder helper, JoinWorldInfo item) { + RectRoundImageView rectRoundImageView = helper.getView(R.id.rriv_user_join_world); + + ImageLoadUtilsV2.loadImage(rectRoundImageView, item.getIcon()); + helper.setText(R.id.tv_name_user_join_world, item.getName()); + + helper.addOnClickListener(R.id.ll_item_user_join_world); + + } +} diff --git a/app/src/main/java/com/chwl/app/ui/user/adapter/UserLabelAdapter.kt b/app/src/main/java/com/chwl/app/ui/user/adapter/UserLabelAdapter.kt new file mode 100644 index 0000000..79dd2a2 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/adapter/UserLabelAdapter.kt @@ -0,0 +1,49 @@ +package com.chwl.app.ui.user.adapter + +import androidx.appcompat.widget.AppCompatTextView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.hjq.toast.ToastUtils +import com.chwl.app.R +import com.chwl.app.ui.user.event.UserLabelEvent +import com.chwl.core.user.bean.UserLabelItemInfo +import org.greenrobot.eventbus.EventBus + +/** + * author: wushaocheng + * Created by wushaocheng on 2023/2/16. + * desc: 用户标签 + */ +class UserLabelAdapter : + BaseQuickAdapter(R.layout.item_user_label) { + + //用来记录已经勾选的位置(set集合是为了防止放入重复数据) + var mutilSelectedList = mutableSetOf() + + override fun convert(helper: BaseViewHolder, item: UserLabelItemInfo) { + helper.setText(R.id.tv_user_tag, item.label) + val tvLabel = helper.getView(R.id.tv_user_tag) + if (item.picked) { + mutilSelectedList.add(helper.layoutPosition) + } else { + mutilSelectedList.remove(helper.layoutPosition) + } + tvLabel.isSelected = item.picked + helper.itemView.setOnClickListener { + if (mutilSelectedList.contains(helper.layoutPosition)) { + mutilSelectedList.remove(helper.layoutPosition) + tvLabel.isSelected = false + EventBus.getDefault().post(UserLabelEvent(item.label)) + } else { + if (mutilSelectedList.size != 20) { + mutilSelectedList.add(helper.layoutPosition) + tvLabel.isSelected = true + EventBus.getDefault().post(UserLabelEvent(item.label)) + } else { + ToastUtils.show(mContext.getString(R.string.max_to_add_label)) + } + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/user/adapter/UserLabelDialogAdapter.kt b/app/src/main/java/com/chwl/app/ui/user/adapter/UserLabelDialogAdapter.kt new file mode 100644 index 0000000..ccd24e2 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/adapter/UserLabelDialogAdapter.kt @@ -0,0 +1,23 @@ +package com.chwl.app.ui.user.adapter + +import androidx.appcompat.widget.AppCompatTextView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.core.user.bean.UserLabelItemInfo + +/** + * author: wushaocheng + * Created by wushaocheng on 2023/2/16. + * desc: 用户标签 + */ +class UserLabelDialogAdapter : + BaseQuickAdapter(R.layout.item_user_tag) { + + override fun convert(helper: BaseViewHolder, item: String) { + val tvLabel = helper.getView(R.id.tv_user_tag) + tvLabel.isSelected = helper.layoutPosition <3 + helper.setText(R.id.tv_user_tag, item) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/user/adapter/UserModifyLabelAdapter.kt b/app/src/main/java/com/chwl/app/ui/user/adapter/UserModifyLabelAdapter.kt new file mode 100644 index 0000000..309b467 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/adapter/UserModifyLabelAdapter.kt @@ -0,0 +1,22 @@ +package com.chwl.app.ui.user.adapter + +import androidx.appcompat.widget.AppCompatTextView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R + +/** + * author: wushaocheng + * Created by wushaocheng on 2023/2/16. + * desc: 用户标签 + */ +class UserModifyLabelAdapter : + BaseQuickAdapter(R.layout.item_user_modify_label) { + + override fun convert(helper: BaseViewHolder, item: String) { + val tvLabel = helper.getView(R.id.tv_user_tag) + tvLabel.isSelected = helper.layoutPosition <3 + helper.setText(R.id.tv_user_tag, item) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/user/adapter/UserModifyPhotosAdapter.java b/app/src/main/java/com/chwl/app/ui/user/adapter/UserModifyPhotosAdapter.java new file mode 100644 index 0000000..f34249e --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/adapter/UserModifyPhotosAdapter.java @@ -0,0 +1,119 @@ +package com.chwl.app.ui.user.adapter; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; + +import com.makeramen.roundedimageview.RoundedImageView; +import com.netease.nim.uikit.support.glide.GlideApp; +import com.chwl.app.R; +import com.chwl.core.user.bean.UserPhoto; + +import java.util.List; + +/** + * Created by chenran on 2017/7/24. + */ + +public class UserModifyPhotosAdapter extends BaseAdapter{ + private Context mContext; + private List photoUrls; + private PhotoItemClickListener listener; + private boolean isEditMode; + + public void setEditMode(boolean editMode) { + isEditMode = editMode; + } + + public UserModifyPhotosAdapter(Context context, List photoUrls, PhotoItemClickListener listener) + { + this.mContext=context; + this.photoUrls = photoUrls; + this.listener = listener; + } + @Override + public int getCount() { + if (photoUrls == null) { + return 1; + } else { + return photoUrls.size() + 1; + } + } + + @Override + public Object getItem(int position) { + return null; + } + + @Override + public long getItemId(int position) { + return 0; + } + + @Override + public View getView(final int position, View convertView, ViewGroup parent) { + UserModifyPhotosViewHolder holder; + if (null == convertView) { + holder = new UserModifyPhotosViewHolder(); + convertView = LayoutInflater.from(mContext).inflate(R.layout.list_item_user_photos_modify, null); + holder.imageView = convertView.findViewById(R.id.iv_user_photo); + holder.imageDelete = convertView.findViewById(R.id.iv_photo_delete); + convertView.setTag(holder); + } else { + holder = (UserModifyPhotosViewHolder) convertView.getTag(); + } + + holder.imageView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (listener != null) { + listener.onPhotoItemClick(position); + } + } + }); + holder.imageDelete.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (listener !=null) { + listener.onPhotoDeleteClick(position); + } + } + }); + + if (position == 0) { + holder.imageView.setImageResource(R.drawable.icon_dy_add_image); + holder.imageDelete.setVisibility(View.GONE); + } else { + UserPhoto userPhoto = photoUrls.get(position-1); + GlideApp.with(mContext) + .load(userPhoto.getPhotoUrl()) + .placeholder(R.drawable.default_cover) + .dontAnimate() + .into(holder.imageView); + if (isEditMode) { + holder.imageDelete.setVisibility(View.VISIBLE); + } else { + holder.imageDelete.setVisibility(View.GONE); + } + } + + return convertView; + } + + public void setData(List privatePhoto) { + this.photoUrls = privatePhoto; + } + + class UserModifyPhotosViewHolder { + private RoundedImageView imageView; + private ImageView imageDelete; + } + + public interface PhotoItemClickListener { + void onPhotoItemClick(int position); + void onPhotoDeleteClick(int position); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/user/adapter/UserPhotoAdapter.java b/app/src/main/java/com/chwl/app/ui/user/adapter/UserPhotoAdapter.java new file mode 100644 index 0000000..d496e6c --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/adapter/UserPhotoAdapter.java @@ -0,0 +1,132 @@ +package com.chwl.app.ui.user.adapter; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.recyclerview.widget.RecyclerView; + +import com.chwl.app.R; +import com.chwl.app.common.widget.RectRoundImageView; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.user.bean.UserPhoto; + +import java.util.List; + +/** + * @author chenran + * @date 2017/7/24 + */ +public class UserPhotoAdapter extends RecyclerView.Adapter { + + private static final int TYPE_ADD = 100; + private static final int TYPE_NORMAL = 101; + + private List photoUrls; + private int type; + private boolean mIsOwner; + + private boolean isSmall = false; + + public UserPhotoAdapter(List photoUrls, int type, long uid) { + this.photoUrls = photoUrls; + this.type = type; + mIsOwner = AuthModel.get().getCurrentUid() == uid && uid != 0; + + } + + public void setSmall(boolean small) { + isSmall = small; + } + + public interface ImageClickListener { + void click(int position, UserPhoto userPhoto, boolean isOwner); + } + + private ImageClickListener mImageClickListener; + + public void setImageClickListener(UserPhotoAdapter.ImageClickListener imageClickListener) { + mImageClickListener = imageClickListener; + } + + @Override + public UserPhtotViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View item; + //表示在个人中心 + if (isInUserInfoView()) { + if (viewType == TYPE_NORMAL) { + + if (isSmall) + item = LayoutInflater.from(parent.getContext()). + inflate(R.layout.list_item_user_photo_small, parent, false); + else + item = LayoutInflater.from(parent.getContext()). + inflate(R.layout.list_item_user_photo, parent, false); + } else { + item = LayoutInflater.from(parent.getContext()). + inflate(R.layout.list_item_user_photo_edit, parent, false); + } + } else { + if (isSmall) + item = LayoutInflater.from(parent.getContext()). + inflate(R.layout.list_item_user_photo_small, parent, false); + else + item = LayoutInflater.from(parent.getContext()). + inflate(R.layout.list_item_user_photo, parent, false); + } + return new UserPhtotViewHolder(item); + } + + @Override + public void onBindViewHolder(UserPhtotViewHolder holder, final int position) { + UserPhoto photo = null; + if (isInUserInfoView()) { + if (position > 0) { + photo = photoUrls.get(position - 1); + ImageLoadUtils.loadPhotoThumbnail(holder.itemView.getContext(), photo.getPhotoUrl(), holder.mPhotoImage); + } + } else { + photo = photoUrls.get(position); + ImageLoadUtils.loadPhotoThumbnail(holder.itemView.getContext(), photo.getPhotoUrl(), holder.mPhotoImage); + } + UserPhoto finalPhoto = photo; + holder.itemView.setOnClickListener(v -> { + if (mImageClickListener != null) { + mImageClickListener.click(position, finalPhoto, mIsOwner); + } + }); + + } + + @Override + public int getItemCount() { + if (photoUrls == null) { + return 0; + } else { + return photoUrls.size() + (isInUserInfoView() ? 1 : 0); + } + } + + private boolean isInUserInfoView() { + return type == 0 && mIsOwner; + } + + @Override + public int getItemViewType(int position) { + if (isInUserInfoView()) return (position == 0) ? TYPE_ADD : TYPE_NORMAL; + else return TYPE_NORMAL; + } + + static class UserPhtotViewHolder extends RecyclerView.ViewHolder { + + private RectRoundImageView mPhotoImage; + + UserPhtotViewHolder(View itemView) { + super(itemView); + + mPhotoImage = itemView.findViewById(R.id.iv_user_photo); + } + + } +} diff --git a/app/src/main/java/com/chwl/app/ui/user/adapter/UserTabBaseAdapter.java b/app/src/main/java/com/chwl/app/ui/user/adapter/UserTabBaseAdapter.java new file mode 100644 index 0000000..9180251 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/adapter/UserTabBaseAdapter.java @@ -0,0 +1,53 @@ +package com.chwl.app.ui.user.adapter; + +import android.content.Context; + +import com.chad.library.adapter.base.BaseMultiItemQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.core.bean.GiftTitleInfo; +import com.chwl.core.bean.UserInfoItem; + +import java.util.List; + +public abstract class UserTabBaseAdapter extends BaseMultiItemQuickAdapter { + + public UserTabBaseAdapter(Context context, List data) { + super(data); + this.mContext = context; + + addItemType(UserInfoItem.TYPE_NONE, R.layout.layout_none); + addItemType(UserInfoItem.TYPE_DIV, R.layout.layout_gift_div); + addItemType(UserInfoItem.TYPE_TITLE, R.layout.layout_gift_title); + } + + public void setTitle(BaseViewHolder helper, UserInfoItem item) { + GiftTitleInfo giftTitleInfo = (GiftTitleInfo) item.getData(); + + if (giftTitleInfo == null) { + helper.setText(R.id.tv_title_text, ""); + helper.setText(R.id.tv_title_number, "(" + 0 + ")"); + + } else { + helper.setText(R.id.tv_title_text, giftTitleInfo.getTitle()); + helper.setText(R.id.tv_title_number, "(" + giftTitleInfo.getNum() + ")"); + + } + + } + + @Override + protected void convert(BaseViewHolder helper, UserInfoItem item) { + if (item == null) + return; + + switch (item.getItemType()) { + case UserInfoItem.TYPE_DIV: + break; + + case UserInfoItem.TYPE_TITLE: + setTitle(helper, item); + break; + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/user/decorationsend/DSAttentionFragment.java b/app/src/main/java/com/chwl/app/ui/user/decorationsend/DSAttentionFragment.java new file mode 100644 index 0000000..225e960 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/decorationsend/DSAttentionFragment.java @@ -0,0 +1,202 @@ +package com.chwl.app.ui.user.decorationsend; + +import static com.chwl.app.R.id.swipe_refresh; + +import android.app.Activity; +import android.os.Bundle; + +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import com.chwl.app.R; +import com.chwl.app.base.BaseFragment; +import com.chwl.core.Constants; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.praise.event.PraiseEvent; +import com.chwl.core.user.AttentionModel; +import com.chwl.core.user.bean.AttentionInfo; +import com.chwl.core.user.event.LoginUserInfoUpdateEvent; +import com.chwl.library.utils.ListUtils; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.ArrayList; +import java.util.List; + +import io.reactivex.SingleObserver; +import io.reactivex.disposables.Disposable; + +public class DSAttentionFragment extends BaseFragment { + public static final String TAG = "AttentionFragment"; + + private RecyclerView mRecyclerView; + private SwipeRefreshLayout swipeRefreshLayout; + private DSAttentionListAdapter mAdapter; + private List mAttentionInfoList = new ArrayList<>(); + private int mPage = Constants.PAGE_START; + + private DecorationSendActivity friendActivity; + + public static DSAttentionFragment newInstance() { + return new DSAttentionFragment(); + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + EventBus.getDefault().register(this); + } + + @Override + public void onDestroy() { + super.onDestroy(); + EventBus.getDefault().unregister(this); + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + + if (activity instanceof DecorationSendActivity) { + friendActivity = (DecorationSendActivity) activity; + } + } + + @Override + public void setUserVisibleHint(boolean isVisibleToUser) { + super.setUserVisibleHint(isVisibleToUser); + //需要踩人等东西,所以进入这个界面需要强制刷新 + if (isVisibleToUser) { + firstLoadData(); + } + } + + @Override + public void onFindViews() { + mRecyclerView = mView.findViewById(R.id.recycler_view); + swipeRefreshLayout = mView.findViewById(swipe_refresh); + mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext())); + } + + @Override + public void onSetListener() { + swipeRefreshLayout.setOnRefreshListener(onRefreshListener); + mAdapter = new DSAttentionListAdapter(mAttentionInfoList); + mAdapter.setRylListener(attentionInfo -> { + if (friendActivity != null) { + friendActivity.showSureDialog(attentionInfo.getUid(), attentionInfo.getNick()); + } + }); + mAdapter.setOnLoadMoreListener(() -> { + mPage++; + onRefreshing(); + }, mRecyclerView); + } + + @Override + public void initiate() { + mRecyclerView.setAdapter(mAdapter); + showLoading(); + onRefreshing(); + } + + @Override + public int getRootLayoutId() { + return R.layout.frg_decoration_send_list; + } + + SwipeRefreshLayout.OnRefreshListener onRefreshListener = this::firstLoadData; + + public void firstLoadData() { + mPage = Constants.PAGE_START; + onRefreshing(); + } + + private void onRefreshing() { + AttentionModel.get().getAttentionList( + AuthModel.get().getCurrentUid(), + mPage, + Constants.PAGE_SIZE + ) + .subscribe(new SingleObserver>() { + @Override + public void onSubscribe(Disposable d) { + mCompositeDisposable.add(d); + } + + @Override + public void onSuccess(List attentionInfos) { + onGetAttentionList(attentionInfos, mPage); + } + + @Override + public void onError(Throwable e) { + onGetAttentionListFail(e.getMessage(), mPage); + } + }); + } + + public void onGetAttentionList(List attentionInfoList, int page) { + mPage = page; + if (!ListUtils.isListEmpty(attentionInfoList)) { + if (mPage == Constants.PAGE_START) { + hideStatus(); + swipeRefreshLayout.setRefreshing(false); + mAttentionInfoList.clear(); + mAdapter.setNewData(attentionInfoList); + if (attentionInfoList.size() < Constants.PAGE_SIZE) { + mAdapter.setEnableLoadMore(false); + } + } else { + mAdapter.loadMoreComplete(); + mAdapter.addData(attentionInfoList); + } + } else { + if (mPage == Constants.PAGE_START) { + swipeRefreshLayout.setRefreshing(false); + showNoData(getString(R.string.no_attention_text)); + } else { + mAdapter.loadMoreEnd(true); + } + + } + } + + public void onGetAttentionListFail(String error, int page) { + mPage = page; + if (mPage == Constants.PAGE_START) { + swipeRefreshLayout.setRefreshing(false); + showNetworkErr(); + } else { + mAdapter.loadMoreFail(); + toast(error); + } + } + + // ------------------关注动作回调 begin------------------- + @Subscribe(threadMode = ThreadMode.MAIN) + public void onPraise(PraiseEvent event) { + if (event.isFailed()) { + return; + } + onRefreshing(); + } + // ------------------关注动作回调 end------------------- + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onLoginUserInfoUpdateEvent(LoginUserInfoUpdateEvent event) { + onRefreshing(); + } + + @Override + public void onReloadData() { + super.onReloadData(); + mPage = Constants.PAGE_START; + showLoading(); + onRefreshing(); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/user/decorationsend/DSAttentionListAdapter.java b/app/src/main/java/com/chwl/app/ui/user/decorationsend/DSAttentionListAdapter.java new file mode 100644 index 0000000..6898854 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/decorationsend/DSAttentionListAdapter.java @@ -0,0 +1,61 @@ +package com.chwl.app.ui.user.decorationsend; + +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.core.level.UserLevelVo; +import com.chwl.core.noble.bean.NobleInfo; +import com.chwl.core.user.bean.AttentionInfo; + +import java.util.List; + +public class DSAttentionListAdapter extends DSBaseListAdapter { + + public DSAttentionListAdapter(List attentionInfoList) { + super(attentionInfoList); + } + + @Override + public String getNick(AttentionInfo info) { + return info.getNick(); + } + + @Override + public String getAvatar(AttentionInfo info) { + return info.getAvatar(); + } + + @Override + public NobleInfo getNobleInfo(AttentionInfo info) { + return info.nobleUsers; + } + + @Override + public UserLevelVo getUserLevelVo(AttentionInfo info) { + return info.userLevelVo; + } + + @Override + public int getGender(AttentionInfo info) { + return info.getGender(); + } + + @Override + public String getUserDesc(AttentionInfo info) { + return info.getUserDesc(); + } + + @Override + public void listeners(AttentionInfo info) { + if (rylListener != null) + rylListener.sendListener(info); + } + + private onClickListener rylListener; + + public interface onClickListener { + void sendListener(AttentionInfo attentionInfo); + } + + public void setRylListener(onClickListener onClickListener) { + rylListener = onClickListener; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/user/decorationsend/DSBaseListAdapter.java b/app/src/main/java/com/chwl/app/ui/user/decorationsend/DSBaseListAdapter.java new file mode 100644 index 0000000..beb86b3 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/decorationsend/DSBaseListAdapter.java @@ -0,0 +1,86 @@ +package com.chwl.app.ui.user.decorationsend; + +import android.text.TextUtils; +import android.view.View; +import android.widget.TextView; + +import androidx.appcompat.widget.AppCompatImageView; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.app.ui.widget.NobleAvatarView; +import com.chwl.core.level.UserLevelVo; +import com.chwl.core.noble.bean.NobleInfo; +import com.chwl.core.noble.NobleUtil; + +import java.util.List; + +/** + * 好友,关注,粉丝展示ui一致 + */ +public abstract class DSBaseListAdapter extends BaseQuickAdapter { + + DSBaseListAdapter(List list) { + super(R.layout.item_send, list); + } + + @Override + protected void convert(K helper, T item) { + if (item == null) return; + + helper.setText(R.id.tv_userName, getNick(item)); + helper.setOnClickListener(R.id.tv_send, v -> listeners(item)); + + NobleInfo nobleUsers = getNobleInfo(item); + + NobleAvatarView nobleAvatarView = helper.getView(R.id.noble_avatar_view); + nobleAvatarView.setSize(50, 65, 15); + nobleAvatarView.setData(getAvatar(item), nobleUsers); + + AppCompatImageView ivNobleLevel = helper.getView(R.id.iv_user_badge); + ivNobleLevel.setVisibility(View.GONE); + if (nobleUsers != null) { + String badgeByLevel = NobleUtil.getBadgeByLevel(nobleUsers.getLevel()); + if (!TextUtils.isEmpty(badgeByLevel)) { + ivNobleLevel.setVisibility(View.VISIBLE); + NobleUtil.loadResource(badgeByLevel, ivNobleLevel); + } + } + + AppCompatImageView ivUserLevel = helper.getView(R.id.iv_user_level); + AppCompatImageView ivOtherLevel = helper.getView(R.id.iv_other_level); + ivUserLevel.setVisibility(View.GONE); + ivOtherLevel.setVisibility(View.GONE); + UserLevelVo userLevelVo = getUserLevelVo(item); + if (userLevelVo != null && !TextUtils.isEmpty(userLevelVo.getExperUrl())) { + ivUserLevel.setVisibility(View.VISIBLE); + ImageLoadUtils.loadImage(mContext, userLevelVo.getExperUrl(), ivUserLevel); + + if (!TextUtils.isEmpty(userLevelVo.getCharmUrl())) { + ivOtherLevel.setVisibility(View.VISIBLE); + ImageLoadUtils.loadImage(mContext, userLevelVo.getCharmUrl(), ivOtherLevel); + } + } + + AppCompatImageView gender = helper.getView(R.id.iv_gender); + if (getGender(item) == 2) { + gender.setImageResource(R.drawable.ic_gender_female); + } else { + gender.setImageResource(R.drawable.ic_gender_male); + } + + TextView desc = helper.getView(R.id.tv_desc); + desc.setText(getUserDesc(item)); + } + + public abstract String getNick(T info); + public abstract String getAvatar(T info); + public abstract NobleInfo getNobleInfo(T info); + public abstract UserLevelVo getUserLevelVo(T info); + public abstract int getGender(T info); + public abstract String getUserDesc(T info); + public abstract void listeners(T info); + +} diff --git a/app/src/main/java/com/chwl/app/ui/user/decorationsend/DSFansListFragment.java b/app/src/main/java/com/chwl/app/ui/user/decorationsend/DSFansListFragment.java new file mode 100644 index 0000000..2f5d5b8 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/decorationsend/DSFansListFragment.java @@ -0,0 +1,219 @@ +package com.chwl.app.ui.user.decorationsend; + +import android.app.Activity; +import android.content.Context; +import android.os.Bundle; + +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import com.chwl.app.R; +import com.chwl.app.base.BaseFragment; +import com.chwl.app.ui.user.activity.UserInfoActivity; +import com.chwl.core.Constants; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.praise.event.PraiseEvent; +import com.chwl.core.user.AttentionModel; +import com.chwl.core.user.bean.FansInfo; +import com.chwl.core.user.bean.FansListInfo; +import com.chwl.core.user.event.LoginUserInfoUpdateEvent; +import com.chwl.library.utils.ListUtils; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.ArrayList; +import java.util.List; + +import io.reactivex.SingleObserver; +import io.reactivex.disposables.Disposable; + +public class DSFansListFragment extends BaseFragment { + private RecyclerView mRecyclerView; + private SwipeRefreshLayout mSwipeRefreshLayout; + private DSFansViewAdapter mAdapter; + private int mCurrentCounter = Constants.PAGE_START; + private List mFansInfoList = new ArrayList<>(); + private Context mContext; + private int mPageType; + private DecorationSendActivity friendActivity; + + public static DSFansListFragment newInstanceForSelect() { + return new DSFansListFragment(); + } + + public static DSFansListFragment newInstance(int pageType) { + DSFansListFragment fragment = new DSFansListFragment(); + Bundle bundle = new Bundle(); + bundle.putInt(Constants.KEY_PAGE_TYPE, pageType); + fragment.setArguments(bundle); + return fragment; + } + + @Override + protected void onInitArguments(Bundle bundle) { + super.onInitArguments(bundle); + if (bundle != null) { + mPageType = bundle.getInt(Constants.KEY_PAGE_TYPE); + } + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + if (activity instanceof DecorationSendActivity) { + friendActivity = (DecorationSendActivity) activity; + } + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mContext = getContext(); + EventBus.getDefault().register(this); + } + + @Override + public void onDestroy() { + super.onDestroy(); + EventBus.getDefault().unregister(this); + } + + @Override + public void onFindViews() { + mRecyclerView = mView.findViewById(R.id.recycler_view); + mSwipeRefreshLayout = mView.findViewById(R.id.swipe_refresh); + } + + @Override + public void onSetListener() { + mRecyclerView.setLayoutManager(new LinearLayoutManager(mContext)); + mAdapter = new DSFansViewAdapter(mFansInfoList); + mAdapter.setOnLoadMoreListener(() -> { + mCurrentCounter++; + onRefreshing(); + }, mRecyclerView); + mRecyclerView.setAdapter(mAdapter); + mSwipeRefreshLayout.setOnRefreshListener(() -> { + mCurrentCounter = Constants.PAGE_START; + onRefreshing(); + }); + mAdapter.setRylListener(new DSFansViewAdapter.OnItemClickListener() { + @Override + public void onItemClick(FansInfo fansInfo) { + UserInfoActivity.Companion.start(mContext, fansInfo.getUid()); + } + + @Override + public void sendListener(FansInfo attentionInfo) { + if (friendActivity != null) { + friendActivity.showSureDialog(attentionInfo.getUid(), attentionInfo.getNick()); + } + } + }); + } + + private void onRefreshing() { + AttentionModel.get().getFansList( + AuthModel.get().getCurrentUid(), + mCurrentCounter, + Constants.PAGE_SIZE + ).subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) { + mCompositeDisposable.add(d); + } + + @Override + public void onSuccess(FansListInfo fansListInfo) { + onGetMyFansList(fansListInfo, mPageType, mCurrentCounter); + } + + @Override + public void onError(Throwable e) { + onGetMyFansListFail(e.getMessage(), mPageType, mCurrentCounter); + } + }); + } + + @Override + public void initiate() { + showLoading(); + onRefreshing(); + } + + @Override + public int getRootLayoutId() { + return R.layout.frg_decoration_send_list; + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onPraise(PraiseEvent event) { + getDialogManager().dismissDialog(); + if (!event.isFailed()) { + toast(event.getError()); + return; + } + //该界面关注后,关注按钮消失,所有没有取消操作 + toast(getString(R.string.fan_success)); + } + + public void onGetMyFansList(FansListInfo fansListInfo, int pageType, int page) { + mCurrentCounter = page; + if (pageType == mPageType) { + mSwipeRefreshLayout.setRefreshing(false); + if (fansListInfo == null || ListUtils.isListEmpty(fansListInfo.getFansList())) { + //第一页 + if (mCurrentCounter == Constants.PAGE_START) { + showNoData(getString(R.string.no_fan_text)); + } else { + mAdapter.loadMoreEnd(true); + } + } else { + hideStatus(); + if (mCurrentCounter == Constants.PAGE_START) { + mFansInfoList.clear(); + List fansList = fansListInfo.getFansList(); + mFansInfoList.addAll(fansList); + mAdapter.setNewData(mFansInfoList); + if (fansList.size() < Constants.PAGE_SIZE) { + mAdapter.setEnableLoadMore(false); + } + return; + } + mAdapter.loadMoreComplete(); + mAdapter.addData(fansListInfo.getFansList()); + } + } + } + + public void onGetMyFansListFail(String error, int pageType, int page) { + mCurrentCounter = page; + if (pageType == mPageType) { + if (mCurrentCounter == Constants.PAGE_START) { + mSwipeRefreshLayout.setRefreshing(false); + showNetworkErr(); + } else { + mAdapter.loadMoreFail(); + toast(error); + } + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onLoginUserInfoUpdateEvent(LoginUserInfoUpdateEvent event) { + mCurrentCounter = Constants.PAGE_START; + onRefreshing(); + } + + @Override + public void onReloadData() { + super.onReloadData(); + mCurrentCounter = Constants.PAGE_START; + showLoading(); + onRefreshing(); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/user/decorationsend/DSFansViewAdapter.java b/app/src/main/java/com/chwl/app/ui/user/decorationsend/DSFansViewAdapter.java new file mode 100644 index 0000000..0a9aa7a --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/decorationsend/DSFansViewAdapter.java @@ -0,0 +1,63 @@ +package com.chwl.app.ui.user.decorationsend; + +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.core.level.UserLevelVo; +import com.chwl.core.noble.bean.NobleInfo; +import com.chwl.core.user.bean.FansInfo; + +import java.util.List; + +public class DSFansViewAdapter extends DSBaseListAdapter { + + private OnItemClickListener onItemClickListener; + + public interface OnItemClickListener { + void onItemClick(FansInfo fansInfo); + void sendListener(FansInfo attentionInfo); + } + + public void setRylListener(OnItemClickListener onClickListener) { + onItemClickListener = onClickListener; + } + + public DSFansViewAdapter(List fansInfoList) { + super(fansInfoList); + } + + @Override + public String getNick(FansInfo info) { + return info.getNick(); + } + + @Override + public String getAvatar(FansInfo info) { + return info.getAvatar(); + } + + @Override + public NobleInfo getNobleInfo(FansInfo info) { + return info.getNobleUsers(); + } + + @Override + public UserLevelVo getUserLevelVo(FansInfo info) { + return info.getUserLevelVo(); + } + + @Override + public int getGender(FansInfo info) { + return info.getGender(); + } + + @Override + public String getUserDesc(FansInfo info) { + return info.getUserDesc(); + } + + @Override + public void listeners(FansInfo info) { + if (onItemClickListener != null) + onItemClickListener.sendListener(info); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/user/decorationsend/DSFriendListAdapter.java b/app/src/main/java/com/chwl/app/ui/user/decorationsend/DSFriendListAdapter.java new file mode 100644 index 0000000..2522db4 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/decorationsend/DSFriendListAdapter.java @@ -0,0 +1,61 @@ +package com.chwl.app.ui.user.decorationsend; + +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.core.level.UserLevelVo; +import com.chwl.core.noble.bean.NobleInfo; +import com.chwl.core.user.bean.UserInfo; + +import java.util.List; + +public class DSFriendListAdapter extends DSBaseListAdapter { + + private onClickListener rylListener; + + public DSFriendListAdapter(List userInfoList) { + super(userInfoList); + } + + @Override + public String getNick(UserInfo info) { + return info.getNick(); + } + + @Override + public String getAvatar(UserInfo info) { + return info.getAvatar(); + } + + @Override + public NobleInfo getNobleInfo(UserInfo info) { + return info.getNobleUsers(); + } + + @Override + public UserLevelVo getUserLevelVo(UserInfo info) { + return info.getUserLevelVo(); + } + + @Override + public int getGender(UserInfo info) { + return info.getGender(); + } + + @Override + public String getUserDesc(UserInfo info) { + return info.getUserDesc(); + } + + public void setRylListener(onClickListener onClickListener) { + rylListener = onClickListener; + } + + @Override + public void listeners(UserInfo info) { + if (rylListener != null) + rylListener.sendListener(info); + } + + public interface onClickListener { + void sendListener(UserInfo userInfo); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/user/decorationsend/DSFriendListFragment.java b/app/src/main/java/com/chwl/app/ui/user/decorationsend/DSFriendListFragment.java new file mode 100644 index 0000000..4a1b885 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/decorationsend/DSFriendListFragment.java @@ -0,0 +1,157 @@ +package com.chwl.app.ui.user.decorationsend; + +import android.app.Activity; +import android.os.Bundle; + +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import com.chwl.app.R; +import com.chwl.app.base.BaseFragment; +import com.chwl.core.im.friend.IMFriendModel; +import com.chwl.core.manager.IMNetEaseManager; +import com.chwl.core.manager.RelationShipEvent; +import com.chwl.core.user.UserModel; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.core.user.event.LoginUserInfoUpdateEvent; +import com.chwl.library.utils.ListUtils; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.List; + +import io.reactivex.SingleObserver; +import io.reactivex.disposables.Disposable; + +public class DSFriendListFragment extends BaseFragment { + + private DSFriendListAdapter mAdapter = null; + private DecorationSendActivity selectFriendActivity; + private SwipeRefreshLayout mSwipeRefresh; + private RecyclerView mRecyclerView; + + public static DSFriendListFragment newInstances() { + return new DSFriendListFragment(); + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + if (activity instanceof DecorationSendActivity) { + selectFriendActivity = (DecorationSendActivity) activity; + } + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + EventBus.getDefault().register(this); + } + + @Override + public void onDestroy() { + super.onDestroy(); + EventBus.getDefault().unregister(this); + } + + @Override + public void onFindViews() { + mSwipeRefresh = mView.findViewById(R.id.swipe_refresh); + mRecyclerView = mView.findViewById(R.id.recycler_view); + } + + @Override + public void onSetListener() { + } + + @Override + public void initiate() { + mSwipeRefresh.setOnRefreshListener(() -> { + mSwipeRefresh.setRefreshing(true); + loadFriends(); + mSwipeRefresh.setRefreshing(false); + }); + + mAdapter = new DSFriendListAdapter(null); + mAdapter.setEnableLoadMore(true); + mAdapter.setRylListener((attentionInfo)->{ + if (selectFriendActivity != null && attentionInfo != null) { + selectFriendActivity.showSureDialog(attentionInfo.getUid(), attentionInfo.getNick()); + } + }); + mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); + mRecyclerView.setAdapter(mAdapter); + + loadFriends(); + + Disposable d = IMNetEaseManager.get().getRelationShipEventObservable().subscribe(this::onGetRelationShipEvent); + mCompositeDisposable.add(d); + } + + private void onGetRelationShipEvent(RelationShipEvent event) { + if (event.event == RelationShipEvent.EVENT_FRIEND_UPDATE) { + onFriendListUpdate(event.accounts); + } + } + + private void loadFriends() { + onFriendListUpdate(IMFriendModel.get().getMyFriendsAccounts()); + } + + @Override + public int getRootLayoutId() { + return R.layout.frg_decoration_send_list; + } + + private void onFriendListUpdate(List accounts) { + if (ListUtils.isListEmpty(accounts)) { + showNoData(getString(R.string.no_frenids_text)); + return; + } + UserModel.get().loadUserInfoByUids(accounts).subscribe(new SingleObserver>() { + @Override + public void onSubscribe(Disposable d) { + mCompositeDisposable.add(d); + } + + @Override + public void onSuccess(List userInfos) { + setData(userInfos); + } + + @Override + public void onError(Throwable e) { + toast(e.getMessage()); + } + }); + + } + + private void setData(List userInfo) { + if (userInfo != null && !userInfo.isEmpty()) { + hideStatus(); + mAdapter.setNewData(userInfo); + mAdapter.notifyDataSetChanged(); + } else { + showNoData(getString(R.string.no_frenids_text)); + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onLoginUserInfoUpdateEvent(LoginUserInfoUpdateEvent event) { + mRecyclerView.postDelayed(()->onFriendListUpdate(IMFriendModel.get().getMyFriendsAccounts()) + , 250); + } + + + @Override + public void onReloadData() { + super.onReloadData(); + showLoading(); + loadFriends(); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/user/decorationsend/DecorationSendActivity.java b/app/src/main/java/com/chwl/app/ui/user/decorationsend/DecorationSendActivity.java new file mode 100644 index 0000000..cd0fe9e --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/decorationsend/DecorationSendActivity.java @@ -0,0 +1,173 @@ +package com.chwl.app.ui.user.decorationsend; + +import android.content.Context; +import android.content.Intent; +import android.view.View; + +import androidx.fragment.app.Fragment; + +import com.chwl.app.R; +import com.chwl.app.base.BaseBindingActivity; +import com.chwl.app.base.TitleBar; +import com.chwl.app.common.ViewPagerAdapter; +import com.chwl.app.databinding.ActivityDecorationSendBinding; +import com.chwl.app.decoration.helper.DecorationDialogHelper; +import com.chwl.app.decoration.helper.DecorationSaleType; +import com.chwl.app.decoration.view.widgets.CarMagicIndicator; +import com.chwl.app.friend.action.AbstractSelectFriendAction; +import com.chwl.app.ui.search.SearchActivity; +import com.chwl.app.ui.widget.magicindicator.ViewPagerHelper; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.CommonNavigator; +import com.chwl.core.decoration.car.bean.CarInfo; +import com.chwl.core.decoration.headwear.bean.HeadWearInfo; +import com.chwl.core.home.bean.TabInfo; +import com.chwl.library.annatation.ActLayoutRes; +import com.chwl.library.utils.ResUtil; + +import java.util.ArrayList; +import java.util.List; + +@ActLayoutRes(R.layout.activity_decoration_send) +public class DecorationSendActivity extends BaseBindingActivity implements CarMagicIndicator.OnItemSelectListener { + + private static final String CAR_INFO = "carInfo"; + private static final String WEAR_INFO = "wearInfo"; + + private String[] titles = {ResUtil.getString(R.string.user_decorationsend_decorationsendactivity_01), ResUtil.getString(R.string.user_decorationsend_decorationsendactivity_02), ResUtil.getString(R.string.user_decorationsend_decorationsendactivity_03)}; + private CarInfo carInfo; + private HeadWearInfo wearInfo; + private int type; + + public static void start(Context context, CarInfo carInfo) { + Intent intent = new Intent(context, DecorationSendActivity.class); + intent.putExtra(AbstractSelectFriendAction.KEY_TYPE, AbstractSelectFriendAction.TYPE_CAR); + intent.putExtra(CAR_INFO, carInfo); + context.startActivity(intent); + } + + public static void start(Context context, HeadWearInfo wearInfo) { + Intent intent = new Intent(context, DecorationSendActivity.class); + intent.putExtra(AbstractSelectFriendAction.KEY_TYPE, AbstractSelectFriendAction.TYPE_WEAR); + intent.putExtra(WEAR_INFO, wearInfo); + context.startActivity(intent); + } + + @Override + public void init() { + type = getIntent().getIntExtra(AbstractSelectFriendAction.KEY_TYPE, AbstractSelectFriendAction.TYPE_CAR); + + if (type != AbstractSelectFriendAction.TYPE_CAR && type != AbstractSelectFriendAction.TYPE_WEAR) + finish(); + + carInfo = (CarInfo) getIntent().getSerializableExtra(CAR_INFO); + wearInfo = (HeadWearInfo) getIntent().getSerializableExtra(WEAR_INFO); + + initTitleBar(getString(R.string.title_select_friend)); + + mBinding.titleBar.addAction(new TitleBar.Action() { + @Override + public String getText() { + return null; + } + + @Override + public int getDrawable() { + return R.drawable.ic_send_search; + } + + @Override + public int getTextColor() { + return 0; + } + + @Override + public int getTextDrawableLeft() { + return 0; + } + + @Override + public void performAction(View view) { + switch (type) { + case AbstractSelectFriendAction.TYPE_CAR: + SearchActivity.start(DecorationSendActivity.this, carInfo); + break; + + case AbstractSelectFriendAction.TYPE_WEAR: + SearchActivity.start(DecorationSendActivity.this, wearInfo); + break; + + } + } + }); + + mBinding.viewpager.setOffscreenPageLimit(3); + mBinding.viewpager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager(), getFragment(), titles)); + + List tabInfoList = new ArrayList<>(2); + tabInfoList.add(new TabInfo(1, getString(R.string.tab_title_friends))); + tabInfoList.add(new TabInfo(2, getString(R.string.tab_title_attentions))); + tabInfoList.add(new TabInfo(3, getString(R.string.tab_title_fans))); + CommonNavigator commonNavigator = new CommonNavigator(this); + commonNavigator.setAdjustMode(true); + CarMagicIndicator indicator = new CarMagicIndicator(this, tabInfoList, 0); + indicator.setOnItemSelectListener(this); + commonNavigator.setAdapter(indicator); + mBinding.viewIndicator.setNavigator(commonNavigator); + ViewPagerHelper.bind(mBinding.viewIndicator, mBinding.viewpager); + } + + private List getFragment() { + List list = new ArrayList<>(); + list.add(DSFriendListFragment.newInstances()); + list.add(DSAttentionFragment.newInstance()); + list.add(DSFansListFragment.newInstanceForSelect()); + return list; + } + + @Override + public void onItemSelect(int position) { + mBinding.viewpager.setCurrentItem(position); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == SearchActivity.CODE_REQUEST_TO_SEARCH && resultCode == RESULT_OK) { + setResult(RESULT_OK, data); + finish(); + } + } + + public void showSureDialog(long targetUid, String nick) { + switch (type) { + case AbstractSelectFriendAction.TYPE_CAR: + if (carInfo != null) { + DecorationDialogHelper.Options options = new DecorationDialogHelper.Builder() + .setType(DecorationSaleType.SEND_CAR) + .setNick(nick) + .setDecoration(carInfo) + .setTargetUid(targetUid) + .create(); + DecorationDialogHelper helper = new DecorationDialogHelper(context, getDialogManager(), options); + helper.showBuyOrDonateDialog(); + } + break; + + case AbstractSelectFriendAction.TYPE_WEAR: + if (wearInfo != null) { + DecorationDialogHelper.Options options = new DecorationDialogHelper.Builder() + .setType(DecorationSaleType.SEND_HEAD_WEAR) + .setNick(nick) + .setDecoration(wearInfo) + .setTargetUid(targetUid) + .create(); + DecorationDialogHelper helper = new DecorationDialogHelper(context, getDialogManager(), options); + helper.showBuyOrDonateDialog(); + } else { + return; + } + break; + } + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/user/decorationsend/UserInfoSkillDecoration.kt b/app/src/main/java/com/chwl/app/ui/user/decorationsend/UserInfoSkillDecoration.kt new file mode 100644 index 0000000..1518dbd --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/decorationsend/UserInfoSkillDecoration.kt @@ -0,0 +1,29 @@ +package com.chwl.app.ui.user.decorationsend + +import android.content.Context +import android.graphics.Rect +import android.view.View +import androidx.recyclerview.widget.RecyclerView +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil + +class UserInfoSkillDecoration(context: Context, space: Int) : RecyclerView.ItemDecoration() { + private val spaceDp = UIUtil.dip2px(context, space.toDouble()) + override fun getItemOffsets( + outRect: Rect, + view: View, + parent: RecyclerView, + state: RecyclerView.State + ) { + super.getItemOffsets(outRect, view, parent, state) + val position = parent.getChildAdapterPosition(view) + val count = parent.adapter?.itemCount ?: 0 + when (position) { + 0 -> outRect.right = spaceDp / 2 + count - 1 -> outRect.left = spaceDp / 2 + else -> { + outRect.right = spaceDp / 2 + outRect.left = spaceDp / 2 + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/user/dialog/CpRelationChangeDialog.kt b/app/src/main/java/com/chwl/app/ui/user/dialog/CpRelationChangeDialog.kt new file mode 100644 index 0000000..e3253f8 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/dialog/CpRelationChangeDialog.kt @@ -0,0 +1,80 @@ +package com.chwl.app.ui.user.dialog + +import android.os.Bundle +import android.view.Gravity +import android.view.WindowManager +import com.chwl.app.R +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.databinding.DialogCpRelationChangeBinding +import com.chwl.core.contacts.MyConstant +import com.chwl.library.common.util.ClickUtils.click +import com.chwl.library.common.util.toColor +import com.chwl.library.widget.text.DrawableTextView +import com.example.lib_utils.ktx.getDrawable + +class CpRelationChangeDialog : BaseDialogFragment() { + + override var width = WindowManager.LayoutParams.MATCH_PARENT + override var height = WindowManager.LayoutParams.WRAP_CONTENT + override var dimAmount = 0f + override var gravity = Gravity.BOTTOM + + + val mViews = hashMapOf() + var mNowType = -1; + var mSelectType = -1 + + companion object{ + fun newInstance(type:Int): CpRelationChangeDialog{ + val args = Bundle() + args.putInt(MyConstant.type, type) + val fragment = CpRelationChangeDialog() + fragment.arguments = args + return fragment + } + } + + override fun init() { + + mViews.put(MyConstant.CP.relationType.CP, binding.bntCp) + mViews.put(MyConstant.CP.relationType.brother, binding.bntBrother) + mViews.put(MyConstant.CP.relationType.sister, binding.bntSister) + mViews.put(MyConstant.CP.relationType.friend, binding.bntParner) + + arguments?.getInt(MyConstant.type,-1)?.let { + setNow(it) + } + + + + mViews.forEach { (t, view) -> + view?.click { + setSelect(t) + } + } + + binding.btnNext.click { + mActionCallBack?.onAction(mSelectType,null) + } + } + + + private fun setNow(type: Int) { + mNowType = type + mViews?.get(type)?.setDrawable(R.drawable.ic_cp_list_item_now.getDrawable(), null, null, null) + } + + + private fun setSelect(type: Int) { + mViews.forEach { (t, view) -> + view?.setDrawable(null, null, R.drawable.transparent_draw.getDrawable(), null) + view?.changeStrikeColor("#f2f3f7".toColor()) + } + mViews?.get(type)?.setDrawable(null, null, R.drawable.ic_hall_member_checked.getDrawable(), null) + mViews?.get(type)?.changeStrikeColor("#FF8C03".toColor()) + binding.btnNext.isEnabled = type != mNowType + mSelectType = type + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/user/dialog/UserAreaDialog.kt b/app/src/main/java/com/chwl/app/ui/user/dialog/UserAreaDialog.kt new file mode 100644 index 0000000..1b2fa7d --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/dialog/UserAreaDialog.kt @@ -0,0 +1,101 @@ +package com.chwl.app.ui.user.dialog + +import android.os.Bundle +import android.view.Gravity +import android.view.WindowManager +import android.widget.ImageView +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.databinding.DialogUserAreaPickerBinding +import com.chwl.app.ui.user.adapter.ArrayWheelAdapter +import com.chwl.core.bean.response.ServiceResult +import com.chwl.core.user.bean.RegionInfoBean +import com.chwl.core.utils.net.RxHelper +import com.chwl.library.net.rxnet.RxNet +import com.google.gson.JsonElement +import io.reactivex.Single +import retrofit2.http.GET +import retrofit2.http.Query +import java.io.Serializable + + +/** + * author: wushaocheng + * time: 2022/2/17 + * desc: 用户地区 + */ +class UserAreaDialog : + BaseDialogFragment() { + + private var mOptionsItems: List? = null + + private var mArea: String? = null + + private var mAction: ((String) -> Unit)? = null + + companion object { + const val KEY_AREA = "key_area" + + @JvmStatic + fun newInstance(area: List): UserAreaDialog { + val userLabelDialog = UserAreaDialog() + val bundle = Bundle() + bundle.putSerializable(KEY_AREA, area as Serializable?) + userLabelDialog.arguments = bundle + return userLabelDialog + } + } + + override fun onStart() { + gravity = Gravity.BOTTOM + width = WindowManager.LayoutParams.MATCH_PARENT + super.onStart() + } + + override fun init() { + mOptionsItems = arguments?.getSerializable(KEY_AREA) as List? + mArea = mOptionsItems?.get(0) + initListener() + setWheelView() + } + + private fun initListener() { + binding?.tvCancel?.setOnClickListener { + dismissAllowingStateLoss() + } + binding?.tvSure?.setOnClickListener { + mArea?.let { area -> + dismissAllowingStateLoss() + mAction?.invoke(area) + } + } + } + + fun setAction(action: (String) -> Unit) { + mAction = action + } + + private fun setWheelView() { + mOptionsItems?.let { + + binding?.wheelView?.setCyclic(false) + binding?.wheelView?.adapter = ArrayWheelAdapter(it) + binding?.wheelView?.setOnItemSelectedListener { index -> mArea = it[index] } + } + } + + private fun getAreaList() : Single> { + return api.getRegionInfoList() + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()) + } + + private final val api = RxNet.create(Api::class.java); + interface Api{ + /** + * 地区列表 + */ + @GET("/regionInfo/list") + fun getRegionInfoList(): Single>> + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/user/event/LabelEvent.kt b/app/src/main/java/com/chwl/app/ui/user/event/LabelEvent.kt new file mode 100644 index 0000000..958b058 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/event/LabelEvent.kt @@ -0,0 +1,8 @@ +package com.chwl.app.ui.user.event + +import lombok.AllArgsConstructor +import lombok.Data + +@AllArgsConstructor +@Data +class LabelEvent(val label: String = "") \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/user/event/UserLabelEvent.kt b/app/src/main/java/com/chwl/app/ui/user/event/UserLabelEvent.kt new file mode 100644 index 0000000..343e400 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/event/UserLabelEvent.kt @@ -0,0 +1,8 @@ +package com.chwl.app.ui.user.event + +import lombok.AllArgsConstructor +import lombok.Data + +@AllArgsConstructor +@Data +class UserLabelEvent(val label: String = "") \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/user/fragment/LabelFragment.kt b/app/src/main/java/com/chwl/app/ui/user/fragment/LabelFragment.kt new file mode 100644 index 0000000..7b0f0a2 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/fragment/LabelFragment.kt @@ -0,0 +1,62 @@ +package com.chwl.app.ui.user.fragment + +import com.google.android.flexbox.FlexDirection +import com.google.android.flexbox.FlexWrap +import com.google.android.flexbox.FlexboxLayoutManager +import com.google.android.flexbox.JustifyContent +import com.chwl.app.base.BaseViewBindingFragment +import com.chwl.app.databinding.FragmentMyTagBinding +import com.chwl.app.ui.user.adapter.UserLabelAdapter +import com.chwl.app.ui.user.event.LabelEvent +import com.chwl.app.ui.user.event.UserLabelEvent +import com.chwl.core.user.bean.UserLabelItemInfo +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode + +/** + * author: wushaocheng + * time: 2022/2/16 + * desc: 我的标签 + */ +class LabelFragment : BaseViewBindingFragment() { + + companion object { + const val USER_TAG = "user_tag" + } + + private var labelList: List? = null + + private val mAdapter by lazy { UserLabelAdapter() } + + override fun init() { + EventBus.getDefault().register(this) + + labelList = arguments?.getSerializable(USER_TAG) as? ArrayList? + val flexBoxLayoutManager = FlexboxLayoutManager(context) + flexBoxLayoutManager.flexDirection = FlexDirection.ROW//主轴为水平方向,起点在左端 + flexBoxLayoutManager.flexWrap = FlexWrap.WRAP//按正常方向换行 + flexBoxLayoutManager.justifyContent = JustifyContent.FLEX_START//交叉轴的起点对齐 + binding.mRecyclerView.layoutManager = flexBoxLayoutManager + + binding.mRecyclerView.adapter = mAdapter + mAdapter.setNewData(labelList) + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onLabelEvent(event: LabelEvent) { + val list = mAdapter.data.map { it.label } + if(list.contains(event.label)){ + val pos = list.indexOf(event.label) + val bean = mAdapter.data[pos] + bean.picked = false + mAdapter.notifyItemChanged(pos) + } + } + + override fun onDestroyView() { + super.onDestroyView() + EventBus.getDefault().unregister(this) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/user/fragment/UserInfoDataFragment.kt b/app/src/main/java/com/chwl/app/ui/user/fragment/UserInfoDataFragment.kt new file mode 100644 index 0000000..c870325 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/fragment/UserInfoDataFragment.kt @@ -0,0 +1,229 @@ +package com.chwl.app.ui.user.fragment + +import android.content.Intent +import android.view.View +import android.widget.TextView +import androidx.core.view.isVisible +import androidx.fragment.app.activityViewModels +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingFragment +import com.chwl.app.databinding.UserInfoDataFragmentBinding +import com.chwl.app.support.FragmentVisibleStateHelper +import com.chwl.app.ui.game_team.invite.GameTeamInviteDialog +import com.chwl.app.ui.user.activity.ShowPhotoActivity +import com.chwl.app.ui.user.activity.UserInfoModifyActivity +import com.chwl.app.ui.user.activity.UserModifyPhotosActivity +import com.chwl.app.ui.user.adapter.UserInfoAlbumAdapter +import com.chwl.app.ui.user.adapter.UserInfoGameTeamAdapter +import com.chwl.app.ui.user.adapter.UserInfoGiftAdapter +import com.chwl.app.ui.user.adapter.UserInfoIndicatorAdapter +import com.chwl.app.ui.user.adapter.UserInfoMedalAdapter +import com.chwl.app.ui.user.viewmodel.UserInfoViewModel +import com.chwl.app.ui.utils.load +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.CommonNavigator +import com.chwl.app.ui.widget.recyclerview.decoration.SpacingDecoration +import com.chwl.core.game_team.UserGameTeamInfo +import com.chwl.core.user.UserModel +import com.chwl.core.user.bean.UserPhoto +import com.chwl.library.utils.ResUtil +import com.example.lib_utils.ktx.getString + +class UserInfoDataFragment : BaseViewBindingFragment() { + + private val viewModel: UserInfoViewModel by activityViewModels() + + override fun init() { + initGameTeam() + initAlbum() + initOther() + initMedal() + initGift() + setGuild() + FragmentVisibleStateHelper(this).apply { + this.start { + onVisibleChanged(it, isFirstVisible) + } + } + } + + private fun initOther() { + val tagList = + arrayListOf(ResUtil.getString(R.string.medal), ResUtil.getString(R.string.gift_action)) + val commonNavigator = CommonNavigator(context) + commonNavigator.setTitleWrapContent(false) + val magicIndicatorAdapter = UserInfoIndicatorAdapter(context, tagList) + magicIndicatorAdapter.textSize = 16 + magicIndicatorAdapter.setOnItemSelectListener { position: Int, view: TextView? -> + binding.magicIndicator.onPageSelected(position) + onOtherTabChange(view?.text?.toString() ?: "") + } + commonNavigator.adapter = magicIndicatorAdapter + binding.magicIndicator.setNavigator(commonNavigator) + } + + private fun onOtherTabChange(str: String) { + when (str) { + ResUtil.getString(R.string.medal) -> { + binding.layoutGift.isVisible = false + binding.layoutMedal.isVisible = true + } + + ResUtil.getString(R.string.gift_action) -> { + binding.layoutGift.isVisible = true + binding.layoutMedal.isVisible = false + + } + + else -> {} + } + } + + private fun initGameTeam() { + val adapter = UserInfoGameTeamAdapter(viewModel.isMe) + binding.recyclerViewGameTeam.addItemDecoration( + SpacingDecoration( + 0, + resources.getDimensionPixelOffset(R.dimen.dp_10), + false + ) + ) + binding.recyclerViewGameTeam.adapter = adapter + adapter.setOnItemChildClickListener { adapter, view, position -> + activity?.let { + val item = (adapter.getItem(position) as? UserGameTeamInfo) + ?: return@setOnItemChildClickListener + GameTeamInviteDialog.newInstance(item).safeShow(it.supportFragmentManager, it) + } + } + viewModel.userInfoDetailData.observe(this) { + adapter.setNewData(it.userGamePartner ?: emptyList()) + binding.layoutGameTeam.isVisible = !it.userGamePartner.isNullOrEmpty() + } + } + + private fun initAlbum() { + val albumAdapter = UserInfoAlbumAdapter() + binding.ivAlbumMore.isVisible = viewModel.isMe + binding.recyclerViewAlbum.adapter = albumAdapter + binding.layoutAlbum.setOnClickListener { + if (viewModel.isMe) { + UserModifyPhotosActivity.startForResult( + requireActivity(), + viewModel.userId, + UserInfoModifyActivity.Method.PHOTO + ) + } + } + albumAdapter.setOnItemClickListener { adapter, view, position -> + val list = albumAdapter.data.map { + UserPhoto().apply { + this.photoUrl = it.photoUrl + } + } + showPhotoPreview(ArrayList(list), position) + } + viewModel.userInfoData.observe(this) { + binding.tvAlbumCount.text = "(${it.privatePhoto?.size ?: 0})" + binding.tvAlbumStatus.isVisible = it.privatePhoto.isNullOrEmpty() + albumAdapter.setNewData(it.privatePhoto) + } + } + + private fun initMedal() { + val medalAdapter = UserInfoMedalAdapter() + binding.recyclerViewMedal.adapter = medalAdapter + viewModel.userInfoDetailData.observe(this) { + val list = it.medals?.userMedals + if (medalAdapter.itemCount > 0) return@observe + medalAdapter.setNewData(list) + binding.tvMedalStatus.isVisible = list.isNullOrEmpty() + } + } + + var isMiniMode = true + private fun initGift() { + val giftAdapter = UserInfoGiftAdapter() + binding.ivGiftMore.setOnClickListener { + isMiniMode = !isMiniMode + loadListData(giftAdapter, 4, isMiniMode, binding.ivGiftMore) + binding.ivGiftMore.animate().rotationBy(180f).start() + } + binding.recyclerViewGift.adapter = giftAdapter + viewModel.giftListLiveData.observe(this) { + loadListData(giftAdapter, 4, isMiniMode, binding.ivGiftMore) + } + viewModel.luckyGiftListLiveData.observe(this) { + loadListData(giftAdapter, 4, isMiniMode, binding.ivGiftMore) + } + viewModel.loadUserInfoGiftWallData() + } + + + private fun setGuild() { + UserModel.get().getUserInfoDetailCache(viewModel.userId).compose(bindToLifecycle()) + .doOnSuccess { + it?.data?.guildInfo?.let { + + //guildName + binding.guildName.text = "${R.string.Guild_Nick.getString()}:${it.guildName}" + //guildId + binding.guildId.text = "${R.string.Guild_ID.getString()}:${it.guildId}" + //guildAgentId + binding.guildAgentId.text = "${R.string.Agent_ID.getString()}:${it.erbanNo}" + + //guildImg + binding.guildImg.load(it.avatar) + + binding.guildLayout.isVisible = true + } + }.subscribe() + } + + private fun loadListData( + adapter: UserInfoGiftAdapter, + miniCount: Int, + miniOrFull: Boolean, + moreView: View + ) { + if (viewModel.luckyGiftIsRead && viewModel.giftIsRead) { + if (!viewModel.giftWallIsRead) { + val gift = viewModel.giftListLiveData.value ?: emptyList() + val luckyGift = viewModel.luckyGiftListLiveData.value ?: emptyList() + + viewModel.userInfoGiftWallData.addAll(gift) + viewModel.userInfoGiftWallData.addAll(luckyGift) + + viewModel.userInfoGiftWallData.sortBy { it.reciveCount } + + viewModel.giftWallIsRead = true + } + } else { + return + } + + val finalList = if (miniOrFull) { + viewModel.userInfoGiftWallData.take(miniCount) + } else { + viewModel.userInfoGiftWallData + } + adapter.setNewData(finalList) + moreView.isVisible = viewModel.userInfoGiftWallData.size > miniCount + binding.tvGiftStatus.isVisible = finalList.isEmpty() + } + + private fun showPhotoPreview(list: ArrayList, position: Int) { + val intent = Intent(context, ShowPhotoActivity::class.java) + intent.putExtra("position", position) + intent.putExtra("photoList", list) + context?.startActivity(intent) + } + + private fun onVisibleChanged(isVisible: Boolean, isFirstVisible: Boolean) { + if (isVisible && !isFirstVisible) { + if (viewModel.userInfoGiftWallData.isEmpty()) { + viewModel.requestGiftList() + viewModel.requestLuckyGiftList() + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/user/fragment/UserInfoDynamicFragment.kt b/app/src/main/java/com/chwl/app/ui/user/fragment/UserInfoDynamicFragment.kt new file mode 100644 index 0000000..18628b2 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/fragment/UserInfoDynamicFragment.kt @@ -0,0 +1,141 @@ +package com.chwl.app.ui.user.fragment + +import android.view.View +import androidx.fragment.app.activityViewModels +import com.chwl.app.R +import com.chwl.app.UIHelper +import com.chwl.app.avroom.ButtonItemFactory +import com.chwl.app.base.BaseViewBindingFragment +import com.chwl.app.common.widget.dialog.DialogManager +import com.chwl.app.databinding.UserInfoDynamicFragmentBinding +import com.chwl.app.ui.user.adapter.UserInfoDynamicAdapter +import com.chwl.app.ui.user.viewmodel.UserInfoViewModel +import com.chwl.app.ui.widget.ButtonItem +import com.chwl.core.XConstants +import com.chwl.core.auth.AuthModel +import com.chwl.core.community.bean.WorldDynamicBean +import com.chwl.core.community.dynamic.DynamicModel +import com.chwl.core.user.UserModel +import com.chwl.core.utils.net.BeanObserver +import com.chwl.core.utils.net.DontWarnObserver +import com.chwl.library.utils.ResUtil +import com.trello.rxlifecycle3.android.FragmentEvent +import java.util.ArrayList + +class UserInfoDynamicFragment : BaseViewBindingFragment() { + + private val viewModel: UserInfoViewModel by activityViewModels() + + private var adapter: UserInfoDynamicAdapter? = null + override fun init() { + initView() + viewModel.userInfoDetailData.observe(this) { + updateList(it.dynamicInfo) + } + } + + private fun initView() { + adapter = UserInfoDynamicAdapter(requireContext()) + adapter?.isUserInfo = true + adapter?.setEnableLoadMore(false) + adapter?.emptyView = layoutInflater.inflate(R.layout.user_info_tab_empty, null) + binding.recyclerView.adapter = adapter + adapter?.setOnItemChildClickListener { adapter, view: View, pos: Int -> + val bean = + adapter?.getItem(pos) as? WorldDynamicBean ?: return@setOnItemChildClickListener + if (view.id == R.id.iv_more) { + val list: MutableList = ArrayList() + if (!UserModel.get().isMyseft(bean.uid)) { + val item = ButtonItem( + getString(R.string.me_shield_dynamic) + ) { + UserModel.get().addReport(bean.dynamicId, 0) + .subscribe(object : BeanObserver() { + override fun onErrorMsg(error: String) { + dialogManager.dismissDialog() + toast(error) + } + + override fun onSuccess(s: String) { + dialogManager.dismissDialog() + toast(ResUtil.getString(R.string.me_shield_success)) + val size = adapter?.data?.size ?: 0 + if (pos < size) { + if (bean == adapter?.getItem(pos)) { + adapter?.remove(pos) + } + } + } + }) + } + list.add(item) + } + if (!UserModel.get().isMyseft(bean.uid)) { + val blackListItem = ButtonItemFactory.createAddToBlackListItem( + dialogManager, bean.uid.toString() + ) + list.add(blackListItem) + } + if (!UserModel.get().isMyseft(bean.uid)) { + val item = ButtonItem( + getString(R.string.me_report_dynamic) + ) { + UIHelper.showReportPage( + mContext, bean.uid, + XConstants.REPORT_TYPE_DYNAMIC_SQUARE + ) + } + list.add(item) + } + if (UserModel.get().isMyseft(bean.uid) || + isThisWorldOwner(bean) + ) { + val item = ButtonItem( + getString(R.string.me_delete) + ) { deleteDynamic(pos, this.adapter) } + list.add(item) + } + dialogManager.showCommonPopupDialog(list, getString(R.string.cancel)) + } else if (view.id == R.id.ll_share) { +// ShareDynamicHelper(activity).share(bean) + } + } + } + + private fun deleteDynamic(pos: Int, adapter: UserInfoDynamicAdapter?) { + dialogManager.showOkCancelWithTitleDialog(getString(R.string.me_cannot_be_restored), + DialogManager.OkCancelDialogListener { + val bean = adapter?.getItem(pos) ?: return@OkCancelDialogListener + DynamicModel.get().delete(bean.worldId, bean.dynamicId) + .compose(bindUntilEvent(FragmentEvent.DESTROY_VIEW)) + .doOnSubscribe { dialogManager.showProgressDialog(mContext) } + .subscribe(object : DontWarnObserver() { + override fun accept(s: String?, error: String?) { + super.accept(s, error) + dialogManager.dismissDialog() + if (error != null) { + toast(error) + } else { + toast(getString(R.string.me_successfully_delete)) + if (pos < adapter.data.size) { + if (bean == adapter.getItem(pos)) { + adapter.remove(pos) + } + } + } + } + }) + }) + } + + /** + * 判断自己是不是该世界的创始人 + */ + private fun isThisWorldOwner(bean: WorldDynamicBean?): Boolean { + return bean != null && bean.worldUid == AuthModel.get().currentUid + } + + private fun updateList(list: List?) { + adapter?.setNewData(list) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/user/fragment/UserInfoGiftFragment.java b/app/src/main/java/com/chwl/app/ui/user/fragment/UserInfoGiftFragment.java new file mode 100644 index 0000000..21e2fbe --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/fragment/UserInfoGiftFragment.java @@ -0,0 +1,203 @@ +package com.chwl.app.ui.user.fragment; + +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.Nullable; +import androidx.lifecycle.Observer; +import androidx.recyclerview.widget.GridLayoutManager; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.trello.rxlifecycle3.android.FragmentEvent; +import com.chwl.app.R; +import com.chwl.app.base.BaseBindingFragment; +import com.chwl.app.databinding.FragmentUserInfoGiftBinding; +import com.chwl.app.ui.user.adapter.UserGiftAdapter; +import com.chwl.core.bean.UserInfoItem; +import com.chwl.core.user.UserInfoUiMgr; +import com.chwl.core.user.UserModel; +import com.chwl.core.user.bean.GiftWallInfo; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.core.user.event.LoginUserInfoUpdateEvent; +import com.chwl.core.utils.net.BeanObserver; +import com.chwl.library.annatation.ActLayoutRes; +import com.chwl.library.utils.ListUtils; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.ArrayList; +import java.util.List; + +@ActLayoutRes(R.layout.fragment_user_info_gift) +public class UserInfoGiftFragment extends BaseBindingFragment { + + private UserInfo userInfo; + private long userId = 0; + private long time; + + private List userInfoItems = new ArrayList<>(); + private UserGiftAdapter userGiftAdapter; + private Observer mObserver; + private Observer mUidObserver; + private boolean isDetails = false; + + public static UserInfoGiftFragment newInstance(int giftType, boolean isDetails) { + UserInfoGiftFragment userInfoGiftFragment = new UserInfoGiftFragment(); + Bundle args = new Bundle(); + args.putInt("giftType", giftType); + args.putBoolean("isDetails", isDetails); + userInfoGiftFragment.setArguments(args); + return userInfoGiftFragment; + } + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + mUidObserver = new Observer() { + @Override + public void onChanged(@Nullable Long info) { + if (info != null) { + userId = info; + } + } + }; + + mObserver = new Observer() { + @Override + public void onChanged(@Nullable UserInfo info) { + if (info != null && info.getUid() == userId) { + Log.i("UserInfoGiftFragment", "info not null"); + userInfo = info; + initData(userInfo); + } + + } + }; + + UserInfoUiMgr.get().registerUid(this, mUidObserver); + UserInfoUiMgr.get().register(this, mObserver); + } + + @Override + public void initiate() { + isDetails = requireArguments().getBoolean("isDetails", false); + mBinding.rvGift.setLayoutManager(new GridLayoutManager(mContext, 12)); + userGiftAdapter = new UserGiftAdapter(mContext, userInfoItems, isDetails); + userGiftAdapter.bindToRecyclerView(mBinding.rvGift); + userGiftAdapter.setSpanSizeLookup(new BaseQuickAdapter.SpanSizeLookup() { + @Override + public int getSpanSize(GridLayoutManager gridLayoutManager, int position) { + List list = userGiftAdapter.getData(); + if (ListUtils.isListEmpty(list)) + return 12; + UserInfoItem userInfoItem = list.get(position); + int type = userInfoItem.getItemType(); + if (type == UserInfoItem.TYPE_DIV || type == UserInfoItem.TYPE_GIFT_EMPTY) { + return 12; + } else if (type == UserInfoItem.TYPE_GIFT_ITEM_TOP) { + return 4; + } else + return 3; + } + }); + + Long uid = UserInfoUiMgr.get().getUid(); + if (uid != null) { + userId = uid; + } + userInfo = UserInfoUiMgr.get().getValue(); + initData(userInfo); + } + + private void initData(UserInfo userInfo) { + if (null != userInfo) { + Log.i("UserInfoGiftFragment", "not null"); + if (System.currentTimeMillis() - time < 2000) { + return; + } + time = System.currentTimeMillis(); + UserModel.get().requestUserGiftWall(userId, requireArguments().getInt("giftType"), 2) + .compose(bindUntilEvent(FragmentEvent.DESTROY_VIEW)) + .subscribe(new BeanObserver>() { + @Override + public void onErrorMsg(String error) { + Log.i("UserInfoGiftFragment:", error); +// onRequestGiftWallFail(error); + } + + @Override + public void onSuccess(List giftWallInfos) { + onRequestGiftWall(giftWallInfos); + } + }); + } else { + + Log.i("UserInfoGiftFragment", "null"); + } + } + + + private void onRequestGiftWall(List giftWallInfoList) { + if (userInfo == null) return; + + userInfoItems.clear(); + // 刷新数据 + if (ListUtils.isListEmpty(giftWallInfoList)) { + userInfoItems.add(new UserInfoItem<>(UserInfoItem.TYPE_GIFT_EMPTY)); + } else { + UserInfoItem userInfoItem; + for (int i = 0; i < giftWallInfoList.size(); i++) { + if (i < 3) { + userInfoItem = new UserInfoItem<>(UserInfoItem.TYPE_GIFT_ITEM_TOP, giftWallInfoList.get(i)); + } else { + userInfoItem = new UserInfoItem<>(UserInfoItem.TYPE_GIFT_ITEM, giftWallInfoList.get(i)); + } + userInfoItems.add(userInfoItem); + //非礼物详情页主需要12个就够了 + if (!isDetails && i == 10) { + break; + } + } + } + + userGiftAdapter.setNewData(userInfoItems); + + } + + private void onRequestGiftWallFail(String msg) { + toast(msg); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onLoginUserInfoUpdateEvent(LoginUserInfoUpdateEvent event) { + userInfo = UserModel.get().getCacheLoginUserInfo(); + initData(userInfo); + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View tmp = super.onCreateView(inflater, container, savedInstanceState); + EventBus.getDefault().register(this); + return tmp; + } + + @Override + public void onDestroyView() { + EventBus.getDefault().unregister(this); + if (mObserver != null) { + UserInfoUiMgr.get().unregister(mObserver); + } + + if (mUidObserver != null) { + UserInfoUiMgr.get().unregisterUid(mUidObserver); + } + super.onDestroyView(); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/user/viewmodel/UserInfoViewModel.kt b/app/src/main/java/com/chwl/app/ui/user/viewmodel/UserInfoViewModel.kt new file mode 100644 index 0000000..9c2cc57 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/user/viewmodel/UserInfoViewModel.kt @@ -0,0 +1,148 @@ +package com.chwl.app.ui.user.viewmodel + +import android.annotation.SuppressLint +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import com.chwl.app.base.BaseViewModel +import com.chwl.app.module_hall.HallDataManager +import com.chwl.core.auth.AuthModel +import com.chwl.core.bean.response.ServiceResult +import com.chwl.core.module_hall.hall.bean.UserClanInfo +import com.chwl.core.user.UserModel +import com.chwl.core.user.bean.GiftWallInfo +import com.chwl.core.user.bean.UserCPListBean +import com.chwl.core.user.bean.UserDetailInfo +import com.chwl.core.user.bean.UserInfo +import com.chwl.core.utils.extension.toast +import com.chwl.core.utils.net.BeanObserver +import com.chwl.core.utils.net.RxHelper +import com.chwl.library.net.rxnet.RxNet +import io.reactivex.Single +import io.reactivex.disposables.Disposable +import retrofit2.http.GET +import retrofit2.http.Query + +class UserInfoViewModel : BaseViewModel() { + var userId: Long = 0 + + var mRoomUid: Long = 0 + + val isMe get() = userId == AuthModel.get().currentUid + + private val _userInfoData = MutableLiveData() + val userInfoData: LiveData = _userInfoData + + private val _userInfoDetailData = MutableLiveData() + private val _userInfoDetailError = MutableLiveData() + val userInfoDetailData: LiveData = _userInfoDetailData + val userInfoDetailError: LiveData = _userInfoDetailError + + val userClanData = MutableLiveData() + + val giftListLiveData = MutableLiveData>() + val luckyGiftListLiveData = MutableLiveData>() + val userInfoGiftWallData = mutableListOf() + var luckyGiftIsRead = false + var giftIsRead = false + var giftWallIsRead = false + + + fun getUserInfo() { + UserModel.get().getUserInfoFromServer(userId) + .subscribe(object : BeanObserver() { + override fun onErrorMsg(error: String) { + error.toast() + _userInfoDetailError.postValue(error) + } + + override fun onSuccess(info: UserInfo) { + _userInfoData.postValue(info) + } + + override fun onSubscribe(d: Disposable) { + addDisposable(d) + } + }) + } + + fun getUserInfoDetail() { + UserModel.get().getUserInfoDetail(userId) + .subscribe(object : BeanObserver() { + override fun onErrorMsg(error: String) { + error.toast() + _userInfoDetailError.postValue(error) + } + + override fun onSuccess(info: UserDetailInfo) { + info.let { + mRoomUid = it.data.roomUid + _userInfoDetailData.postValue(it.data) + } + } + + override fun onSubscribe(d: Disposable) { + addDisposable(d) + } + }) + } + + @SuppressLint("CheckResult") + fun getUserHallAndClan() { + val subscribe = HallDataManager.get().requestUserClanInfo(userId) + .toFlowable() + .subscribe( + { data -> data?.let { userClanData.value = data } }, + { th -> + th.printStackTrace() + th.message?.toast() + } + ) + addDisposable(subscribe) + } + + fun requestGiftList() { + addDisposable(UserModel.get().requestUserGiftWall(userId, 1, 2) + .doOnError { + giftIsRead=true + } + .subscribe { it -> + giftIsRead=true + giftListLiveData.postValue(it) + }) + } + + fun requestLuckyGiftList() { + addDisposable(UserModel.get().requestUserGiftWall(userId, 2, 2) + .doOnError { + luckyGiftIsRead=true + } + .subscribe { it -> + luckyGiftListLiveData.postValue(it) + luckyGiftIsRead=true + }) + } + + fun loadUserInfoGiftWallData(){ + giftIsRead = false + luckyGiftIsRead = false + userInfoGiftWallData.clear() + requestGiftList() + requestLuckyGiftList() + } + + + fun getNameTypeTopList(uid: Long): Single> { + return api.nameTypeTopList(uid) + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()) + } + + + private val api: Api = RxNet.create(Api::class.java) + private interface Api { + @GET("/user/cp/nameTypeTopList") + fun nameTypeTopList( + @Query("uid") uid: Long + ): Single>> + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/utils/CpUtils.kt b/app/src/main/java/com/chwl/app/ui/utils/CpUtils.kt new file mode 100644 index 0000000..6db9816 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/utils/CpUtils.kt @@ -0,0 +1,223 @@ +package com.chwl.app.ui.utils + +import android.graphics.Bitmap +import android.view.View +import com.bumptech.glide.load.DataSource +import com.bumptech.glide.load.engine.GlideException +import com.bumptech.glide.request.RequestFutureTarget +import com.bumptech.glide.request.RequestListener +import com.bumptech.glide.request.target.Target +import com.chwl.app.R +import com.chwl.app.application.App +import com.chwl.core.contacts.MyConstant +import com.chwl.core.utils.LogUtils +import com.chwl.library.utils.ResUtil +import com.example.lib_utils.ktx.getString +import com.netease.nim.uikit.support.glide.GlideApp +import com.tencent.qgame.animplayer.AnimView +import com.tencent.qgame.animplayer.inter.IFetchResource +import com.tencent.qgame.animplayer.mix.Resource + +object CpUtils { + + fun getHeadSvga(level: Int) : String { + return "svga/cp_list_head_$level.svga" + } + + fun getUserInfoAnim(level: Int) : String? { + if (level < 3) return null + return "mp4/cp_userinfo_anim_$level.mp4" + } + + + var flags = arrayListOf( + R.drawable.ic_user_info_cp_avatar_flag_0, + R.drawable.ic_user_info_cp_avatar_flag_1, + R.drawable.ic_user_info_cp_avatar_flag_2, + R.drawable.ic_user_info_cp_avatar_flag_3, + R.drawable.ic_user_info_cp_avatar_flag_4, + R.drawable.ic_user_info_cp_avatar_flag_5, + ) + var levels = arrayListOf( + R.drawable.ic_cp_list_level_0, + R.drawable.ic_cp_list_level_1, + R.drawable.ic_cp_list_level_2, + R.drawable.ic_cp_list_level_3, + R.drawable.ic_cp_list_level_4, + R.drawable.ic_cp_list_level_5, + ) + + var levelBgs = arrayListOf( + R.drawable.transparent_draw, + R.drawable.ic_cp_level_up_bg_1, + R.drawable.ic_cp_level_up_bg_2, + R.drawable.ic_cp_level_up_bg_3, + R.drawable.ic_cp_level_up_bg_4, + R.drawable.ic_cp_level_up_bg_5 + ) + + var cpLevelUpStr = arrayListOf( + R.string.Sweet_Duo, + R.string.Dynamic_Duo, + R.string.Ldeal_Duo, + R.string.Dream_Duo, + R.string.Perfect_Duo, + R.string.Divine_Duo + ) + + var cpUserInfoCardBgs = mapOf( + MyConstant.CP.relationType.CP to R.drawable.ic_user_info_cp_bg_1, + MyConstant.CP.relationType.brother to R.drawable.ic_user_info_cp_bg_2, + MyConstant.CP.relationType.sister to R.drawable.ic_user_info_cp_bg_3, + MyConstant.CP.relationType.friend to R.drawable.ic_user_info_cp_bg_4, + ) + + var cpListCardBgs = mapOf( + MyConstant.CP.relationType.CP to R.drawable.ic_cp_list_item_bg_1, + MyConstant.CP.relationType.brother to R.drawable.ic_cp_list_item_bg_2, + MyConstant.CP.relationType.sister to R.drawable.ic_cp_list_item_bg_3, + MyConstant.CP.relationType.friend to R.drawable.ic_cp_list_item_bg_4, + ) + + var cpListCardProgressDrawables = mapOf( + MyConstant.CP.relationType.CP to R.drawable.bar_cp_progress_1, + MyConstant.CP.relationType.brother to R.drawable.bar_cp_progress_2, + MyConstant.CP.relationType.sister to R.drawable.bar_cp_progress_3, + MyConstant.CP.relationType.friend to R.drawable.bar_cp_progress_4, + ) + + var cpRelationalNames = mapOf( + MyConstant.CP.relationType.CP to R.string.v26_cp, + MyConstant.CP.relationType.brother to R.string.v26_Brother, + MyConstant.CP.relationType.sister to R.string.v26_Sister, + MyConstant.CP.relationType.friend to R.string.v26_Parner, + ) + + fun getListCardProgressDrawables(type: Int?) : Int{ + if (type == null) { + return R.drawable.bar_cp_progress_1 + } else { + return cpListCardProgressDrawables[type] ?:R.drawable.bar_cp_progress_1 + } + } + fun getCpListCardBg(type: Int?) : Int{ + if (type == null) { + return R.drawable.ic_user_info_cp_bg_1 + } else { + return cpListCardBgs[type] ?:R.drawable.ic_user_info_cp_bg_1 + } + } + fun getCpRelationalNames(type: Int?) : String{ + if (type == null) { + return R.string.v26_cp.getString() + } else { + return cpRelationalNames[type]?.getString() ?:R.string.v26_cp.getString() + } + } + fun getCpUserInfoCardBg(type: Int?) : Int{ + if (type == null) { + return R.drawable.ic_user_info_cp_bg_1 + } else { + return cpUserInfoCardBgs[type] ?:R.drawable.ic_user_info_cp_bg_1 + } + } + + fun getFlag(level: Int) : Int{ + return flags.getOrNull(level)?:R.drawable.ic_user_info_cp_avatar_flag_0 + } + + fun getLevelImg(level: Int) : Int{ + return levels.getOrNull(level)?:R.drawable.ic_cp_list_level_0 + } + + fun getCpLevelUpTextBg(level: Int) : Int{ + return levelBgs.getOrNull(level)?:R.drawable.ic_cp_level_up_bg_1 + } + + fun getCpLevelUpStr(level: Int) : String{ + return ResUtil.getString(cpLevelUpStr.getOrNull(level)?:R.string.Sweet_Duo) + } + + fun downLoadAvatar(url:String?, onResourceReady:(resource: Bitmap?)->Unit) { + if (url.isNullOrEmpty()) return + try { + val futureTarget = RequestFutureTarget(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) + GlideApp.with(App.instance()) + .asBitmap() + .circleCrop() + .load(url) + .addListener(object : RequestListener { + override fun onLoadFailed(e: GlideException?, model: Any?, target: Target?, isFirstResource: Boolean): Boolean { + onResourceReady(null) + return true + } + + override fun onResourceReady(resource: Bitmap?, model: Any?, target: Target?, dataSource: DataSource?, isFirstResource: Boolean): Boolean { + onResourceReady(resource) + return true + } + }) + .into(futureTarget) + .get() + } catch (e: Exception) { + + } + } + + fun loadVap(animView: AnimView, url :String?, imgUrlMap: HashMap?=null , textMap: HashMap?=null) { + if (url == null) return + animView.visibility = View.VISIBLE + var index = 0 + val bitmapMap = hashMapOf() + + if (!imgUrlMap.isNullOrEmpty()){ + imgUrlMap.keys.forEach { key -> + downLoadAvatar(imgUrlMap[key]) { resource -> + index++ + bitmapMap[key] = resource + if (index == imgUrlMap.keys.size){ + animView.setFetchResource(object : IFetchResource { + override fun fetchImage(resource: Resource, result: (Bitmap?) -> Unit) { + if (bitmapMap.isEmpty()) { + result(null) + } else { + var bitmap : Bitmap?=null + bitmapMap.keys.forEach { + if (resource.tag == it){ + bitmap = bitmapMap[it] + } + } + result(bitmap) + } + } + + override fun fetchText(resource: Resource, result: (String?) -> Unit) { + if (textMap.isNullOrEmpty()) { + result(null) + } else { + var text = "" + textMap.keys.forEach { + if (resource.tag == it){ + text = textMap[it].toString() + } + } + result(text) + } + } + + override fun releaseResource(resources: List) { + resources?.forEach { + it?.bitmap?.recycle() + } + } + }) + LogUtils.d(" animViewSetAnimListener startPlay url = $url") + animView.startPlay(animView.context.assets, url) + } + } + } + } + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/utils/DesignUtils.java b/app/src/main/java/com/chwl/app/ui/utils/DesignUtils.java new file mode 100644 index 0000000..cf25894 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/utils/DesignUtils.java @@ -0,0 +1,89 @@ +package com.chwl.app.ui.utils; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.app.Activity; +import android.os.Build; +import android.transition.Explode; +import android.transition.Fade; +import android.transition.Slide; +import android.view.Gravity; +import android.view.View; +import android.view.ViewAnimationUtils; + +/** + * Created by zhouxiangfeng on 2017/4/18. + */ + +public class DesignUtils { + + /** + * 显示控件 + * @param myView + */ + private void show(final View myView) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + // get the center for the clipping circle + int cx = (myView.getLeft() + myView.getRight()) / 2; + int cy = (myView.getTop() + myView.getBottom()) / 2; + // get the final radius for the clipping circle + int finalRadius = Math.max(myView.getWidth(), myView.getHeight()); + // create the animator for this view (the start radius is zero) + Animator anim = ViewAnimationUtils.createCircularReveal(myView, cx, cy, 0, finalRadius); + // make the view visible and start the animation + myView.setVisibility(View.VISIBLE); + anim.start(); + } else { + myView.setVisibility(View.VISIBLE); + } + } + + /** + * 隐藏控件 + * @param myView + */ + private void hide(final View myView) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + // get the center for the clipping circle + int cx = (myView.getLeft() + myView.getRight()) / 2; + int cy = (myView.getTop() + myView.getBottom()) / 2; + // get the initial radius for the clipping circle + int initialRadius = myView.getWidth(); + // create the animation (the final radius is zero) + Animator anim = ViewAnimationUtils.createCircularReveal(myView, cx, cy, initialRadius, 0); + // make the view invisible when the animation is done + anim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + myView.setVisibility(View.INVISIBLE); + } + }); + anim.start(); + } else { + myView.setVisibility(View.INVISIBLE); + } + } + + private void showAnim(Activity act, int type) { + if(Build.VERSION.SDK_INT >= 21){ + switch (type) { + case 1: + Explode explode = new Explode(); + explode.setDuration(300L); + act.getWindow().setEnterTransition(explode); + break; + case 2: + Slide slide = new Slide(Gravity.RIGHT); + slide.setDuration(300L); + act.getWindow().setEnterTransition(slide); + break; + case 3: + Fade fade = new Fade(); + fade.setDuration(300L); + act.getWindow().setEnterTransition(fade); + break; + } + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/utils/GameUtil.kt b/app/src/main/java/com/chwl/app/ui/utils/GameUtil.kt new file mode 100644 index 0000000..a08efd6 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/utils/GameUtil.kt @@ -0,0 +1,46 @@ +package com.chwl.app.ui.utils + +import com.chwl.app.BuildConfig +import com.chwl.app.R +import com.chwl.core.room.bean.RoomIcon +import com.chwl.core.room.game.bean.BaiShunGameConfig +import com.chwl.library.utils.SingleToastUtil +import com.google.gson.Gson + +object GameUtil { + + + fun findGame(gameId:Long,games:List): RoomIcon? { + var data : RoomIcon? = null + games?.forEachIndexed { index, roomIcon -> + if (gameId == roomIcon.id) { + data = roomIcon + } + } + return data + } + + + fun startGame(data : RoomIcon, openGame: (url:String,config:BaiShunGameConfig)->Unit) { + try { + val url = data.skipContent + val ruleValue = Gson().fromJson( + data.ruleValue, + RoomIcon.RuleValueBean::class.java + ) + val config = Gson().fromJson( + ruleValue.RESERVE, + BaiShunGameConfig::class.java + ) + if (config != null && url != null) { + config.reloadDynamicParams() + config.showType = data.showType + openGame(url, config) + } else { + SingleToastUtil.showToast(R.string.manager_trtc_trtcengineadapter_042) + } + } catch (e: Exception) { + e.printStackTrace() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/utils/GlideCacheUtil.java b/app/src/main/java/com/chwl/app/ui/utils/GlideCacheUtil.java new file mode 100644 index 0000000..222e3a4 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/utils/GlideCacheUtil.java @@ -0,0 +1,175 @@ +package com.chwl.app.ui.utils; + +import android.content.Context; +import android.os.Looper; +import android.text.TextUtils; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.load.engine.cache.ExternalCacheDiskCacheFactory; +import com.bumptech.glide.load.engine.cache.InternalCacheDiskCacheFactory; + +import java.io.File; +import java.math.BigDecimal; + +/** + * Glide缓存工具类 + * Created by KathLine on 2017/4/27. + */ + +public class GlideCacheUtil { + private static GlideCacheUtil inst; + + public static GlideCacheUtil getInstance() { + if (inst == null) { + inst = new GlideCacheUtil(); + } + return inst; + } + + /** + * 清除图片磁盘缓存 + */ + public void clearImageDiskCache(final Context context) { + try { + if (Looper.myLooper() == Looper.getMainLooper()) { + new Thread(new Runnable() { + @Override + public void run() { + Glide.get(context).clearDiskCache(); + } + }).start(); + } else { + Glide.get(context).clearDiskCache(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 清除图片内存缓存 + */ + public void clearImageMemoryCache(Context context) { + try { + if (Looper.myLooper() == Looper.getMainLooper()) { //只能在主线程执行 + Glide.get(context).clearMemory(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 清除图片所有缓存 + */ + public void clearImageAllCache(Context context) { + clearImageDiskCache(context); + clearImageMemoryCache(context); + String ImageExternalCatchDir = context.getExternalCacheDir() + ExternalCacheDiskCacheFactory.DEFAULT_DISK_CACHE_DIR; + deleteFolderFile(ImageExternalCatchDir, true); + } + + /** + * 获取Glide造成的缓存大小 + * + * @return CacheSize + */ + public String getCacheSize(Context context) { + try { + return getFormatSize(getFolderSize(new File(context.getCacheDir() + "/" + InternalCacheDiskCacheFactory.DEFAULT_DISK_CACHE_DIR))); + } catch (Exception e) { + e.printStackTrace(); + } + return ""; + } + + /** + * 获取指定文件夹内所有文件大小的和 + * + * @param file file + * @return size + * @throws Exception + */ + private long getFolderSize(File file) throws Exception { + long size = 0; + try { + File[] fileList = file.listFiles(); + for (File aFileList : fileList) { + if (aFileList.isDirectory()) { + size = size + getFolderSize(aFileList); + } else { + size = size + aFileList.length(); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return size; + } + + /** + * 删除指定目录下的文件,这里用于缓存的删除 + * + * @param filePath filePath + * @param deleteThisPath deleteThisPath + */ + private void deleteFolderFile(String filePath, boolean deleteThisPath) { + if (!TextUtils.isEmpty(filePath)) { + try { + File file = new File(filePath); + if (file.isDirectory()) { + File files[] = file.listFiles(); + for (File file1 : files) { + deleteFolderFile(file1.getAbsolutePath(), true); + } + } + if (deleteThisPath) { + if (!file.isDirectory()) { + file.delete(); + } else { + if (file.listFiles().length == 0) { + file.delete(); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + /** + * 格式化单位 + * + * @param size size + * @return size + */ + private static String getFormatSize(double size) { + + double kiloByte = size / 1024; + if (kiloByte < 1) { + return size + "Byte"; + } + + double megaByte = kiloByte / 1024; + if (megaByte < 1) { + BigDecimal result1 = new BigDecimal(Double.toString(kiloByte)); + return result1.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "KB"; + } + + double gigaByte = megaByte / 1024; + if (gigaByte < 1) { + BigDecimal result2 = new BigDecimal(Double.toString(megaByte)); + return result2.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "MB"; + } + + double teraBytes = gigaByte / 1024; + if (teraBytes < 1) { + BigDecimal result3 = new BigDecimal(Double.toString(gigaByte)); + return result3.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "GB"; + } + BigDecimal result4 = new BigDecimal(teraBytes); + + return result4.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "TB"; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/utils/ImageLoad.kt b/app/src/main/java/com/chwl/app/ui/utils/ImageLoad.kt new file mode 100644 index 0000000..b4bbac4 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/utils/ImageLoad.kt @@ -0,0 +1,220 @@ +package com.chwl.app.ui.utils + +import android.app.Activity +import android.app.Application +import android.content.Context +import android.content.ContextWrapper +import android.graphics.drawable.Drawable +import android.widget.ImageView +import androidx.annotation.DrawableRes +import androidx.fragment.app.FragmentActivity +import com.bumptech.glide.load.DataSource +import com.bumptech.glide.load.engine.GlideException +import com.bumptech.glide.load.resource.bitmap.CenterCrop +import com.bumptech.glide.load.resource.bitmap.RoundedCorners +import com.bumptech.glide.request.RequestListener +import com.bumptech.glide.request.target.CustomTarget +import com.bumptech.glide.request.target.Target +import com.bumptech.glide.request.transition.Transition +import com.bumptech.glide.util.Util +import com.chwl.app.R +import com.chwl.core.utils.LogUtils +import com.chwl.library.common.glide.GlideUtils +import com.chwl.library.common.util.isVerify +import com.netease.nim.uikit.common.util.sys.ScreenUtil +import com.netease.nim.uikit.support.glide.GlideApp +import com.opensource.svgaplayer.SVGADrawable +import com.opensource.svgaplayer.SVGAImageView +import com.opensource.svgaplayer.SVGAParser +import com.opensource.svgaplayer.SVGAVideoEntity +import com.tencent.qgame.animplayer.AnimView +import com.tencent.qgame.animplayer.util.ScaleType +import java.io.File +import java.net.MalformedURLException +import java.net.URL + +fun ImageView.load( + url: String?, + round: Float = 0f, + @DrawableRes defaultRes: Int = R.drawable.default_cover +) { + + if (context.isDestroyed()) return + + if (url.isNullOrEmpty()) { + load(defaultRes) + return + } + + GlideApp.with(context).load(url) + .dontAnimate() + .placeholder(defaultRes) + .error(defaultRes) + .apply { + if (round != 0f) transform(CenterCrop(), RoundedCorners(ScreenUtil.dip2px(round))) + } + .into(this) +} + +fun ImageView.load( + @DrawableRes resId: Int, + round: Float = 0f, + @DrawableRes defaultRes: Int = R.drawable.default_cover +) { + + if (context.isDestroyed()) return + + GlideApp.with(context).load(resId) + .dontAnimate() + .placeholder(defaultRes) + .error(defaultRes) + .apply { + if (round != 0f) transform(CenterCrop(), RoundedCorners(ScreenUtil.dip2px(round))) + } + .into(this) + + +} + +fun ImageView.loadAvatar(url: String?) { + if (context.isDestroyed()) return + if (url.isVerify()) { + ImageLoadUtils.loadAvatar(url,this) + } +} + + +fun ImageView.loadImage(url: String? = "") { + if (this.context.isDestroyed()) return + url?.let { + if (it.endsWith(".gif") || it.endsWith(".GIF")) { + ImageLoadUtils.loadImageGif(this.context,it,this,R.drawable.default_cover) + } else { + GlideApp.with(this.context).load(it) + .dontAnimate() + .into(this) + } + } + +} + +fun Context.isDestroyed(): Boolean { + return (getActivityContext(this) as? Activity)?.isDestroyed == true +} + +fun getActivityContext(context: Context): Context { + + if (Util.isOnMainThread() && context !is Application) { + if (context is FragmentActivity) { + return context + } else if (context is Activity) { + return context + } else if (context is ContextWrapper + // Only unwrap a ContextWrapper if the baseContext has a non-null application context. + // Context#createPackageContext may return a Context without an Application instance, + // in which case a ContextWrapper may be used to attach one. + && context.baseContext.applicationContext != null + ) { + return getActivityContext(context.baseContext) + } + } + return context +} + +fun SVGAImageView.loadFromUrl(svgaUrl: String?) { + try { + SVGAParser.shareParser() + .decodeFromURL(URL(svgaUrl), object : SVGAParser.ParseCompletion { + override fun onComplete(videoItem: SVGAVideoEntity) { + val drawable = SVGADrawable(videoItem) + setImageDrawable(drawable) + startAnimation() + } + + override fun onError() { + } + }) + } catch (e: MalformedURLException) { + + } +} + +fun SVGAImageView.loadFromAssets(name: String) { + try { + SVGAParser.shareParser() + .decodeFromAssets(name, object : SVGAParser.ParseCompletion { + override fun onComplete(videoItem: SVGAVideoEntity) { + val drawable = SVGADrawable(videoItem) + setImageDrawable(drawable) + startAnimation() + } + + override fun onError() { + } + }) + } catch (e: MalformedURLException) { + + } +} + +fun AnimView.loadAnim(url: String) { + + if (context.isDestroyed()) return + + GlideApp.with(this) + .asFile() + .dontTransform() + .load(url) + .into(object : CustomTarget() { + + override fun onLoadCleared(placeholder: Drawable?) {} + + override fun onLoadFailed(errorDrawable: Drawable?) { + super.onLoadFailed(errorDrawable) + LogUtils.d("onLoadFailed") + } + + override fun onResourceReady(resource: File, transition: Transition?) { + this@loadAnim.setScaleType(ScaleType.CENTER_CROP) + this@loadAnim.startPlay(resource) + } + }) +} + +fun AnimView.loadAnim2(url: String,isSafe:Boolean = true,callBack: (isSuccess: Boolean) -> Unit ={_->}) { + if (context.isDestroyed()) return + LogUtils.d("AnimLoadUtil drawEffect loadAnim2 url = $url") + GlideUtils.instance().downloadFromUrl2(context,url,object : RequestListener { + override fun onLoadFailed( + e: GlideException?, + model: Any?, + target: Target?, + isFirstResource: Boolean + ): Boolean { + callBack(false) + LogUtils.d("AnimLoadUtil drawEffect loadAnim2 onLoadFailed url = $url") + return true + } + + override fun onResourceReady( + resource: File?, + model: Any?, + target: Target?, + dataSource: DataSource?, + isFirstResource: Boolean + ): Boolean { + if (resource != null) { + if (isSafe) { + if (this@loadAnim2.isAttachedToWindow){ + this@loadAnim2.startPlay(resource) + } + } else { + this@loadAnim2.startPlay(resource) + } + callBack(true) + LogUtils.d("AnimLoadUtil drawEffect loadAnim2 onResourceReady url = $url") + } + return true + } + }) +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/utils/ImageLoadUtils.java b/app/src/main/java/com/chwl/app/ui/utils/ImageLoadUtils.java new file mode 100644 index 0000000..041fa83 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/utils/ImageLoadUtils.java @@ -0,0 +1,630 @@ +package com.chwl.app.ui.utils; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.NinePatchDrawable; +import android.os.Looper; +import android.text.TextUtils; +import android.view.View; +import android.widget.ImageView; + +import androidx.annotation.DrawableRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.util.Consumer; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.load.DataSource; +import com.bumptech.glide.load.engine.DiskCacheStrategy; +import com.bumptech.glide.load.engine.GlideException; +import com.bumptech.glide.load.resource.bitmap.CenterCrop; +import com.bumptech.glide.load.resource.bitmap.CircleCrop; +import com.bumptech.glide.load.resource.bitmap.RoundedCorners; +import com.bumptech.glide.load.resource.gif.GifDrawable; +import com.bumptech.glide.request.RequestListener; +import com.bumptech.glide.request.target.CustomTarget; +import com.bumptech.glide.request.target.SimpleTarget; +import com.bumptech.glide.request.target.Target; +import com.bumptech.glide.request.transition.Transition; +import com.chwl.app.R; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.utils.BlurTransformation; +import com.chwl.core.utils.LogUtils; +import com.netease.nim.uikit.common.util.string.StringUtil; +import com.netease.nim.uikit.support.glide.GlideApp; +import com.tencent.qgame.animplayer.AnimView; +import com.tencent.qgame.animplayer.util.ScaleType; + +import java.io.File; + +import io.reactivex.Single; + +/** + * 图片加载处理 + * Created by chenran on 2017/11/9. + */ +public class ImageLoadUtils { + private static final String PIC_PROCESSING = "?imageslim"; + private static final String ACCESS_URL = "img.erbanyy.com"; + + public static void loadAvatarBig(String avatar, ImageView imageView) { + loadAvatar(imageView.getContext(), avatar, imageView, R.drawable.default_avatar); + } + public static void loadAvatar(String avatar, ImageView imageView) { + loadAvatar(imageView.getContext(), avatar, imageView, R.drawable.default_avatar); + } + + public static void loadAvatar(Context context,String avatar, ImageView imageView) { + loadAvatar(context,avatar, imageView, R.drawable.default_avatar); + } + + public static void loadAvatar(String avatar, ImageView imageView, int defaultRes) { + loadAvatar(imageView.getContext(),avatar,imageView,defaultRes); + } + + public static void loadAvatar(Context context,String avatar, ImageView imageView, int defaultRes) { + if (TextUtils.isEmpty(avatar) || avatar.equals("null")) return; + if (context == null) return; + if (avatar.endsWith(".gif") || avatar.endsWith(".GIF")) { + ImageLoadUtils.loadCircleImageGif(context, avatar,imageView,defaultRes); + } else { + ImageLoadUtils.loadCircleImage(context, avatar, imageView,defaultRes); + } + } + + + + + + public static void loadSmallRoundBackground(Context context, String url, ImageView imageView) { + if (StringUtil.isEmpty(url)) { + return; + } + StringBuilder sb = new StringBuilder(url); + if (url.contains(ACCESS_URL)) { + if (!url.contains("?")) { + sb.append(PIC_PROCESSING); + } + sb.append("|imageView2/1/w/220/h/220"); + } + GlideApp.with(context.getApplicationContext()) + .load(sb.toString()) + .diskCacheStrategy(DiskCacheStrategy.ALL) + .transforms(new CenterCrop(), + new RoundedCorners(context.getResources().getDimensionPixelOffset(R.dimen.common_cover_round_size))) + .placeholder(R.drawable.default_cover) + .error(R.drawable.default_cover) + .into(imageView); + } + + public static void loadRoomBgBackground(Context context, String url, ImageView imageView) { + if (StringUtil.isEmpty(url)) { + return; + } + StringBuilder sb = new StringBuilder(url); + if (url.contains(ACCESS_URL)) { + if (!url.contains("?")) { + sb.append(PIC_PROCESSING); + } + sb.append("|imageView2/1/w/720/h/1280"); + } + GlideApp.with(context.getApplicationContext()) + .load(sb.toString()) + .diskCacheStrategy(DiskCacheStrategy.ALL) + .into(imageView); + } + + public static void loadBannerRoundBackground(Context context, String url, ImageView imageView) { + if (StringUtil.isEmpty(url)) { + return; + } + StringBuffer sb = new StringBuffer(url); + if (url.contains(ACCESS_URL)) { + if (!url.contains("?")) { + sb.append(PIC_PROCESSING); + } + sb.append("|imageView2/1/w/660/h/220"); + } + + GlideApp.with(context.getApplicationContext()) + .load(sb.toString()) + .diskCacheStrategy(DiskCacheStrategy.ALL) + .transforms(new CenterCrop(), + new RoundedCorners(context.getResources().getDimensionPixelOffset(R.dimen.common_cover_round_size))) + .placeholder(R.drawable.default_cover) + .into(imageView); + } + + public static void loadGameBannerRoundBackground(Context context, String url, ImageView imageView) { + if (StringUtil.isEmpty(url)) { + return; + } + StringBuffer sb = new StringBuffer(url); + if (url.contains(ACCESS_URL)) { + if (!url.contains("?")) { + sb.append(PIC_PROCESSING); + } + sb.append("|imageView2/1/w/660/h/220"); + } + + GlideApp.with(context.getApplicationContext()) + .load(sb.toString()) + .diskCacheStrategy(DiskCacheStrategy.ALL) + .transforms(new CenterCrop(), + new RoundedCorners(context.getResources().getDimensionPixelOffset(R.dimen.dp_8))) + .placeholder(R.drawable.default_cover) + .into(imageView); + } + + public static void loadRoundBackground(Context context, String url, View view, int dp, @DrawableRes int defaultRes) { + if (StringUtil.isEmpty(url)) { + view.setBackgroundResource(defaultRes); + return; + } + GlideApp.with(context.getApplicationContext()) + .load(url) + .diskCacheStrategy(DiskCacheStrategy.ALL) + .transforms(new CenterCrop(), + new RoundedCorners(UIUtil.dip2px(context, dp))) + .placeholder(defaultRes) + .into(new SimpleTarget() { + @Override + public void onResourceReady(Drawable resource, Transition transition) { + view.setBackground(resource); + } + }); + } + + public static void loadBannerRoundBackground(Context context, String url, ImageView imageView, int roundingRadius) { + if (StringUtil.isEmpty(url)) { + return; + } + StringBuffer sb = new StringBuffer(url); + if (url.contains(ACCESS_URL)) { + if (!url.contains("?")) { + sb.append(PIC_PROCESSING); + } + sb.append("|imageView2/1/w/660/h/220"); + } + + GlideApp.with(context.getApplicationContext()) + .load(sb.toString()) + .diskCacheStrategy(DiskCacheStrategy.ALL) + .transforms(new RoundedCorners(roundingRadius)) + .placeholder(R.drawable.default_cover) + .into(imageView); + } + + public static void loadPhotoThumbnail(Context context, String url, ImageView imageView) { + if (StringUtil.isEmpty(url)) { + return; + } + + StringBuffer sb = new StringBuffer(url); + if (url.contains(ACCESS_URL)) { + if (!url.contains("?")) { + sb.append(PIC_PROCESSING); + } + sb.append("|imageView2/1/w/150/h/150"); + } + + loadImage(context, sb.toString(), imageView, R.drawable.default_cover); + } + + public static void loadImageWithBlurTransformation(Context context, String url, final ImageView imageView) { + if (StringUtil.isEmpty(url)) { + return; + } + StringBuffer sb = new StringBuffer(url); + if (url.contains(ACCESS_URL)) { + if (!url.contains("?")) { + sb.append(PIC_PROCESSING); + } + sb.append("|imageView2/1/w/75/h/75"); + } + GlideApp.with(context.getApplicationContext()) + .load(sb.toString()) + .dontTransform() + .dontAnimate() + .override(75, 75) + .centerInside() + .diskCacheStrategy(DiskCacheStrategy.RESOURCE) + .listener(new RequestListener() { + @Override + public boolean onLoadFailed(@Nullable GlideException e, Object o, + Target target, boolean b) { + return false; + } + + @Override + public boolean onResourceReady(Drawable drawable, Object o, + Target target, DataSource dataSource, boolean b) { + imageView.setImageDrawable(drawable); + if (!b) { + imageView.setAlpha(0.F); + imageView.animate().alpha(1F).setDuration(500).start(); + } + return true; + } + }) + // “23”:设置模糊度(在0.0到25.0之间),默认”25";"4":图片缩放比例,默认“1”。 + .transforms(new BlurTransformation(context, 10, 1)) + .into(imageView); + } + + public static void loadImageWithBlurTransformationAndCorner(Context context, String url, + ImageView imageView) { + int defaultPx = context.getResources().getDimensionPixelOffset(R.dimen.common_cover_round_size); + loadImageWithBlurTransformationAndCorner(context, url, imageView, 25, defaultPx); + } + + /** + * @param blur 0-25 越大高斯效果越强 + * @param scale 值越大,图片越模糊 + */ + public static void loadImageWithBlur(Context context, String url, ImageView imageView, int blur, int scale) { + if (StringUtil.isEmpty(url)) { + return; + } + GlideApp.with(context) + .load(url) + .diskCacheStrategy(DiskCacheStrategy.ALL) + .placeholder(R.drawable.default_cover) + .transform(new BlurTransformation(context, blur, scale)) + .into(imageView); + } + + public static void loadImageWithBlurTransformationAndCorner(Context context, String url, + ImageView imageView, int blurRadius, int cornerPx) { + if (StringUtil.isEmpty(url)) { + return; + } + StringBuffer sb = new StringBuffer(url); + if (url.contains(ACCESS_URL)) { + if (!url.contains("?")) { + sb.append(PIC_PROCESSING); + } + sb.append("|imageView2/1/w/75/h/75"); + } + GlideApp.with(context.getApplicationContext()) + .load(url) + .diskCacheStrategy(DiskCacheStrategy.ALL) + .transforms(new CenterCrop(), + new BlurTransformation(context, blurRadius, 3), + new RoundedCorners(cornerPx) + ) + .into(imageView); + } + + public static void loadCircleImage(Context context, String url, ImageView imageView, int defaultRes) { + GlideApp.with(context.getApplicationContext()).load(url) + .transform(new CircleCrop()) + .placeholder(defaultRes) + .error(defaultRes) + .listener(new RequestListener() { + @Override + public boolean onLoadFailed(@Nullable GlideException e, Object model, + Target target, boolean isFirstResource) { + imageView.setImageResource(defaultRes); + return true; + } + + @Override + public boolean onResourceReady(Drawable resource, Object model, + Target target, DataSource dataSource, boolean isFirstResource) { + imageView.setImageDrawable(resource); + return true; + } + }) + .into(imageView); + } + + public static void loadCircleImageGif(Context context, String url, ImageView imageView, int defaultRes) { + GlideApp.with(context.getApplicationContext()) + .asGif() + .load(url) + .transform(new CircleCrop()) + .placeholder(defaultRes) + .error(defaultRes) + .listener(new RequestListener() { + @Override + public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { + imageView.setImageResource(defaultRes); + return true; + } + + @Override + public boolean onResourceReady(GifDrawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { + if (resource != null) { + imageView.setImageDrawable(resource); + resource.start(); + } + return true; + } + }) + .into(imageView); + } + + public static void loadImageGif(Context context, String url, ImageView imageView, int defaultRes) { + GlideApp.with(context.getApplicationContext()) + .asGif() + .load(url) + .placeholder(defaultRes) + .error(defaultRes) + .listener(new RequestListener() { + @Override + public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { + imageView.setImageResource(defaultRes); + return true; + } + + @Override + public boolean onResourceReady(GifDrawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { + if (resource != null) { + imageView.setImageDrawable(resource); + resource.start(); + } + return true; + } + }) + .into(imageView); + } + + public static void loadRoundedImage(ImageView imageView,String url,int Rounded) { + GlideApp.with(imageView.getContext()) + .asDrawable() + .load(url) + .placeholder(R.drawable.default_cover) + .error(R.drawable.default_cover) + .listener(new RequestListener() { + @Override + public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { + if (imageView.isAttachedToWindow()) { + imageView.setImageResource(R.drawable.default_cover); + } + return true; + } + @Override + public boolean onResourceReady(Drawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { + if (imageView.isAttachedToWindow()) { + imageView.setImageDrawable(resource); + } + return true; + } + }) + .into(imageView); + } + + public static void loadBackground(Context context, String url, int defaultRes, View view) { + GlideApp.with(context) + .asDrawable() + .load(url) + .error(defaultRes) + .placeholder(defaultRes) + .into(new SimpleTarget() { + @Override + public void onResourceReady(Drawable resource, Transition transition) { + view.setBackground(resource); + } + }); + } + + public static void loadSpecSizeCircleImage(Context context, String url, ImageView imageView, + int defaultRes, int width, int height) { + GlideApp.with(context.getApplicationContext()).load(url) + .transform(new CircleCrop()) + .override(width, height) + .centerCrop() + .placeholder(defaultRes) + .into(imageView); + } + + public static void loadRectImage(Context context, String url, ImageView imageView, int defaultRes, int cornerRadius) { + GlideApp.with(context.getApplicationContext()).load(url) + .dontAnimate() + .placeholder(defaultRes) + .transform(new CenterCrop(), new RoundedCorners(cornerRadius)) + .error(defaultRes) + .into(imageView); + } + + public static void loadImage(Context context, String url, ImageView imageView, int defaultRes) { + GlideApp.with(context.getApplicationContext()).load(url) + .dontAnimate() + .placeholder(defaultRes) + .error(defaultRes) + .into(imageView); + } + + public static void loadDefaultImage(Context context, ImageView imageView, int defaultRes) { + GlideApp.with(context.getApplicationContext()) + .load(defaultRes) + .placeholder(defaultRes) + .error(defaultRes) + .into(imageView); + } + + public static void loadImage(Context context, File file, ImageView imageView, int defaultRes) { + GlideApp.with(context.getApplicationContext()).load(file).dontAnimate().placeholder(defaultRes).into(imageView); + } + + public static void loadImage(Context context, File file, ImageView imageView) { + GlideApp.with(context.getApplicationContext()).load(file).dontAnimate().into(imageView); + } + + public static void loadImage(Context context, String url, ImageView imageView) { + GlideApp.with(context.getApplicationContext()).load(url).dontAnimate().into(imageView); + } + + public static void load(String url, ImageView imageView) { + if (url != null && !TextUtils.isEmpty(url)){ + if (url.endsWith(".gif") || url.endsWith(".GIF")) { + GlideApp.with(imageView.getContext()).asGif().load(url).dontAnimate().into(imageView); + } else { + GlideApp.with(imageView.getContext()).asBitmap().load(url).dontAnimate().into(imageView); + } + } + } + + public static void loadImage(ImageView imageView, String url) { + GlideApp.with(imageView).load(url).dontAnimate().into(imageView); + } + + public static void loadImage1(Context context, String url, ImageView imageView) { + GlideApp.with(context).load(url).optionalFitCenter().into(new SimpleTarget() { + @Override + public void onResourceReady(Drawable resource, Transition transition) { + imageView.setImageDrawable(resource); + } + }); + } + + + public static void clearMemory(Context context) { +// if (SystemUtils.isMainThread()) { + if (Looper.getMainLooper() == Looper.myLooper()) { + Glide.get(context.getApplicationContext()).clearMemory(); + } + } + + public static void loadKtvRoundBackground(Context context, String url, ImageView imageView) { + GlideApp.with(context) + .load(url) + .diskCacheStrategy(DiskCacheStrategy.ALL) + .transforms(new RoundedCorners(context.getResources().getDimensionPixelOffset(R.dimen.common_cover_round_size))) + .placeholder(R.drawable.default_cover) + .error(R.drawable.default_cover) + .into(imageView); + } + + public static void loadImageWithPlaceholder(Context context, String url, ImageView imageView) { + GlideApp.with(context) + .load(url) + .placeholder(R.drawable.default_cover) + .error(R.drawable.default_cover) + .into(imageView); + } + + /** + * 下载图片 + * + * @param context + * @param url + * @return 返回一个图片 + */ + public static Single loadDrawable(Context context, String url) { + return Single.create(emitter -> GlideApp.with(context).load(url) + + .into(new SimpleTarget() { + + @Override + public void onResourceReady(Drawable resource, Transition transition) { + emitter.onSuccess(resource); + } + + @Override + public void onLoadCleared(@Nullable Drawable placeholder) { + super.onLoadCleared(placeholder); + emitter.onError(new Throwable("onLoadCleared")); + } + + @Override + public void onLoadFailed(@Nullable Drawable errorDrawable) { + super.onLoadFailed(errorDrawable); + emitter.onError(new Throwable("onLoadCleared")); + } + + })); + } + + public static String getCustomSizeUrl(String url, int customSize) { + if (TextUtils.isEmpty(url)) { + return ""; + } + StringBuilder sb = new StringBuilder(url); + if (url.contains(ACCESS_URL)) { + if (!url.contains("?")) { + sb.append(PIC_PROCESSING); + } + sb.append("|imageView2/1/w/").append(customSize).append("/h/").append(customSize); + } + return sb.toString(); + } + + public static String getAvatarSizeUrl(String url) { + return getCustomSizeUrl(url, 150); + } + + /** + * 加载VAP动画 + * test url http://img.uat.lecheng163.com/mask_trunk_demo.mp4 + * + * @param animView + * @param vapUrl + */ + public static void loadVAP(AnimView animView, String vapUrl) { + GlideApp.with(animView) + .asFile() + .dontTransform() + .load(vapUrl) + .into(new CustomTarget() { + @Override + public void onResourceReady(@NonNull File resource, @Nullable Transition transition) { + animView.setScaleType(ScaleType.CENTER_CROP); + animView.startPlay(resource); + } + + @Override + public void onLoadCleared(@Nullable Drawable placeholder) { + + } + + @Override + public void onLoadFailed(@Nullable Drawable errorDrawable) { + super.onLoadFailed(errorDrawable); + LogUtils.d("onLoadFailed"); + } + }); + + } + + public static void loadNinePatchBg(View view, String bgUrl) { + loadNinePatchBg(view, bgUrl,null); + } + + public static void loadNinePatchBg(View view, String bgUrl, Consumer callback) { + GlideApp.with(view) + .asBitmap() + .load(bgUrl) + .into(new CustomTarget() { + @Override + public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition transition) { + try { + NinePatchDrawable drawable = NinePatchBitmapFactory.createNinePatchDrawable(view.getResources(), resource); + view.setBackground(drawable); + if (callback != null) { + callback.accept(true); + } + } catch (Exception e) { + e.printStackTrace(); + if (callback != null) { + callback.accept(false); + } + } + } + + @Override + public void onLoadCleared(@Nullable Drawable placeholder) { + } + + @Override + public void onLoadFailed(@Nullable Drawable errorDrawable) { + super.onLoadFailed(errorDrawable); + if (callback != null) { + callback.accept(false); + } + } + }); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/utils/ImageLoadUtilsV2.java b/app/src/main/java/com/chwl/app/ui/utils/ImageLoadUtilsV2.java new file mode 100644 index 0000000..ae6b672 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/utils/ImageLoadUtilsV2.java @@ -0,0 +1,177 @@ +package com.chwl.app.ui.utils; + +import android.app.Activity; +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.text.TextUtils; +import android.widget.ImageView; + +import com.bumptech.glide.load.resource.bitmap.BitmapTransformation; +import com.bumptech.glide.load.resource.bitmap.CenterCrop; +import com.bumptech.glide.load.resource.bitmap.RoundedCorners; +import com.bumptech.glide.request.RequestOptions; +import com.netease.nim.uikit.support.glide.GlideApp; +import com.netease.nim.uikit.support.glide.GlideRequest; +import com.chwl.app.R; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; + +/** + * create by lvzebiao @2019/7/26 + * {@link ImageLoadUtils 写的有点乱,添加V2,对Context进行判断} + */ +public class ImageLoadUtilsV2 { + + private static final String PIC_PROCESSING = "?imageslim"; + + private static int small_avatar_size = 100; + + public static void init(Context context) { + small_avatar_size = UIUtil.dip2px(context, 50); + } + + public static void loadImage(ImageView imageView, String url, int size) { + loadImage(imageView, url, size, false, false); + } + + public static void loadImage(ImageView imageView, String url) { + loadImage(imageView, url, false); + } + + public static void loadImage(ImageView imageView, String url, boolean isDontAnim) { + loadImage(imageView, url, -1, false, isDontAnim); + } + + public static void loadImage(ImageView imageView, String url, boolean isDontAnim, int roundDp) { + loadImage(imageView, url, isDontAnim, roundDp, null); + } + + public static void loadImage(ImageView imageView, String url, boolean isDontAnim, int roundDp, + RequestOptions option) { + if (imageView == null) { + return; + } + loadImage(imageView.getContext(), imageView, url, -1, false, + R.drawable.default_cover, R.drawable.default_cover, isDontAnim, option, + new CenterCrop(), new RoundedCorners(UIUtil.dip2px(imageView.getContext(), roundDp))); + } + + public static void loadImage(ImageView imageView, String url, + int size, boolean isSquare, boolean isDontAnim) { + loadImage(imageView, url, size, isSquare, R.drawable.default_cover, R.drawable.default_cover, + isDontAnim, null); + } + + public static void loadImage(ImageView imageView, String url, + int size, boolean isSquare, + int errorId, int placeholderId, + boolean isDontAnim) { + loadImage(imageView, url, size, isSquare, errorId, placeholderId, + isDontAnim, null); + } + + public static void loadImage(ImageView imageView, String url, + int size, boolean isSquare, + int errorId, int placeholderId, + boolean isDontAnim, RequestOptions option, + BitmapTransformation... transformations) { + if (imageView == null) { + return; + } + loadImage(imageView.getContext(), imageView, url, size, isSquare, errorId, placeholderId, + isDontAnim, option, transformations); + } + + /** + * + */ + public static void loadImage(Context context, ImageView imageView, String url, + int size, boolean isSquare, + int errorId, int placeholderId, + boolean isDontAnim, RequestOptions option, + BitmapTransformation... transformations) { + if (imageView == null) { + return; + } + if (context == null) { + imageView.setImageResource(placeholderId); + return; + } + if (isGlideDestroyActivity(context)) { + imageView.setImageResource(placeholderId); + return; + } + if (size > 0) { + url = getSizeUrl(url, isSquare, size); + } + GlideRequest requests = GlideApp.with(context).asDrawable().load(url); + if (transformations != null && transformations.length > 0) { + requests = requests.transforms(transformations); + } + if (option != null) { + requests = requests.apply(option); + } + if (isDontAnim) { + requests = requests.dontAnimate(); + } + requests.placeholder(placeholderId) + .error(errorId) + .into(imageView); + + } + + /** + * 加载图片 + * @param view + * @param url + * @param size 大小(Glide.override属性) + */ + @Deprecated(since = "临时加的,后续会整合优化项目的图片加载器!") + public static void loadImage2(ImageView view, String url, int size) { + if (view == null) { + return; + } + GlideApp.with(view).load(url).placeholder(R.drawable.default_cover) + .error(R.drawable.default_cover).override(size).into(view); + } + + /** + * + * @param url - + * @param customSize 七牛云返回的尺寸 + * @param isSquare ture的话,返回一个正方形尺寸,一般用于头像 + * false的话,指定宽度,高度自适应 + * @return - + */ + public static String getSizeUrl(String url, boolean isSquare, int customSize) { + if (TextUtils.isEmpty(url)) { + return ""; + } + try { + if (!url.startsWith("http")) { + return url; + } + StringBuilder sb = new StringBuilder(url); + if (!url.contains("?")) { + sb.append(PIC_PROCESSING); + } + if (isSquare) { + sb.append("|imageView2/1/w/").append(customSize).append("/h/").append(customSize); + } else { + sb.append("|imageView2/2/w/").append(customSize); + } + return sb.toString(); + } catch (Exception ex) { + ex.printStackTrace(); + } + return url; + } + + public static String getSizeUrl(String url, int customSize) { + return getSizeUrl(url, false, customSize); + } + + private static boolean isGlideDestroyActivity(Context context) { + return context instanceof Activity && ((Activity) context).isDestroyed(); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/utils/NinePatchBitmapFactory.java b/app/src/main/java/com/chwl/app/ui/utils/NinePatchBitmapFactory.java new file mode 100644 index 0000000..bd9bb3e --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/utils/NinePatchBitmapFactory.java @@ -0,0 +1,194 @@ +package com.chwl.app.ui.utils; + +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Color; +import android.graphics.Rect; +import android.graphics.drawable.NinePatchDrawable; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.List; + +/** + * User: bgriffey + * Date: 12/27/12 + * Time: 2:37 PM + */ +public class NinePatchBitmapFactory { + + private static final int NO_COLOR = 0x00000001; + + private static final int TRANSPARENT_COLOR = 0x00000000; + + public static NinePatchDrawable createNinePatchDrawable(Resources res, Bitmap bitmap) { + RangeLists rangeLists = checkBitmap(bitmap); + Bitmap trimedBitmap = trimBitmap(bitmap); + NinePatchDrawable drawable = createNinePatchWithCapInsets(res, trimedBitmap, rangeLists.rangeListX, rangeLists.rangeListY, null); + return drawable; + } + + + public static NinePatchDrawable createNinePatchWithCapInsets(Resources res, Bitmap bitmap, + List rangeListX, List rangeListY, String srcName) { + ByteBuffer buffer = getByteBuffer(rangeListX, rangeListY); + NinePatchDrawable drawable = new NinePatchDrawable(res, bitmap, buffer.array(), new Rect(), srcName); + return drawable; + } + + private static ByteBuffer getByteBuffer(List rangeListX, List rangeListY) { + ByteBuffer buffer = ByteBuffer.allocate(4 + 4 * 7 + 4 * 2 * rangeListX.size() + 4 * 2 * rangeListY.size() + 4 * 9).order(ByteOrder.nativeOrder()); + buffer.put((byte) 0x01); // was serialised + buffer.put((byte) (rangeListX.size() * 2)); // x div + buffer.put((byte) (rangeListY.size() * 2)); // y div + buffer.put((byte) 0x09); // color + + // skip + buffer.putInt(0); + buffer.putInt(0); + + // padding + buffer.putInt(0); + buffer.putInt(0); + buffer.putInt(0); + buffer.putInt(0); + + // skip 4 bytes + buffer.putInt(0); + + for (Range range : rangeListX) { + buffer.putInt(range.start); + buffer.putInt(range.end); + } + for (Range range : rangeListY) { + buffer.putInt(range.start); + buffer.putInt(range.end); + } + buffer.putInt(NO_COLOR); + buffer.putInt(NO_COLOR); + buffer.putInt(NO_COLOR); + buffer.putInt(NO_COLOR); + buffer.putInt(NO_COLOR); + buffer.putInt(NO_COLOR); + buffer.putInt(NO_COLOR); + buffer.putInt(NO_COLOR); + buffer.putInt(NO_COLOR); + + return buffer; + + + } + + public static RangeLists checkBitmap(Bitmap bitmap) { + int width = bitmap.getWidth(); + int height = bitmap.getHeight(); + + List rangeListX = new ArrayList<>(); + + int pos = -1; + for (int i = 1; i < width - 1; i++) { + int color = bitmap.getPixel(i, 0); + int alpha = Color.alpha(color); + int red = Color.red(color); + int green = Color.green(color); + int blue = Color.blue(color); + if (alpha == 255 && red == 0 && green == 0 && blue == 0) { + if (pos == -1) { + pos = i - 1; + } + } else { + if (pos != -1) { + Range range = new Range(); + range.start = pos; + range.end = i - 1; + rangeListX.add(range); + pos = -1; + } + } + } + if (pos != -1) { + Range range = new Range(); + range.start = pos; + range.end = width - 2; + rangeListX.add(range); + } + List rangeListY = new ArrayList(); + + pos = -1; + for (int i = 1; i < height - 1; i++) { + int color = bitmap.getPixel(0, i); + int alpha = Color.alpha(color); + int red = Color.red(color); + int green = Color.green(color); + int blue = Color.blue(color); + if (alpha == 255 && red == 0 && green == 0 && blue == 0) { + if (pos == -1) { + pos = i - 1; + } + } else { + if (pos != -1) { + Range range = new Range(); + range.start = pos; + range.end = i - 1; + rangeListY.add(range); + pos = -1; + } + } + + } + if (pos != -1) { + Range range = new Range(); + range.start = pos; + range.end = height - 2; + rangeListY.add(range); + } + RangeLists rangeLists = new RangeLists(); + rangeLists.rangeListX = rangeListX; + rangeLists.rangeListY = rangeListY; + + return rangeLists; + } + + public static Bitmap trimBitmap(Bitmap bitmap) { + int width = bitmap.getWidth(); + int height = bitmap.getHeight(); + + Bitmap result = Bitmap.createBitmap(bitmap, 1, 1, width - 2, height - 2); + + return result; + + } + + public static Bitmap loadBitmap(File file) { + BufferedInputStream bis = null; + try { + bis = new BufferedInputStream(new FileInputStream(file)); + return BitmapFactory.decodeStream(bis); + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + bis.close(); + } catch (Exception e) { + + } + } + return null; + } + + public static class RangeLists { + public List rangeListX; + public List rangeListY; + } + + public static class Range { + public int start; + public int end; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/utils/RVDelegate.java b/app/src/main/java/com/chwl/app/ui/utils/RVDelegate.java new file mode 100644 index 0000000..1502944 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/utils/RVDelegate.java @@ -0,0 +1,190 @@ +package com.chwl.app.ui.utils; + +import android.view.View; + +import androidx.recyclerview.widget.RecyclerView; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.netease.nim.uikit.common.util.sys.NetworkUtil; +import com.chwl.app.R; +import com.chwl.app.base.IDataStatus; +import com.chwl.app.common.EmptyViewHelper; +import com.chwl.core.bean.response.ListResult; +import com.chwl.core.utils.LogUtils; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; + +import java.util.List; + +/** + * 无聊写的,好像没什么用的样子 + * create time 2018/11/28 + * + * @param Adapter对应数据类型 + */ + +public class RVDelegate { + private BaseQuickAdapter adapter; + private RecyclerView recyclerView; + private SwipeRefreshLayout refreshLayout; + private int pageSize; + private IDataStatus dataStatus; + private View emptyView; + + private RVDelegate(BaseQuickAdapter adapter, RecyclerView.LayoutManager layoutManager, RecyclerView recyclerView, SwipeRefreshLayout refreshLayout, IDataStatus dataStatus, View emptyView, int pageSize) { + this.adapter = adapter; + this.recyclerView = recyclerView; + this.pageSize = pageSize; + this.dataStatus = dataStatus; + this.refreshLayout = refreshLayout; + this.emptyView = emptyView; + recyclerView.setLayoutManager(layoutManager); + try { + adapter.bindToRecyclerView(recyclerView); + } catch (IllegalStateException e) { + LogUtils.e("already bind adapter,skip bind!"); + } + } + + public void loadData(ListResult result) { + if (result == null) { + LogUtils.d("result == null,skip layout"); + return; + } + if (result.isSuccess()) { + loadData(result.getData(), result.isRefresh()); + } else { + loadErr(result.isRefresh()); + } + } + + public void loadData(List data, boolean isRefresh) { + if (isRefresh) { + setNewData(data); + } else { + addData(data); + } + } + + + public void addData(List data) { + if (data != null) { + adapter.addData(data); + } + if (data != null && data.size() >= pageSize) { + adapter.loadMoreComplete(); + } else { + adapter.loadMoreEnd(); + } + } + + public void setNewData(List data) { + adapter.setNewData(data); + if (emptyView != null && adapter.getEmptyView() == null) { + adapter.setEmptyView(emptyView); + } + adapter.disableLoadMoreIfNotFullPage(); + if (data != null && data.size() >= pageSize) { + adapter.loadMoreComplete(); + } else { + adapter.loadMoreEnd(); + } + if (refreshLayout != null) refreshLayout.setRefreshing(false); + if (dataStatus != null) { + if (!ListUtils.isListEmpty(data)) { + dataStatus.hideStatus(); + } else { + dataStatus.showNoData(); + } + } + } + + + public BaseQuickAdapter getAdapter() { + return adapter; + } + + public void loadErr(boolean isRefresh) { + if (isRefresh) { + if (!NetworkUtil.isNetAvailable(recyclerView.getContext())) { + adapter.setEmptyView(EmptyViewHelper.createEmptyTextView(recyclerView.getContext(), ResUtil.getString(R.string.ui_utils_rvdelegate_01))); + } else if (emptyView != null) { + adapter.setEmptyView(emptyView); + } + if (refreshLayout != null) refreshLayout.setRefreshing(false); + if (dataStatus != null) { + if (NetworkUtil.isNetAvailable(recyclerView.getContext())) { + dataStatus.showNoData(); + } else { + dataStatus.showNetworkErr(); + } + } + } else { + adapter.loadMoreFail(); + } + } + + + public static class Builder { + private BaseQuickAdapter adapter; + private RecyclerView.LayoutManager layoutManager; + private RecyclerView recyclerView; + private int pageSize = Integer.MAX_VALUE; + private IDataStatus dataStatus; + private SwipeRefreshLayout refreshLayout; + private View emptyView; + + public Builder setAdapter(BaseQuickAdapter mAdapter) { + this.adapter = mAdapter; + return this; + } + + /** + * @param pageSize 每页数量,不设置默认不分页 + * @return + */ + + public Builder setPageSize(int pageSize) { + this.pageSize = pageSize; + return this; + } + + public Builder setLayoutManager(RecyclerView.LayoutManager layoutManager) { + this.layoutManager = layoutManager; + return this; + } + + public Builder setRecyclerView(RecyclerView recyclerView) { + this.recyclerView = recyclerView; + return this; + } + + /** + * 如果设置refreshLayout,可会在每次加载完数据后隐藏刷新的view + * + * @param refreshLayout + * @return + */ + public Builder setRefreshLayout(SwipeRefreshLayout refreshLayout) { + this.refreshLayout = refreshLayout; + return this; + } + + public Builder setDataStatus(IDataStatus dataStatus) { + this.dataStatus = dataStatus; + return this; + } + + public Builder setEmptyView(View emptyView) { + this.emptyView = emptyView; + return this; + } + + public RVDelegate build() { + return new RVDelegate<>(adapter, layoutManager, recyclerView, refreshLayout, dataStatus, emptyView, pageSize); + } + + } +} diff --git a/app/src/main/java/com/chwl/app/ui/utils/SoftPool.kt b/app/src/main/java/com/chwl/app/ui/utils/SoftPool.kt new file mode 100644 index 0000000..19af98c --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/utils/SoftPool.kt @@ -0,0 +1,62 @@ +package com.chwl.app.ui.utils + +import com.opensource.svgaplayer.utils.Pools +import java.lang.ref.SoftReference +import java.util.LinkedList + +class SoftPool (private var max:Int) : Pools.Pool { + + init { + if (max <= 0){ + max = 8 + } + } + + private var mPool = LinkedList>() + + fun acquire(getItemEmpty:()->T):T{ + return acquire()?:getItemEmpty() + } + + + override fun acquire(): T? { + if (mPool.size == 0){ + return null + } + + while (true){ + val item = mPool.poll()?:return null + if (item.get() != null) { + return item.get() + } + } + + } + + override fun release(instance: T): Boolean { + if (mPool.size > max) { + if (getRealSize() > max) { + return false + } + } + mPool.addFirst(SoftReference(instance)) + return true + } + + + private fun getRealSize() : Int{ + val iterator = mPool.listIterator() + while (iterator.hasNext()) { + val item = iterator.next().get() + if (item == null) iterator.remove() + } + return mPool.size + } + + fun clear(){ + mPool.clear() + } + + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/utils/SurfaceViewAnimation.java b/app/src/main/java/com/chwl/app/ui/utils/SurfaceViewAnimation.java new file mode 100644 index 0000000..656f33c --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/utils/SurfaceViewAnimation.java @@ -0,0 +1,506 @@ +package com.chwl.app.ui.utils; + +import android.content.res.AssetManager; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.PixelFormat; +import android.graphics.PorterDuff; +import android.graphics.Rect; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.util.Log; +import android.util.SparseArray; +import android.view.SurfaceHolder; +import android.view.SurfaceView; + +import androidx.annotation.IntDef; +import androidx.annotation.IntRange; +import androidx.annotation.NonNull; + +import java.io.File; +import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Created by yuyashuai on 2016/11/28 0028. + * use SurfaceView play Frame Animation + */ + +public final class SurfaceViewAnimation { + + + private final SparseArray mBitmapCache; + private SurfaceView mSurfaceView; + private SurfaceHolder mSurfaceHolder; + private List mPathList; + private MyCallBack mCallBack; + private int mode = MODE_INFINITE; + private boolean isOnDestory = false; + /** + * 是否从asset中读取资源 + */ + private boolean isAssetResource = false; + private AssetManager mAssetManager; + private final String TAG = "SurfaceViewAnimation"; + /** + * total frames. + */ + private int mTotalCount; + + /** + * handler of the thread that in charge of loading bitmap. + */ + private Handler mDecodeHandler; + + /** + * time interval between two frames. + */ + private int mFrameInterval = 100; + /** + * number of frames resides in memory. + */ + private int mCacheCount = 5; + + /** + * callback of animation state. + */ + private AnimationStateListener mAnimationStateListener; + + /** + * start animation command. + */ + private final int CMD_START_ANIMATION = -1; + + /** + * stop animation command. + */ + private final int CMD_STOP_ANIMATION = -2; + + /** + * Repeat the animation once. + */ + public static final int MODE_ONCE = 1; + /** + * Repeat the animation indefinitely. + */ + public static final int MODE_INFINITE = 2; + + private SurfaceViewAnimation() { + mBitmapCache = new SparseArray<>(); + } + + @IntDef({MODE_INFINITE, MODE_ONCE}) + @Retention(RetentionPolicy.SOURCE) + public @interface RepeatMode { + } + + public static class Builder { + + private final String TAG = "SurfaceViewAnimation"; + + private SurfaceViewAnimation mAnimation; + + public Builder(@NonNull SurfaceView surfaceView, @NonNull List pathList) { + mAnimation = new SurfaceViewAnimation(); + mAnimation.init(surfaceView, pathList); + } + + /** + * @param surfaceView + * @param assetPath asset resource path, must be a directory + */ + public Builder(@NonNull SurfaceView surfaceView, @NonNull String assetPath) { + AssetManager assetManager = surfaceView.getContext().getAssets(); + try { + String assetFiles[] = assetManager.list(assetPath); + if (assetFiles.length == 0) { + Log.e(TAG, "no file in this asset directory"); + return; + } + //转换真实路径 + for(int i=0;i mAssertList = Arrays.asList(assetFiles); + mAnimation = new SurfaceViewAnimation(); + mAnimation.isAssetResource = true; + mAnimation.setAssetManager(assetManager); + mAnimation.init(surfaceView, mAssertList); + } catch (IOException e) { + Log.e(TAG, e.getMessage()); + e.printStackTrace(); + } + } + + /** + * @param surfaceView + * @param file must be a directory + */ + public Builder(@NonNull SurfaceView surfaceView, @NonNull File file) { + List list = new ArrayList<>(); + if (file != null) { + if (file.exists() && file.isDirectory()) { + File[] files = file.listFiles(); + for (File mFrameFile : files) { + list.add(mFrameFile.getAbsolutePath()); + } + } else if (!file.exists()) { + Log.e(TAG, "file doesn't exists"); + } else { + Log.e(TAG, "file isn't a directory"); + } + } else { + Log.e(TAG, "file is null"); + } + mAnimation = new SurfaceViewAnimation(); + mAnimation.init(surfaceView, list); + } + + + public Builder setFrameInterval(int timeMillisecond) { + mAnimation.setFrameInterval(timeMillisecond); + return this; + } + + public Builder setCacheCount(@IntRange(from = 1) int count) { + mAnimation.setCacheCount(count); + return this; + } + + public Builder setAnimationListener(AnimationStateListener listener) { + mAnimation.setAnimationStateListener(listener); + return this; + } + + public Builder setRepeatMode(@RepeatMode int mode) { + mAnimation.setRepeatMode(mode); + return this; + } + + public SurfaceViewAnimation build() { + return mAnimation; + } + + } + + private void init(SurfaceView surfaceView, List pathList) { + this.mSurfaceView = surfaceView; + this.mSurfaceHolder = surfaceView.getHolder(); + mCallBack = new MyCallBack(); + mSurfaceHolder.setFormat(PixelFormat.TRANSLUCENT); + mSurfaceView.setZOrderOnTop(true); + mSurfaceHolder.addCallback(mCallBack); + this.mPathList = pathList; + } + + + public void start() { + if (isOnDestory) { + return; + } + + if (mCallBack.isDrawing) { + return; + //stopAnimation(); + } + if (mPathList == null) { + throw new NullPointerException("pathList can not be null."); + } + if (mPathList.size() == 0) { + return; + } + //从文件中读取 + if(!isAssetResource) + { + File file = new File(mPathList.get(0)); + if (!file.exists()) { + return; + } + } + mTotalCount = mPathList.size(); + startDecodeThread(); + } + + private void setAssetManager(AssetManager assetManager) { + this.mAssetManager = assetManager; + } + + private void setFrameInterval(int time) { + this.mFrameInterval = time; + } + + public void stop() { + if(!isDrawing()) return; + mCallBack.stopAnim(); + } + + private void setCacheCount(int count) { + mCacheCount = count; + } + + private void setRepeatMode(@RepeatMode int mode) { + this.mode = mode; + } + + public boolean isDrawing() { + return mCallBack.isDrawing; + } + + private void setAnimationStateListener(AnimationStateListener animationStateListener) { + this.mAnimationStateListener = animationStateListener; + } + + public interface AnimationStateListener { + void onStart(); + + void onFinish(); + } + + private class MyCallBack implements SurfaceHolder.Callback { + private Canvas mCanvas; + private Bitmap mCurrentBitmap; + private int position = 0; + public boolean isDrawing = false; + private Thread drawThread; + private Rect rect = new Rect(); + + @Override + public void surfaceCreated(SurfaceHolder holder) { + isOnDestory = false; + } + + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + rect.set(0, 0, width, height); + } + + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + isOnDestory = true; + stop(); + } + + /** + * 绘制 + */ + private void drawBitmap() { + + //当循环播放时,获取真实的position + if (mode == MODE_INFINITE && position >= mTotalCount) { + position = position % mTotalCount; + } + + if (position >= mTotalCount) { + isDrawing = false; + mDecodeHandler.sendEmptyMessage(-2); + //clear surfaceView + clearSurface(); + return; + } + if (mBitmapCache.get(position, null) == null) { + mCanvas = mSurfaceHolder.lockCanvas(); + if (mCanvas == null) { + return; + } + //clear surfaceView + clearSurface(); + return; + } + mCurrentBitmap = mBitmapCache.get(position); + mDecodeHandler.sendEmptyMessage(position); + mCanvas = mSurfaceHolder.lockCanvas(rect); + if (mCanvas == null) { + return; + } + mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); + mCanvas.drawBitmap(mCurrentBitmap, null, rect, null); + mSurfaceHolder.unlockCanvasAndPost(mCanvas); + mCurrentBitmap.recycle(); + position++; + } + + private void clearSurface() { + mCanvas = mSurfaceHolder.lockCanvas(); + //clear surfaceView + if (mCanvas != null) { + mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); + mSurfaceHolder.unlockCanvasAndPost(mCanvas); + } + } + + private void startAnim() { + if (isOnDestory) { + return; + } + + if (mAnimationStateListener != null) { + mAnimationStateListener.onStart(); + } + isDrawing = true; + position = 0; + + //绘制线程 + drawThread = new Thread() { + @Override + public void run() { + super.run(); + while (isDrawing) { + try { + long now = System.currentTimeMillis(); +// drawBitmap(); + if (mode == MODE_INFINITE && position >= mTotalCount) { + position = position % mTotalCount; + } + + if (position >= mTotalCount) { + isDrawing = false; + mDecodeHandler.sendEmptyMessage(-2); + //clear surfaceView + clearSurface(); + return; + } + if (mBitmapCache.get(position, null) == null) { + mCanvas = mSurfaceHolder.lockCanvas(); + if (mCanvas == null) { + return; + } + //clear surfaceView + clearSurface(); + return; + } + mCurrentBitmap = mBitmapCache.get(position); + mDecodeHandler.sendEmptyMessage(position); + mCanvas = mSurfaceHolder.lockCanvas(rect); + if (mCanvas == null) { + return; + } + mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); + mCanvas.drawBitmap(mCurrentBitmap, null, rect, null); + mSurfaceHolder.unlockCanvasAndPost(mCanvas); + mCurrentBitmap.recycle(); + position++; + //控制两帧之间的间隔 + sleep(mFrameInterval - (System.currentTimeMillis() - now) > 0 ? mFrameInterval - (System.currentTimeMillis() - now) : 0); + } catch (InterruptedException e1) { + e1.printStackTrace(); + } +// finally { +// if (mCanvas != null) { +// mSurfaceHolder.unlockCanvasAndPost(mCanvas); +// } +// } + } + } + }; + drawThread.start(); + } + + private void stopAnim() { + isDrawing = false; + position = 0; + mBitmapCache.clear(); + clearSurface(); + //mPathList.clear(); + if(mDecodeHandler!=null) + { + mDecodeHandler.sendEmptyMessage(CMD_STOP_ANIMATION); + } + if(drawThread!=null) + { + drawThread.interrupt(); + } + if (mAnimationStateListener != null) { + mAnimationStateListener.onFinish(); + } + + } + } + + //decode线程 + private void startDecodeThread() { + new Thread() { + @Override + public void run() { + super.run(); + Looper.prepare(); + + mDecodeHandler = new Handler(Looper.myLooper()) { + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + if (msg.what == CMD_STOP_ANIMATION) { + decodeBitmap(CMD_STOP_ANIMATION); + getLooper().quit(); + return; + } + decodeBitmap(msg.what); + } + }; + decodeBitmap(CMD_START_ANIMATION); + Looper.loop(); + } + }.start(); + } + + /** + * 根据不同指令 进行不同操作 + * + * @param position + */ + private void decodeBitmap(int position) { + if (position == CMD_START_ANIMATION) { + for (int i = 0; i < mCacheCount; i++) { + if (mPathList.size() <= i) break; + mBitmapCache.put(i, decodeBitmapReal(mPathList.get(i))); + } + mCallBack.startAnim(); + } else if (position == CMD_STOP_ANIMATION) { + mCallBack.stopAnim(); + } else if (mode == MODE_ONCE) { + if (position + mCacheCount <= mTotalCount - 1) { + mBitmapCache.remove(position); + mBitmapCache.put(position + mCacheCount, decodeBitmapReal(mPathList.get(position + mCacheCount))); + } + } else if (mode == MODE_INFINITE) { + if (position + mCacheCount > mTotalCount - 1) { + mBitmapCache.remove(position); + mBitmapCache.put((position + mCacheCount) % mTotalCount, decodeBitmapReal(mPathList.get((position + mCacheCount) % mTotalCount))); + } else { + mBitmapCache.remove(position); + mBitmapCache.put(position + mCacheCount, decodeBitmapReal(mPathList.get(position + mCacheCount))); + } + } + } + + /** + * 根据不同的情况,选择不同的加载方式 + * @param path + * @return + */ + private Bitmap decodeBitmapReal(String path) + { + if(isAssetResource) + { + try { + return BitmapFactory.decodeStream(mAssetManager.open(path)); + } catch (IOException e) { + stop(); + Log.e(TAG,"IOException, animation stop"); + Log.e(TAG,e.getMessage()); + e.printStackTrace(); + } + }else + { + return BitmapFactory.decodeFile(path); + } + return null; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/utils/VipUtil.kt b/app/src/main/java/com/chwl/app/ui/utils/VipUtil.kt new file mode 100644 index 0000000..16e4b37 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/utils/VipUtil.kt @@ -0,0 +1,83 @@ +package com.chwl.app.ui.utils + +import android.view.ViewGroup +import android.widget.ImageView +import com.chwl.app.R +import com.chwl.app.avroom.widget.GalleryLayoutManager.LayoutParams +import com.chwl.core.user.bean.EffectType +import com.chwl.core.user.bean.UserBgVO +import com.chwl.library.common.util.isVerify +import com.chwl.library.common.util.setViewWH +import com.chwl.library.common.util.setVis +import com.chwl.library.widget.SVGAView +import com.tencent.qgame.animplayer.AnimView +import com.tencent.qgame.animplayer.util.ScaleType + +object VipUtil { + + val vipIcons = arrayListOf( + R.drawable.vip_center_identification_vipidentity_lv1, + R.drawable.vip_center_identification_vipidentity_lv2, + R.drawable.vip_center_identification_vipidentity_lv3, + R.drawable.vip_center_identification_vipidentity_lv4, + R.drawable.vip_center_identification_vipidentity_lv5, + R.drawable.vip_center_identification_vipidentity_lv6, + R.drawable.vip_center_identification_vipidentity_lv7, + R.drawable.vip_center_identification_vipidentity_lv8, + R.drawable.vip_center_identification_vipidentity_lv9 + ) + + fun getVipIcon(level: Int) { + vipIcons.getOrNull(level)?:R.drawable.vip_center_identification_vipidentity_lv1 + } + + + fun setUserBg( + data: UserBgVO?, + layout: ViewGroup, + callBack: (isSuccess: Boolean) -> Unit ={_->} + ){ + if (data != null) { + layout.setVis(true) + layout.removeAllViews() + + if (data.effectType == EffectType.IMG) { + val url = if (data.effect.isVerify()) data.effect else data.pic + val image = ImageView(layout.context) + layout.addView(image) + image.setViewWH(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, false) + image.setScaleType(ImageView.ScaleType.FIT_XY) + image.loadImage(url) + callBack(true) + }else { + if (data.effect.isVerify()) { + var animView : AnimView?=null + var svgaView : SVGAView?=null + + if (data.effectType == EffectType.MP4) { + animView = AnimView(layout.context) + layout.addView(animView) + animView.setLoop(Int.MAX_VALUE) + animView.setScaleType(ScaleType.FIT_XY) + callBack(true) + } else if (data.effectType == EffectType.SVGA) { + svgaView = SVGAView(layout.context) + layout.addView(svgaView) + svgaView.loops = Int.MAX_VALUE + svgaView.setScaleType(ImageView.ScaleType.FIT_XY) + callBack(true) + } else { + callBack(false) + } + + animView?.setViewWH(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, false) + svgaView?.setViewWH(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT,false) + + animView?.loadAnim2(data.effect,false) + svgaView?.loadUrl(data.effect,true) + } + } + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/utils/sys/InstallUtil.java b/app/src/main/java/com/chwl/app/ui/utils/sys/InstallUtil.java new file mode 100644 index 0000000..a56f397 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/utils/sys/InstallUtil.java @@ -0,0 +1,116 @@ +package com.chwl.app.ui.utils.sys; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.net.Uri; +import android.text.TextUtils; + +import com.netease.nim.uikit.api.NimUIKit; + +import java.io.File; + +public class InstallUtil { + private static final String TAG = "InstallUtil"; + + private static int versionCode; + + private static String versionName; + + /** + * 是否已安装app + * + * @param context + * @param packageName + * @return + */ + public static boolean isAppInstalled(Context context, String packageName) { + try { + if (TextUtils.isEmpty(packageName)) + return false; + return context.getPackageManager().getPackageInfo(packageName, PackageManager.GET_ACTIVITIES) != null; + } catch (NameNotFoundException localNameNotFoundException) { + return false; + } + } + + /** + * 打开app + * + * @param packageName + * @param context + */ + public static void openApp(Context context, String packageName) { + PackageManager packageManager = context.getPackageManager(); + Intent intent = packageManager.getLaunchIntentForPackage(packageName); + if (intent != null) + context.startActivity(intent); + } + + /** + * 某个app的版本号,未安装时返回null + */ + public static final String getVersionName(Context context, String packageName) { + try { + PackageInfo pi = context.getPackageManager().getPackageInfo(packageName, 0); + if (pi != null) { + return pi.versionName; + } else { + return null; + } + } catch (NameNotFoundException e) { + return null; + } + } + + public static final int getVersionCode(Context context) { + if (versionCode == 0) { + loadVersionInfo(context); + } + + return versionCode; + } + + /** + * 易信版本号 + */ + public static final String getVersionName(Context context) { + if (TextUtils.isEmpty(versionName)) { + loadVersionInfo(context); + } + + return versionName; + } + + private static final void loadVersionInfo(Context context) { + try { + PackageInfo pi = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); + if (pi != null) { + versionCode = pi.versionCode; + versionName = pi.versionName; + } + } catch (NameNotFoundException e) { + e.printStackTrace(); + } + } + + /** + * 安装apk文件 + */ + public static void installApk(String filepath) { + NimUIKit.getContext().startActivity(getInstallApkIntent(filepath)); + } + + /** + * 安装apk文件 + */ + public static Intent getInstallApkIntent(String filepath) { + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + File file = new File(filepath); + intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive"); + return intent; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/utils/sys/PermissionUtil.kt b/app/src/main/java/com/chwl/app/ui/utils/sys/PermissionUtil.kt new file mode 100644 index 0000000..d2d466a --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/utils/sys/PermissionUtil.kt @@ -0,0 +1,4 @@ +package com.chwl.app.ui.utils.sys + +class PermissionUtil { +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/wallet/WalletActivity.kt b/app/src/main/java/com/chwl/app/ui/wallet/WalletActivity.kt new file mode 100644 index 0000000..4d592c7 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/wallet/WalletActivity.kt @@ -0,0 +1,128 @@ +package com.chwl.app.ui.wallet + +import android.content.Context +import android.content.Intent +import android.widget.LinearLayout +import android.widget.TextView +import androidx.activity.viewModels +import androidx.fragment.app.Fragment +import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback +import com.chwl.app.R +import com.chwl.app.avroom.adapter.CommonVPAdapter +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.databinding.WalletActivityBinding +import com.chwl.app.ui.utils.load +import com.chwl.app.ui.webview.CommonWebViewActivity +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.CommonNavigator +import com.chwl.app.utils.LoginSuccessManager +import com.chwl.core.UriProvider +import com.chwl.library.utils.ResUtil +import com.netease.nim.uikit.StatusBarUtil +import org.greenrobot.eventbus.EventBus + +class WalletActivity : BaseViewBindingActivity() { + + private val viewModel: WalletViewModel by viewModels() + + companion object { + fun start(context: Context) { + context.startActivity(Intent(context, WalletActivity::class.java)) + } + } + + override fun init() { + EventBus.getDefault().register(this) + initWhiteTitleBar(ResUtil.getString(R.string.wallet)) + initViewPager() + initObserve() + dialogManager.showProgressDialog(this) + + if (!LoginSuccessManager.getInstance().mFirstRechargeStatus) { + LoginSuccessManager.getInstance().mFirstRechargeInfo?.let { + binding.ivBanner.load(it.chargeBanner) + binding.ivBanner.setOnClickListener { + CommonWebViewActivity.start(this@WalletActivity,UriProvider.getFirstRechargeBonus()) + } + } + } + } + + override fun onResume() { + super.onResume() + viewModel.getWalletInfo() + } + + private fun initObserve() { + viewModel.walletInfoLiveData.observe(this) { + dialogManager.dismissDialog() + if (!it.isSuccess && it.message != null) { + toast(it.message) + } + } + } + + private fun initViewPager() { + val fragmentList: MutableList = ArrayList(2) + fragmentList.add(WalletCoinsFragment()) + fragmentList.add(WalletDiamondFragment()) + val tagList: MutableList = ArrayList(2) + tagList.add(getString(R.string.diamond)) + tagList.add(getString(R.string.gold)) + val commonNavigator = CommonNavigator(context) + commonNavigator.setTitleWrapContent(true) + val magicIndicatorAdapter = WalletIndicatorAdapter(context, tagList) + magicIndicatorAdapter.setOnItemSelectListener { position: Int, view: TextView? -> + binding.viewPager.currentItem = position + } + commonNavigator.adapter = magicIndicatorAdapter + binding.magicIndicator.navigator = commonNavigator + commonNavigator.titleContainer.showDividers = LinearLayout.SHOW_DIVIDER_MIDDLE + binding.viewPager.offscreenPageLimit = 2 + binding.viewPager.adapter = CommonVPAdapter( + supportFragmentManager, + lifecycle, + fragmentList + ) + binding.viewPager.registerOnPageChangeCallback(object : OnPageChangeCallback() { + override fun onPageScrolled( + position: Int, + positionOffset: Float, + positionOffsetPixels: Int + ) { + binding.magicIndicator.onPageScrolled( + position, + positionOffset, + positionOffsetPixels + ) + } + + override fun onPageSelected(position: Int) { + binding.magicIndicator.onPageSelected(position) + if (position == 0) { + binding.ivTop.setImageResource(R.drawable.wallet_bg_coins_top) + } else { + binding.ivTop.setImageResource(R.drawable.wallet_bg_diamond_top) + } + } + + override fun onPageScrollStateChanged(state: Int) { + binding.magicIndicator.onPageScrollStateChanged(state) + } + }) + } + + override fun needSteepStateBar(): Boolean { + return true + } + + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } + + override fun onDestroy() { + super.onDestroy() + EventBus.getDefault().unregister(this) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/wallet/WalletCoinsFragment.kt b/app/src/main/java/com/chwl/app/ui/wallet/WalletCoinsFragment.kt new file mode 100644 index 0000000..49a94ed --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/wallet/WalletCoinsFragment.kt @@ -0,0 +1,35 @@ +package com.chwl.app.ui.wallet + +import androidx.fragment.app.activityViewModels +import com.chwl.app.R +import com.chwl.app.base.BaseBindingFragment +import com.chwl.app.databinding.WalletCoinsFragmentBinding +import com.chwl.app.ui.pay.ChargeActivity +import com.chwl.app.ui.webview.CommonWebViewActivity +import com.chwl.core.UriProvider +import com.chwl.library.annatation.ActLayoutRes +import com.chwl.library.utils.FormatUtils +import com.example.lib_utils.ktx.singleClick + + +@ActLayoutRes(R.layout.wallet_coins_fragment) +class WalletCoinsFragment : BaseBindingFragment() { + val viewModel: WalletViewModel by activityViewModels() + override fun initiate() { + mBinding.layoutDetails.singleClick { + CommonWebViewActivity.start(context, UriProvider.getDiamondDetail()) + } + viewModel.walletInfoLiveData.observe(this) { + if (it.isSuccess) { + updateValue(it.data?.diamondNum ?: 0.0) + } + } + mBinding.tvNext.singleClick { + ChargeActivity.start(requireContext()) + } + } + + private fun updateValue(number: Double) { + mBinding.tvCurrencyValue.text = FormatUtils.formatBigDecimal(number) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/wallet/WalletDiamondFragment.kt b/app/src/main/java/com/chwl/app/ui/wallet/WalletDiamondFragment.kt new file mode 100644 index 0000000..e0fcb35 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/wallet/WalletDiamondFragment.kt @@ -0,0 +1,53 @@ +package com.chwl.app.ui.wallet + +import androidx.fragment.app.activityViewModels +import com.chwl.app.R +import com.chwl.app.base.BaseBindingFragment +import com.chwl.app.databinding.WalletDiamondFragmentBinding +import com.chwl.app.earn.activity.ConvertDiamondActivity +import com.chwl.app.ui.webview.CommonWebViewActivity +import com.chwl.core.UriProvider +import com.chwl.library.annatation.ActLayoutRes +import com.chwl.library.utils.FormatUtils +import com.example.lib_utils.ktx.singleClick + +@ActLayoutRes(R.layout.wallet_diamond_fragment) +class WalletDiamondFragment : BaseBindingFragment() { + val viewModel: WalletViewModel by activityViewModels() + + private var wantToConvert = false + + override fun initiate() { + mBinding.layoutDetails.singleClick { + CommonWebViewActivity.start(context, UriProvider.getGoldDetail()) + } + + mBinding.tvNext.singleClick { + jumpConvert() + } + + viewModel.walletInfoLiveData.observe(this) { + if (it.isSuccess) { + updateValue(it.data?.goldNum ?: 0.0) + } + } + + viewModel.convertInfoLiveData.observe(this) { + if (it.isSuccess) { + it?.data?.let { + ConvertDiamondActivity.start(requireContext(), it) + } + } else if (it.message != null) { + toast(it.message) + } + } + } + + private fun jumpConvert() { + viewModel.getConvertInfo() + } + + private fun updateValue(number: Double) { + mBinding.tvCurrencyValue.text = FormatUtils.formatBigDecimal(number) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/wallet/WalletIndicatorAdapter.java b/app/src/main/java/com/chwl/app/ui/wallet/WalletIndicatorAdapter.java new file mode 100644 index 0000000..16373f2 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/wallet/WalletIndicatorAdapter.java @@ -0,0 +1,105 @@ +package com.chwl.app.ui.wallet; + +import android.content.Context; +import android.view.Gravity; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.TextView; + +import androidx.core.content.ContextCompat; + +import com.chwl.app.R; +import com.chwl.app.ui.widget.XRecyclerView.ScaleTransitionPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.CommonNavigatorAdapter; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.indicators.LinePagerIndicator; + +import java.util.List; + +public class WalletIndicatorAdapter extends CommonNavigatorAdapter { + private final Context mContext; + private final List mTitleList; + + private int textSize = 16; + private float minScale = 1f; + private boolean showIndicator = true; + private OnItemSelectListener mOnItemSelectListener; + + public WalletIndicatorAdapter(Context context, List charSequences) { + this.mContext = context; + this.mTitleList = charSequences; + } + + @Override + public int getCount() { + return mTitleList == null ? 0 : mTitleList.size(); + } + + @Override + public IPagerTitleView getTitleView(Context context, final int i) { + ScaleTransitionPagerTitleView scaleTransitionPagerTitleView = new ScaleTransitionPagerTitleView(context, true); + scaleTransitionPagerTitleView.setNormalColor(ContextCompat.getColor(context, R.color.color_7E8373)); + scaleTransitionPagerTitleView.setSelectedColor(ContextCompat.getColor(context, R.color.color_4E390A)); + scaleTransitionPagerTitleView.setMinScale(minScale); + scaleTransitionPagerTitleView.setTextSize(textSize); + int padding = UIUtil.dip2px(context, 37); + scaleTransitionPagerTitleView.setPadding(padding, 0, padding, 0); + scaleTransitionPagerTitleView.setText(mTitleList.get(i)); + scaleTransitionPagerTitleView.setOnClickListener(view -> { + if (mOnItemSelectListener != null) { + mOnItemSelectListener.onItemSelect(i, scaleTransitionPagerTitleView); + } + + }); + return scaleTransitionPagerTitleView; + } + + @Override + public IPagerIndicator getIndicator(Context context) { + LinePagerIndicator indicator = new LinePagerIndicator(context); + indicator.setMode(LinePagerIndicator.MODE_EXACTLY); + indicator.setLineHeight(UIUtil.dip2px(mContext, 1.5)); + indicator.setRoundRadius(UIUtil.dip2px(mContext, 1)); + indicator.setLineWidth(UIUtil.dip2px(mContext, 11)); + indicator.setColors(context.getResources().getColor(R.color.color_AA7400)); + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); +// lp.bottomMargin = mBottomMargin; + lp.gravity = Gravity.BOTTOM; + indicator.setLayoutParams(lp); + return indicator; + } + + public int getTextSize() { + return textSize; + } + + public void setTextSize(int textSize) { + this.textSize = textSize; + } + + public float getMinScale() { + return minScale; + } + + public void setMinScale(float minScale) { + this.minScale = minScale; + } + + public boolean isShowIndicator() { + return showIndicator; + } + + public void setShowIndicator(boolean showIndicator) { + this.showIndicator = showIndicator; + } + + public void setOnItemSelectListener(OnItemSelectListener onItemSelectListener) { + mOnItemSelectListener = onItemSelectListener; + } + + public interface OnItemSelectListener { + void onItemSelect(int position, TextView view); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/wallet/WalletViewModel.kt b/app/src/main/java/com/chwl/app/ui/wallet/WalletViewModel.kt new file mode 100644 index 0000000..093422b --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/wallet/WalletViewModel.kt @@ -0,0 +1,75 @@ +package com.chwl.app.ui.wallet + +import androidx.lifecycle.MutableLiveData +import com.chwl.app.base.BaseViewModel +import com.chwl.core.bean.response.BeanResult +import com.chwl.core.earn.bean.GoldToDiamondInfo +import com.chwl.core.earn.model.EarnModel +import com.chwl.core.pay.PayModel +import com.chwl.core.pay.bean.WalletInfo +import com.chwl.core.pay.event.GetWalletInfoEvent +import com.chwl.core.pay.event.UpdateWalletInfoEvent +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.functions.Consumer +import io.reactivex.schedulers.Schedulers +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode + +class WalletViewModel : BaseViewModel() { + + val walletInfoLiveData = MutableLiveData>() + + val convertInfoLiveData = MutableLiveData>() + + init { + EventBus.getDefault().register(this) + } + fun getWalletInfo() { + addDisposable( + PayModel.get().walletInfo + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(Consumer { walletInfo: WalletInfo? -> + walletInfoLiveData.postValue(BeanResult.success(walletInfo)) + }) { + walletInfoLiveData.postValue(BeanResult.failed(it)) + } + ) + } + + fun getConvertInfo() { + safeLaunch( + true, + onError = { + convertInfoLiveData.value = BeanResult.failed(it) + }, + block = { + val data = EarnModel.getGoldToDiamond() + convertInfoLiveData.value = BeanResult.success(data) + } + ) + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onWalletInfoUpdate(event: UpdateWalletInfoEvent?) { + loadLocalWalletInfo() + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onGetWalletInfoEvent(event: GetWalletInfoEvent?) { + loadLocalWalletInfo() + } + + private fun loadLocalWalletInfo() { + val info = PayModel.get().currentWalletInfo + if (info != null) { + walletInfoLiveData.value = BeanResult.success(info) + } + } + + override fun onCleared() { + super.onCleared() + EventBus.getDefault().unregister(this) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/wallet/payment/GPaymentClient.kt b/app/src/main/java/com/chwl/app/ui/wallet/payment/GPaymentClient.kt new file mode 100644 index 0000000..a91bdd9 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/wallet/payment/GPaymentClient.kt @@ -0,0 +1,285 @@ +package com.chwl.app.ui.wallet.payment + +import android.app.Activity +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleEventObserver +import androidx.lifecycle.LifecycleOwner +import com.chwl.app.R +import com.chwl.app.common.widget.dialog.DialogManager +import com.chwl.core.pay.PayModel +import com.chwl.core.pay.bean.PayRecordId +import com.chwl.library.utils.SingleToastUtil +import com.example.lib_utils.log.ILog +import com.example.module_base.support.billing.IBillingResult +import com.example.module_base.support.billing.IBillingService2 +import com.example.module_base.support.billing.IProductDetails +import com.example.module_base.support.billing.IPurchase +import com.example.module_base.support.billing.OnBillingClientStateListener +import com.example.module_base.support.billing.OnConsumeResponseListener +import com.example.module_base.support.billing.OnProductDetailsResponseListener +import com.example.module_base.support.billing.OnPurchasesResponseListener +import com.example.module_base.support.google.IGoogleService +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.disposables.Disposable + +class GPaymentClient(val activity: Activity) : IPaymentClient, IBillingService2.Listener, + OnProductDetailsResponseListener, LifecycleEventObserver, ILog, OnBillingClientStateListener { + + private var compositeDisposable: CompositeDisposable? = null + private var _billingService: IBillingService2? = null + private val dialogManager = DialogManager(activity) + + private var paymentIntent: PaymentIntent? = null + private var productItem: IProductDetails? = null + private var orderId: String? = null + + init { + dialogManager.setCanceledOnClickOutside(false) + dialogManager.setCanceledOnClickBackKey(false) + (activity as? LifecycleOwner)?.lifecycle?.addObserver(this) + } + + private fun getBillingService(): IBillingService2? { + if (_billingService == null) { + _billingService = IGoogleService.newBillingService2(activity, this) + _billingService?.setLogEnabled(true) + _billingService?.startConnection(this) + } + return _billingService + } + + override fun launchPayment(intent: PaymentIntent) { + logD("launchPayment() intent:${intent.productId}") + if (paymentIntent != null) { + SingleToastUtil.showToast(R.string.retryTips) + return + } + dialogManager.showProgressDialog(activity) + this.paymentIntent = intent + tryLaunch() + } + + private fun tryLaunch() { + val billingService = getBillingService() + if (billingService == null) { + callFailed( + IPaymentClient.CODE_NONSUPPORT, + PaymentException(activity.getString(R.string.bean_response_serviceresult_015)) + ) + return + } + val productId = paymentIntent?.productId + val productItem = productItem + logD("tryLaunch() productId:$productId productItem:$productItem") + if (productId == null) { + return + } + if (getBillingService()?.isServiceConnected() != true) { + logD("tryLaunch() isServiceConnected = false") + return + } + if (productItem == null) { + getBillingService()?.querySkuDetailsAsync(listOf(productId), this) + } else { + placeOrder(productItem) + } + } + + private fun placeOrder(productItem: IProductDetails) { + logD("placeOrder() productItem:${productItem.getProductId()}") + addDisposable(PayModel.get().placeOrder(productItem.getProductId()) + .subscribe( + { recordId: PayRecordId -> + if (paymentIntent?.productId == productItem.getProductId()) { + orderId = recordId.recordId + getBillingService()?.launchBillingFlow( + productItem, + recordId.recordId + ) + } else { + logE("placeOrder() 意图发生改变") + } + } + ) { throwable: Throwable -> + callFailed(IPaymentClient.CODE_PLACE_ORDER_FAILED, throwable) + }) + } + + override fun onBillingSetupFinished(billingResult: IBillingResult) { + if (billingResult.isResponseOk()) { + logD("onBillingClientSetupFinished()") + getBillingService()?.queryPurchases(object : OnPurchasesResponseListener { + override fun onQueryPurchasesResponse( + billingResult: IBillingResult, + purchases: List + ) { + if (billingResult.isResponseOk() && purchases.isNotEmpty()) { + purchases.forEach { + handlePurchases(false, it) + } + } + } + }) + tryLaunch() + } else { + callFailed( + IPaymentClient.CODE_UNAVAILABLE, billingResult + ) + } + } + + override fun onPurchasesUpdated(billingResult: IBillingResult, purchases: List?) { + logD("onPurchasesUpdated() billingResult:${billingResult.getResponseCode()} purchases:${purchases?.size}") + if (billingResult.isResponseOk() && !purchases.isNullOrEmpty()) { + purchases.forEach { + handlePurchases(true, it) + } + } else { + callFailed(IPaymentClient.CODE_PURCHASE_FAILED, billingResult) + } + } + + private fun handlePurchases(isCurrentPaying: Boolean, purchases: IPurchase) { + logD("handlePurchases isCurrentPaying:${isCurrentPaying} state:${purchases.getPurchaseState()}") + val identifiers = purchases.getAccountIdentifiers() + if (purchases.isPurchasedState() && identifiers != null) { + logD("handlePurchases() verifyOrder") + addDisposable( + PayModel.get().verifyOrder( + identifiers.getObfuscatedAccountId(), + purchases.getProducts().firstOrNull(), + purchases.getPackageName(), + purchases.getPurchaseToken() + ).subscribe({ + logD("handlePurchases() verifyOrder consumeAsync") + consumeAsync(isCurrentPaying, it) + }, { + logD("handlePurchases() error:${it.message}") + if (isCurrentPaying) { + callFailed(IPaymentClient.CODE_VERIFY_ORDER_FAILED, it) + } + }) + ) + } + } + + private fun consumeAsync(isCurrentPaying: Boolean, token: String) { + logD("consumeAsync() isCurrentPaying:${isCurrentPaying} token:$token") + getBillingService()?.consumeAsync(token, object : OnConsumeResponseListener { + override fun onConsumeResponse(billingResult: IBillingResult, purchaseToken: String) { + logD("consumeAsync() onConsumeResponse billingResult:${billingResult} purchaseToken:$purchaseToken") + if (isCurrentPaying) { + if (billingResult.isResponseOk()) { + val orderId = orderId + if (orderId != null) { + callSuccess(orderId) + } + } else { + callFailed(IPaymentClient.CODE_CONSUME_ORDER_FAILED, billingResult) + } + } + } + }) + } + + override fun onProductDetailsResponse( + billingResult: IBillingResult, + productDetails: List + ) { + logD("onProductDetailsResponse() billingResult:${billingResult.getResponseCode()} productDetails:${productDetails.size}") + if (billingResult.isResponseOk()) { + val item = productDetails.firstOrNull { + it.getProductId() == paymentIntent?.productId + } + productItem = item + if (item != null) { + tryLaunch() + } else { + callFailed(IPaymentClient.CODE_PRODUCT_NOT_FOUND, billingResult) + } + } else { + callFailed(IPaymentClient.CODE_PRODUCT_NOT_FOUND, billingResult) + } + } + + private fun callSuccess(orderRecordId: String) { + logD("callSuccess() orderRecordId:${orderRecordId} productId:${paymentIntent?.productId}") + paymentIntent?.let { + it.listener.onResponse(PaymentResult.PaymentSuccess(it.productId, orderRecordId)) + } + paymentIntent = null + dialogManager.dismissDialog() + } + + private fun callFailed(code: Int) { + callFailed( + code, + PaymentException( + code, + message = activity.getString(R.string.common_operation_prompt_format).format(code) + ) + ) + } + + private fun callFailed(code: Int, billingResult: IBillingResult) { + callFailed( + code, + PaymentException( + code, + message = activity.getString(R.string.common_operation_prompt_format) + .format("$code-${billingResult.getResponseCode()}") + ) + ) + } + + private fun callFailed(code: Int, throwable: Throwable) { + throwable.printStackTrace() + logD("callFailed() code:${code} throwable:${throwable.message}") + throwable.let { + SingleToastUtil.showToast( + it.message + ) + } + paymentIntent?.let { + it.listener.onResponse(PaymentResult.PaymentFailed(it.productId, code, throwable)) + } + paymentIntent = null + dialogManager.dismissDialog() + } + + private fun getCompositeDisposable(): CompositeDisposable { + var disposable = compositeDisposable + if (disposable == null) { + disposable = CompositeDisposable() + compositeDisposable = disposable + } + return disposable + } + + private fun addDisposable(disposable: Disposable) { + getCompositeDisposable().add(disposable) + } + + override fun onCleared() { + logD("onCleared()") + _billingService?.destroy() + paymentIntent = null + compositeDisposable?.dispose() + compositeDisposable = null + dialogManager.dismissDialog() + } + + override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) { + logD("onStateChanged() event:$event") + when (event) { + Lifecycle.Event.ON_DESTROY -> { + (activity as? LifecycleOwner)?.lifecycle?.removeObserver(this) + onCleared() + } + + else -> { + + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/wallet/payment/IPaymentClient.kt b/app/src/main/java/com/chwl/app/ui/wallet/payment/IPaymentClient.kt new file mode 100644 index 0000000..0dcbef5 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/wallet/payment/IPaymentClient.kt @@ -0,0 +1,42 @@ +package com.chwl.app.ui.wallet.payment + +import com.example.lib_utils.ICleared + +interface IPaymentClient : ICleared { + companion object { + // 支付成功 + const val CODE_SUCCESS = 200 + + // 未知异常原因 + const val CODE_OTHER = 0 + + // 不支持该功能 + const val CODE_NONSUPPORT = 1 + + // 服务暂不可用 + const val CODE_UNAVAILABLE = 2 + + // 未查询到购买信息 + const val CODE_PRODUCT_NOT_FOUND = 3 + + // 预下单失败 + const val CODE_PLACE_ORDER_FAILED = 4 + + // 购买失败 + const val CODE_PURCHASE_FAILED = 5 + + // 验证订单失败 + const val CODE_VERIFY_ORDER_FAILED = 6 + + // 核消订单失败 + const val CODE_CONSUME_ORDER_FAILED = 7 + } + + fun launchPayment(intent: PaymentIntent) + + override fun onCleared() + + interface Listener { + fun onResponse(result: PaymentResult) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/wallet/payment/PaymentException.kt b/app/src/main/java/com/chwl/app/ui/wallet/payment/PaymentException.kt new file mode 100644 index 0000000..da7d1b4 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/wallet/payment/PaymentException.kt @@ -0,0 +1,13 @@ +package com.chwl.app.ui.wallet.payment + +import androidx.annotation.Keep + +@Keep +class PaymentException : Exception { + var code = 0 + + constructor(message: String) : super(message) + constructor(code: Int, message: String) : super(message) { + this.code = code + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/wallet/payment/PaymentIntent.kt b/app/src/main/java/com/chwl/app/ui/wallet/payment/PaymentIntent.kt new file mode 100644 index 0000000..3891166 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/wallet/payment/PaymentIntent.kt @@ -0,0 +1,4 @@ +package com.chwl.app.ui.wallet.payment + +class PaymentIntent(val productId: String, val listener: IPaymentClient.Listener) { +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/wallet/payment/PaymentResult.kt b/app/src/main/java/com/chwl/app/ui/wallet/payment/PaymentResult.kt new file mode 100644 index 0000000..8398690 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/wallet/payment/PaymentResult.kt @@ -0,0 +1,12 @@ +package com.chwl.app.ui.wallet.payment + +sealed class PaymentResult { + + data class PaymentSuccess(val productId: String, val orderId: String) : PaymentResult() + + data class PaymentFailed( + val productId: String, + val code: Int, + val exception: Throwable? = null + ) : PaymentResult() +} diff --git a/app/src/main/java/com/chwl/app/ui/webview/CommonWebViewActivity.java b/app/src/main/java/com/chwl/app/ui/webview/CommonWebViewActivity.java new file mode 100644 index 0000000..9102de8 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/webview/CommonWebViewActivity.java @@ -0,0 +1,485 @@ +package com.chwl.app.ui.webview; + +import android.annotation.SuppressLint; +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.ActivityNotFoundException; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.graphics.Bitmap; +import android.net.Uri; +import android.net.http.SslError; +import android.os.Build; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; +import android.webkit.SslErrorHandler; +import android.webkit.ValueCallback; +import android.webkit.WebBackForwardList; +import android.webkit.WebChromeClient; +import android.webkit.WebSettings; +import android.webkit.WebView; +import android.webkit.WebViewClient; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.TextView; + +import androidx.annotation.LayoutRes; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AlertDialog; + +import com.chwl.app.R; +import com.chwl.app.application.App; +import com.chwl.app.base.BaseActivity; +import com.chwl.app.ui.im.RouterHandler; +import com.chwl.app.ui.webview.event.ShowNavEvent; +import com.chwl.app.ui.webview.event.TaroPayResultEvent; +import com.chwl.app.utils.WebViewUtils; +import com.chwl.core.Constants; +import com.chwl.core.UriProvider; +import com.chwl.core.certification.event.CertificationResultEvent; +import com.chwl.core.web.bean.WebJsBeanInfo; +import com.chwl.core.web.event.WebViewRefreshEvent; +import com.chwl.library.rxbus.RxBus; +import com.chwl.library.utils.ResUtil; +import com.google.gson.Gson; +import com.netease.nim.uikit.StatusBarUtil; +import com.netease.nim.uikit.common.util.log.LogUtil; +import com.netease.nim.uikit.common.util.string.StringUtil; +import com.orhanobut.logger.Logger; +import com.trello.rxlifecycle3.android.ActivityEvent; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.HashMap; +import java.util.Map; + +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; + + +/** + * @author Administrator + */ +public class CommonWebViewActivity extends BaseActivity { + + protected FrameLayout layoutTitleBar; + protected WebView webView; + private ProgressBar mProgressBar; + private CommonWebViewActivity mActivity; + private WebChromeClient wvcc; + private ImageView imgShare; + private TextView mTvRightText; + private ImageView mIvBack; + private ImageView mIvClose; + private TextView mTitle; + + private WebJsBeanInfo mWebJsBeanInfo; + private String url; + private String from; + private String targetUrl; + + private ValueCallback mUploadMessage; + private ValueCallback mUploadMessage5; + public static final int FILECHOOSER_RESULTCODE = 5173; + public static final int FILECHOOSER_RESULTCODE_FOR_ANDROID_5 = 5174; + + private static final String POSITION = "position"; + private int mPosition; + + private JSInterface jsInterface; + + public static void start(Context context, String url) { + Intent intent = new Intent(context, CommonWebViewActivity.class); + intent.putExtra("url", url); + context.startActivity(intent); + } + + /** + * 排行榜专用 + */ + public static void start(Context context, String url, int position) { + Intent intent = new Intent(context, CommonWebViewActivity.class); + intent.putExtra("url", url); + intent.putExtra(POSITION, position); + context.startActivity(intent); + } + + /** + * webView 某些h5 功能页面 需要在h5 使用结束后做一些操作 + * + * @param context + * @param url + * @param callBack 回调 + */ + public static void start(Context context, String url, WebViewCallBack callBack) { + Intent intent = new Intent(context, CommonWebViewActivity.class); + intent.putExtra("url", url); + context.startActivity(intent); + webViewCallBack = callBack; + } + + @SuppressLint("CheckResult") + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + this.initBefore(savedInstanceState); + setContentView(getLayoutId()); + Intent intent = getIntent(); + url = intent.getStringExtra("url"); + from = intent.getStringExtra("from"); + mPosition = intent.getIntExtra(POSITION, 0) + 1; + mActivity = this; + initView(); + initData(); + setListener(); + showWebView(url); + RxBus.get().toFlowable(ShareH5Event.class) + .compose(bindUntilEvent(ActivityEvent.DESTROY)) + .subscribeOn(Schedulers.newThread()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(shareH5Event -> { + WebJsBeanInfo webJsBeanInfo = shareH5Event.getWebJsBeanInfo(); + if (webJsBeanInfo != null) { + if (App.isDebug()) { + toast("WebJsBeanInfo->" + new Gson().toJson(webJsBeanInfo)); + } + mWebJsBeanInfo = webJsBeanInfo; + showMenu(webJsBeanInfo.getData()); + } + }); + EventBus.getDefault().register(this); + } + + /** + * 该方法是在onCreate()方法里执行,在setContentView()方法被调用之前触发,可用于处理解析Activity#getIntent()中的数据时的场景 + */ + protected void initBefore(@Nullable Bundle savedInstanceState) { + + } + + @LayoutRes + protected int getLayoutId() { + return R.layout.activity_common_web_view; + } + + private void setListener() { + imgShare.setOnClickListener(v -> { + }); + + mIvBack.setOnClickListener(v -> { + if (webView.canGoBack()) { + webView.goBack(); + } else { + finish(); + } + }); + + mIvClose.setOnClickListener(v -> { + finish(); + }); + } + + @SuppressLint("SetJavaScriptEnabled") + private void initData() { + webView.getSettings().setJavaScriptEnabled(true); + webView.getSettings().setUseWideViewPort(true); + webView.getSettings().setLoadWithOverviewMode(true); + webView.getSettings().setDomStorageEnabled(true); + // 设置 WebView 可以在 HTTPS 通道上加载 HTTP 资源,Android 4.4 后的暗坑 + // 因为 Android 4.4 后默认不允许在 HTTPS 通道上加载 HTTP 资源 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + webView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE); + } + webView.getSettings().setTextZoom(100); + jsInterface = new JSInterface(webView, this); + jsInterface.setPosition(mPosition); + webView.addJavascriptInterface(jsInterface, "androidJsObj"); + webView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE); + webView.setWebViewClient(new WebViewClient() { + + + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + Logger.e("WebViewClient shouldOverrideUrlLoading--------" + url); + LogUtil.e("shouldOverrideUrlLoading" + url); + targetUrl = url; + + if (url.contains("tel:")) { + //删除直接拨打电话的功能 + return true; + } + // ------- 处理结束 ------- + + if (!(url.startsWith("http") || url.startsWith("https"))) { + return true; + } + + view.loadUrl(url); + return true; + } + + @Override + public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { + // super.onReceivedSslError(view, handler, error); + androidx.appcompat.app.AlertDialog.Builder builder = new androidx.appcompat.app.AlertDialog.Builder(view.getContext()); + builder.setMessage(ResUtil.getString(R.string.ui_webview_commonwebviewactivity_07)); + builder.setPositiveButton(ResUtil.getString(R.string.ui_webview_commonwebviewactivity_08), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + handler.proceed();// 接受https所有网站的证书 + } + }); + + builder.setNegativeButton(ResUtil.getString(R.string.ui_webview_commonwebviewactivity_09), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + handler.cancel(); + } + }); + + AlertDialog dialog = builder.create(); + dialog.show(); + } + + @Override + public void onPageFinished(WebView view, String url) { + Logger.e("WebViewClient onPageFinished--------" + url); + mProgressBar.setProgress(100); + mProgressBar.setVisibility(View.GONE); + super.onPageFinished(view, url); + } + + @Override + public void onPageStarted(WebView view, String url, Bitmap favicon) { + Logger.e("WebViewClient onPageStarted--------" + url); + super.onPageStarted(view, url, favicon); + mProgressBar.setVisibility(View.VISIBLE); + } + }); + //获取webviewtitle作为titlebar的title + wvcc = new WebChromeClient() { + @Override + public void onProgressChanged(WebView view, int newProgress) { + super.onProgressChanged(view, newProgress); + mProgressBar.setProgress(newProgress); + } + + @Override + public void onReceivedTitle(WebView view, String title) { + super.onReceivedTitle(view, title); + mTitle.setText(title + ""); + } + + // For Android >= 4.1 + public void openFileChooser(ValueCallback uploadMsg, + String acceptType, String capture) { + mUploadMessage = uploadMsg; + Intent i = new Intent(Intent.ACTION_GET_CONTENT); + i.addCategory(Intent.CATEGORY_OPENABLE); + i.setType("*/*"); + startActivityForResult(Intent.createChooser(i, "File Browser"), + FILECHOOSER_RESULTCODE); + } + + //xxx 接收 webView 的 標籤的 文件選擇 + // For Lollipop 5.0+ Devices + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + public boolean onShowFileChooser(WebView mWebView, + ValueCallback filePathCallback, + FileChooserParams fileChooserParams) { + if (mUploadMessage5 != null) { + mUploadMessage5.onReceiveValue(null); + mUploadMessage5 = null; + } + mUploadMessage5 = filePathCallback; + Intent intent = fileChooserParams.createIntent(); + try { + startActivityForResult(intent, + FILECHOOSER_RESULTCODE_FOR_ANDROID_5); + } catch (ActivityNotFoundException e) { + mUploadMessage5 = null; + return false; + } + return true; + } + + }; + // 设置setWebChromeClient对象 + webView.setWebChromeClient(wvcc); + // 设置Webview的user-agent + webView.getSettings().setUserAgentString(webView.getSettings().getUserAgentString() + " molistarAppAndroid"); + } + + private void onGotoAppFinish(WebView view) { + // 跳转成功或失败与否,都重新回到最后打开的App内非第三方网页 + view.post(() -> { + if (from != null && from.equals("xplan_flutter")) { + finish(); + return; + } + WebBackForwardList list = view.copyBackForwardList(); + final int length = list.getSize(); + int steps = 1; + for (int i = length - 1; i >= 0; i--) { + String lastUrl = list.getItemAtIndex(i).getUrl(); + steps--; + if (lastUrl != null && lastUrl.startsWith(UriProvider.JAVA_WEB_URL)) { + view.goBackOrForward(steps); + break; + } + } + }); + } + + @SuppressLint("NewApi") + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent intent) { + super.onActivityResult(requestCode, resultCode, intent); + if (requestCode == FILECHOOSER_RESULTCODE) { + if (null == mUploadMessage) { + return; + } + Uri result = intent == null || resultCode != Activity.RESULT_OK ? null + : intent.getData(); + mUploadMessage.onReceiveValue(result); + mUploadMessage = null; + } else if (requestCode == FILECHOOSER_RESULTCODE_FOR_ANDROID_5) { + if (null == mUploadMessage5) { + return; + } + mUploadMessage5.onReceiveValue(WebChromeClient.FileChooserParams + .parseResult(resultCode, intent)); + mUploadMessage5 = null; + } + } + + private void initView() { + layoutTitleBar = findViewById(R.id.layout_title_bar); + webView = (WebView) findViewById(R.id.webview); + imgShare = (ImageView) findViewById(R.id.img_share); + mProgressBar = (ProgressBar) findViewById(R.id.progress_bar); + mTvRightText = (TextView) findViewById(R.id.tv_title_right); + + mIvBack = findViewById(R.id.iv_back); + mIvClose = findViewById(R.id.iv_close); + mTitle = findViewById(R.id.tv_title); + } + + private void showMenu(WebJsBeanInfo.DataBean data) { + switch (mWebJsBeanInfo.getType()) { + case WebJsBeanInfo.TEXT: + mTvRightText.setVisibility(View.VISIBLE); + mTvRightText.setText(data.getTitle()); + mTvRightText.setOnClickListener(v -> webView.loadUrl(data.getLink())); + break; + case WebJsBeanInfo.SHARE: + imgShare.setVisibility(View.VISIBLE); + break; + case WebJsBeanInfo.JUMP_APP_PAGE: + mTvRightText.setVisibility(View.VISIBLE); + mTvRightText.setText(data.getTitle()); + mTvRightText.setOnClickListener(v -> + RouterHandler.handle(this, data.getRouterType(), data.getRouterVal())); + break; + case WebJsBeanInfo.RESET_UI: + imgShare.setVisibility(View.GONE); + mTvRightText.setText(""); + mTvRightText.setVisibility(View.GONE); + break; + default: + } + } + + public void showWebView(String url) { + Logger.d("ShowWebView--------" + url); + if (!TextUtils.isEmpty(url)) { + Map map = new HashMap<>(); + map.put("Referer", Constants.WXPAY_REFERER); + webView.loadUrl(url, map); + } else { + toast(ResUtil.getString(R.string.ui_webview_commonwebviewactivity_010)); + finish(); + } + } + + @Override + public void onBackPressed() { + if (webView.canGoBack()) { + if (!TextUtils.isEmpty(targetUrl) && targetUrl.contains("modules/nobles/paySuccess.html")) { + finish(); + } else + webView.goBack(); + } else { + this.finish(); + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onRecieveNeedRefreshWebView(WebViewRefreshEvent event) { + if (!StringUtil.isEmpty(url)) { + showWebView(url); + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void handleCertificationResultEvent(CertificationResultEvent event) { + webView.evaluateJavascript("renderByStatus(" + event.getStatus() + ")", null); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void showNavEvent(ShowNavEvent event) { + if (event != null) { + // true为显示,false为关闭 + if (event.isShowNav()) { + layoutTitleBar.setVisibility(View.VISIBLE); + } else { + layoutTitleBar.setVisibility(View.GONE); + } + } + } + + @Override + protected void onDestroy() { + if (jsInterface != null) { + jsInterface.onCleared(); + } + EventBus.getDefault().unregister(this); + + if (webViewCallBack != null) { + webViewCallBack.onResult(""); + webViewCallBack = null; + } + super.onDestroy(); + WebViewUtils.releaseWeb(webView); + } + + private static WebViewCallBack webViewCallBack; + + public interface WebViewCallBack { + void onResult(String str); + } + + @Override + protected boolean needSteepStateBar() { + return true; + } + + @Override + protected void setStatusBar() { + super.setStatusBar(); + StatusBarUtil.transparencyBar(this); + StatusBarUtil.StatusBarLightMode(this); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onTaroPayResultEvent(TaroPayResultEvent event) { + if (webView != null) { + webView.evaluateJavascript("taroPayResultCallback(" + event.getResult() + ")", null); + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/webview/CommonWebViewFragment.java b/app/src/main/java/com/chwl/app/ui/webview/CommonWebViewFragment.java new file mode 100644 index 0000000..a327d72 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/webview/CommonWebViewFragment.java @@ -0,0 +1,122 @@ +package com.chwl.app.ui.webview; + +import android.content.DialogInterface; +import android.net.http.SslError; +import android.os.Build; +import android.text.TextUtils; +import android.webkit.SslErrorHandler; +import android.webkit.WebSettings; +import android.webkit.WebView; +import android.webkit.WebViewClient; + +import androidx.appcompat.app.AlertDialog; + +import com.orhanobut.logger.Logger; +import com.chwl.app.R; +import com.chwl.app.base.BaseBindingFragment; +import com.chwl.app.databinding.FragmentCommonWebViewBinding; +import com.chwl.library.annatation.ActLayoutRes; +import com.chwl.library.utils.ResUtil; + +@ActLayoutRes(R.layout.fragment_common_web_view) +public class CommonWebViewFragment extends BaseBindingFragment { + + private WebView webView; + protected String url; + private JSInterface jsInterface; + + @Override + public void initiate() { + webView.getSettings().setJavaScriptEnabled(true); + webView.getSettings().setUseWideViewPort(true); + // 设置 WebView 可以在 HTTPS 通道上加载 HTTP 资源,Android 4.4 后的暗坑 + // 因为 Android 4.4 后默认不允许在 HTTPS 通道上加载 HTTP 资源 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + webView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE); + } + webView.getSettings().setTextZoom(100); + jsInterface = new JSInterface(webView, getActivity()); + webView.addJavascriptInterface(jsInterface, "androidJsObj"); + webView.setWebViewClient(new WebViewClient() { + + + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + Logger.e("shouldOverrideUrlLoading--------" + url); + //modules/noble/paySuccess.html + //modules/noble/order.html?nobleIndex=1 // 获取上下文, H5PayDemoActivity为当前页面 + if (url.contains("tel:")) { + //删除直接拨打电话的功能 + return true; + } + // ------- 处理结束 ------- + + if (!(url.startsWith("http") || url.startsWith("https"))) { + return true; + } + + view.loadUrl(url); + return true; + } + + @Override + public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { + // super.onReceivedSslError(view, handler, error); + AlertDialog.Builder builder = new AlertDialog.Builder(view.getContext()); + builder.setMessage(ResUtil.getString(R.string.ui_webview_commonwebviewfragment_04)); + builder.setPositiveButton(ResUtil.getString(R.string.ui_webview_commonwebviewfragment_05), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + handler.proceed();// 接受https所有网站的证书 + } + }); + + builder.setNegativeButton(ResUtil.getString(R.string.ui_webview_commonwebviewfragment_06), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + handler.cancel(); + } + }); + + AlertDialog dialog = builder.create(); + dialog.show(); + } + + @Override + public void onPageFinished(WebView view, String url) { + Logger.e("onPageFinished--------" + url); + super.onPageFinished(view, url); + } + }); + // 设置Webview的user-agent + webView.getSettings().setUserAgentString(webView.getSettings().getUserAgentString() + " molistarAppAndroid"); + } + + @Override + public void onFindViews() { + super.onFindViews(); + webView = mBinding.webview; + } + + public void ShowWebView(String url) { + webView.loadUrl(url); + + } + + @Override + public void onResume() { + super.onResume(); + if (!TextUtils.isEmpty(url)) { + // 强制每次点到这个 tab 的时候就刷新数据 + ShowWebView(url); + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (jsInterface != null) { + jsInterface.onCleared(); + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/webview/DatingRuleWebViewActivity.java b/app/src/main/java/com/chwl/app/ui/webview/DatingRuleWebViewActivity.java new file mode 100644 index 0000000..e3da35b --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/webview/DatingRuleWebViewActivity.java @@ -0,0 +1,32 @@ +package com.chwl.app.ui.webview; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.view.Gravity; +import android.view.WindowManager; + +import com.netease.nim.uikit.common.util.sys.ScreenUtil; +import com.chwl.app.R; + + +public class DatingRuleWebViewActivity extends CommonWebViewActivity { + + public static void start(Context context, String url) { + Intent intent = new Intent(context, DatingRuleWebViewActivity.class); + intent.putExtra("url", url); + context.startActivity(intent); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT, ScreenUtil.getDisplayHeight()); + getWindow().setGravity(Gravity.CENTER); + } + + @Override + protected int getLayoutId() { + return R.layout.activity_dating_rule_web_view; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/webview/DialogWebViewActivity.java b/app/src/main/java/com/chwl/app/ui/webview/DialogWebViewActivity.java new file mode 100644 index 0000000..c207cda --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/webview/DialogWebViewActivity.java @@ -0,0 +1,71 @@ +package com.chwl.app.ui.webview; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; + +import com.chwl.app.R; +import com.netease.nim.uikit.common.util.sys.ScreenUtil; + +//xxx 半屏 Web +public class DialogWebViewActivity extends CommonWebViewActivity { + + private boolean showTitleBar; + + public static void start(Context context, String url) { + start(context, url, true); + } + + public static void start(Context context, String url, boolean showTitleBar) { + Intent intent = new Intent(context, DialogWebViewActivity.class); + intent.putExtra("url", url); + intent.putExtra("showTitleBar", showTitleBar); + context.startActivity(intent); + } + + public static void start(Context context, String url, boolean showTitleBar,int height) { + Intent intent = new Intent(context, DialogWebViewActivity.class); + intent.putExtra("url", url); + intent.putExtra("showTitleBar", showTitleBar); + intent.putExtra("height", height); + context.startActivity(intent); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getWindow().getDecorView().setSystemUiVisibility( + View.SYSTEM_UI_FLAG_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY + ); + getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT); + View topView = findViewById(R.id.v_top); + topView.setOnClickListener(v -> finish()); + ViewGroup.LayoutParams params = topView.getLayoutParams(); + int height = getIntent().getIntExtra("height", 0); + if (height > 0) { + params.height = height; + } else { + params.height = getTopMargin(); + } + topView.setLayoutParams(params); + showTitleBar = getIntent().getBooleanExtra("showTitleBar", true); + if (!showTitleBar) { + layoutTitleBar.setVisibility(View.GONE); + } + } + + @Override + protected int getLayoutId() { + return R.layout.activity_dialog_web_view; + } + + protected int getTopMargin() { + return ScreenUtil.screenHeight / 3; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/webview/DialogWebViewCenterActivity.java b/app/src/main/java/com/chwl/app/ui/webview/DialogWebViewCenterActivity.java new file mode 100644 index 0000000..58a7ff5 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/webview/DialogWebViewCenterActivity.java @@ -0,0 +1,99 @@ +package com.chwl.app.ui.webview; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.webkit.WebView; + +import com.chwl.app.R; +import com.chwl.library.common.util.OtherExtKt; +import com.netease.nim.uikit.common.util.sys.ScreenUtil; + +//xxx 居中透明 Web +public class DialogWebViewCenterActivity extends CommonWebViewActivity { + + public static int T_FIRST_RECHARNGE_INDEX = 1; + + private boolean showTitleBar; + + public static void start(Context context, String url) { + start(context, url, false); + } + + public static void start(Context context, String url, boolean showTitleBar) { + Intent intent = new Intent(context, DialogWebViewCenterActivity.class); + intent.putExtra("url", url); + intent.putExtra("showTitleBar", showTitleBar); + context.startActivity(intent); + } + + public static void start(Context context, String url, boolean showTitleBar,int height,int margin,int type) { + Intent intent = new Intent(context, DialogWebViewCenterActivity.class); + intent.putExtra("url", url); + intent.putExtra("showTitleBar", showTitleBar); + intent.putExtra("height", height); + intent.putExtra("margin", margin); + intent.putExtra("type", type); + context.startActivity(intent); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getWindow().getDecorView().setSystemUiVisibility( + View.SYSTEM_UI_FLAG_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY + ); + getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT); + WebView view = findViewById(R.id.webview); + view.setOnClickListener(v -> finish()); + ViewGroup.LayoutParams params = view.getLayoutParams(); + int height = getIntent().getIntExtra("height", 0); + int margin = getIntent().getIntExtra("margin", 0); + if (height > 0) { + params.height = height; + } else { + params.height = getTopMargin(); + } + view.setLayoutParams(params); + OtherExtKt.setMargin(view,margin,0,margin,0,false); + //设置webview背景透明,默认为⽩⾊ + view.setBackgroundColor(0); + //设置view背景透明,默认为⽩⾊ 可选(单独activity添加webView组件时需要添加) + view.setBackgroundColor(0); + showTitleBar = getIntent().getBooleanExtra("showTitleBar", true); + if (!showTitleBar) { + layoutTitleBar.setVisibility(View.GONE); + } + + int type = getIntent().getIntExtra("type", 0); + if (T_FIRST_RECHARNGE_INDEX == type){ + View root = findViewById(R.id.root); + if (root != null) { + root.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); + root.postDelayed(() -> { + finish(); + },3000); + } + } + } + + @Override + protected int getLayoutId() { + return R.layout.activity_dialog_web_view; + } + + protected int getTopMargin() { + return ScreenUtil.screenHeight / 2; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/webview/FairyDialogWebViewActivity.java b/app/src/main/java/com/chwl/app/ui/webview/FairyDialogWebViewActivity.java new file mode 100644 index 0000000..ede0681 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/webview/FairyDialogWebViewActivity.java @@ -0,0 +1,55 @@ +package com.chwl.app.ui.webview; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.os.Build; +import android.os.Bundle; +import android.view.Gravity; +import android.view.View; +import android.view.WindowManager; +import android.widget.FrameLayout; + +import androidx.annotation.Nullable; + +import com.netease.nim.uikit.common.util.sys.ScreenUtil; +import com.chwl.app.R; + +public class FairyDialogWebViewActivity extends CommonWebViewActivity { + + + public static void start(Context context, String url) { + Intent intent = new Intent(context, FairyDialogWebViewActivity.class); + intent.putExtra("url", url); + context.startActivity(intent); + } + + @Override + protected void initBefore(@Nullable Bundle savedInstanceState) { + super.initBefore(savedInstanceState); + //适配8.0和8.1不能同时设置屏幕固定方向和透明窗口背景的问题 + if (Build.VERSION.SDK_INT != Build.VERSION_CODES.O && Build.VERSION.SDK_INT != Build.VERSION_CODES.O_MR1) { + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT, ScreenUtil.screenHeight - ScreenUtil.getStatusBarHeight(this)); + getWindow().setGravity(Gravity.BOTTOM); + View layoutRoot = findViewById(R.id.ll_root); + FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) layoutRoot.getLayoutParams(); + layoutParams.height = ScreenUtil.screenWidth * 1245 / 750; + layoutParams.width = FrameLayout.LayoutParams.MATCH_PARENT; + layoutRoot.setLayoutParams(layoutParams); + layoutTitleBar.setVisibility(View.GONE); + webView.setBackgroundColor(0); + webView.getBackground().setAlpha(0); + } + + @Override + protected int getLayoutId() { + return R.layout.activity_elf_dialog_web_view; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/webview/JSInterface.java b/app/src/main/java/com/chwl/app/ui/webview/JSInterface.java new file mode 100644 index 0000000..c6789d5 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/webview/JSInterface.java @@ -0,0 +1,663 @@ +package com.chwl.app.ui.webview; + +import static android.content.Context.CLIPBOARD_SERVICE; + +import android.app.Activity; +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; +import android.os.Build; +import android.os.Looper; +import android.text.TextUtils; +import android.util.Log; +import android.webkit.JavascriptInterface; +import android.webkit.WebView; + +import androidx.annotation.NonNull; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.chwl.app.UIHelper; +import com.chwl.app.application.IReportConstants; +import com.chwl.app.application.ReportManager; +import com.chwl.app.avroom.activity.AVRoomActivity; +import com.chwl.app.earn.activity.EarnRecordActivity; +import com.chwl.app.ui.im.RouterHandler; +import com.chwl.app.ui.im.avtivity.NimP2PMessageActivity; +import com.chwl.app.ui.invite.InviteImageHelper; +import com.chwl.app.ui.invite.ShareInviteDialog; +import com.chwl.app.ui.invite.ShareInviteInfo; +import com.chwl.app.ui.pay.ChargeActivity; +import com.chwl.app.ui.wallet.payment.GPaymentClient; +import com.chwl.app.ui.wallet.payment.IPaymentClient; +import com.chwl.app.ui.wallet.payment.PaymentIntent; +import com.chwl.app.ui.wallet.payment.PaymentResult; +import com.chwl.app.ui.webview.event.H5NotifyClientEvent; +import com.chwl.app.ui.webview.event.ShowNavEvent; +import com.chwl.app.ui.webview.event.TaroPayResultEvent; +import com.chwl.app.utils.ShareManager; +import com.chwl.core.XConstants; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.decoration.bean.DecorationStoreRouterType; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.market_verify.MarketVerifyModel; +import com.chwl.core.pay.PayModel; +import com.chwl.core.pay.bean.WalletInfo; +import com.chwl.core.praise.PraiseModel; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.core.user.UserModel; +import com.chwl.core.web.bean.WebJsBeanInfo; +import com.chwl.library.common.util.DeviceUtil; +import com.chwl.library.language.LanguageHelper; +import com.chwl.library.rxbus.RxBus; +import com.chwl.library.utils.AppMetaDataUtil; +import com.chwl.library.utils.DeviceUuidFactory; +import com.chwl.library.utils.SystemUtils; +import com.chwl.library.utils.VersionUtil; +import com.chwl.library.utils.config.BasicConfig; +import com.chwl.library.utils.json.JsonUtils; +import com.example.lib_utils.ICleared; +import com.google.gson.Gson; +import com.netease.nim.uikit.common.util.log.LogUtil; +import com.orhanobut.logger.Logger; + +import org.greenrobot.eventbus.EventBus; + +import java.util.HashMap; + +/** + *

html js 与webview 交互接口

+ * Created by ${user} on 2017/11/6. + */ +public class JSInterface implements ICleared { + private static final String TAG = JSInterface.class.getSimpleName(); + private WebView mWebView; + private CommonWebViewActivity mActivity; + private Context context; + private int mPosition; +// private MediaRecorder recorder; +// private File myRecAudioFile; +// private ExtAudioRecorder extAudioRecorder; + private GPaymentClient paymentClient; + + private Activity mVerifyActivity; + + public JSInterface(WebView webView, CommonWebViewActivity activity) { + mWebView = webView; + mActivity = activity; + context = activity; + } + + public JSInterface(WebView webView, Context context) { + mWebView = webView; + this.context = context; + } + + private void loadUrl(String url) { + com.example.lib_utils.log.LogUtil.d("JSInterface", "loadUrl url:" + url, false); + if (Looper.myLooper() == Looper.getMainLooper()) { + if (mWebView != null) { + mWebView.loadUrl(url); + } + } else { + if (mActivity != null) { + mActivity.runOnUiThread(() -> { + if (mWebView != null) { + mWebView.loadUrl(url); + } + }); + } + } + } + + private void callJsWithJson(String name, Object params) { + if (name == null) { + return; + } + if (params != null) { + String jsonStr = JsonUtils.toJson(params); + loadUrl("javascript:" + name + "(" + jsonStr + ")"); + } else { + loadUrl("javascript:" + name + "()"); + } + } + + /** + * 拉起本地支付 + */ + @JavascriptInterface + public void openPayment(String productId) { + com.example.lib_utils.log.LogUtil.d("JSInterface", "openPayment productId:" + productId, false); + if (mActivity == null || TextUtils.isEmpty(productId)) { + return; + } + mActivity.runOnUiThread(() -> { + if (paymentClient == null) { + paymentClient = new GPaymentClient(mActivity); + } + PaymentIntent paymentIntent = new PaymentIntent(productId, new IPaymentClient.Listener() { + @Override + public void onResponse(@NonNull PaymentResult result) { + HashMap map = new HashMap<>(); + if (result instanceof PaymentResult.PaymentSuccess) { + map.put("orderId", ((PaymentResult.PaymentSuccess) result).getOrderId()); + map.put("productId", ((PaymentResult.PaymentSuccess) result).getProductId()); + map.put("code", 200); + } else if (result instanceof PaymentResult.PaymentFailed) { + map.put("code", ((PaymentResult.PaymentFailed) result).getCode()); + map.put("productId", ((PaymentResult.PaymentFailed) result).getProductId()); + } + callJsWithJson("openPaymentCallback", map); + } + }); + paymentClient.launchPayment(paymentIntent); + }); + } + + + /** + * 调转个人主页 + * + * @param uid 用户id + */ + @JavascriptInterface + public void openPersonPage(String uid) { + LogUtil.i(TAG, "openPersonPage:" + uid); + if (!TextUtils.isEmpty(uid)) { + try { + long uidLong = Long.parseLong(uid); + UIHelper.showUserInfoAct(context, uidLong); + } catch (NumberFormatException e) { + e.printStackTrace(); + } + } + } + + /** + * 跳转充值页面 + */ + @JavascriptInterface + public void openChargePage(int type) { + if (context != null) { + LogUtil.i(TAG, "openChargePage:" + type); + //充值 + WalletInfo goldWalletInfo = PayModel.get().getCurrentWalletInfo(); + HashMap map = new HashMap<>(5); + map.put(IReportConstants.PAYPAGE_TYPE, type); + if (goldWalletInfo != null) { + map.put(IReportConstants.ACCOUNT_BALANCE, goldWalletInfo.getDiamondNum()); + } + map.put(IReportConstants.MODULE, IReportConstants.MOLISTAR_PAY); + ReportManager.get().reportEvent(IReportConstants.PAYPAGE_SHOW, map); +// if (AppMetaDataUtil.getChannelID().equals(Constants.GOOGLE)) { + ChargeActivity.start(context); +// } else { +// CommonWebViewActivity.start( +// context, UriProvider.getOfficialPay( +// 4, +// DeviceUtil.getDeviceId(context) +// ) +// ); +// } + } + } + + /** + * 三方按钮充值点击 + * + * @param money + */ + @JavascriptInterface + public void chargePayPage(int money) { + if (mActivity != null) { + LogUtil.i(TAG, "chargePayPage:" + money); + //点击充值 + HashMap map = new HashMap<>(3); + map.put(IReportConstants.MONEY, money); + map.put(IReportConstants.MODULE, IReportConstants.MOLISTAR_PAY); + ReportManager.get().reportEvent(IReportConstants.PAY_CLICK, map); + } + } + + @JavascriptInterface + public void openSharePage() { + } + + @JavascriptInterface + public void goToExchangeGold() { + EarnRecordActivity.start(context); + } + + @JavascriptInterface + public void openSharePage(String json) { + Logger.e("openSharePage: " + json); + WebJsBeanInfo webJsBeanInfo = JSON.parseObject(json, WebJsBeanInfo.class); + RxBus.get().post(new ShareH5Event().setWebJsBeanInfo(webJsBeanInfo)); + } + + @JavascriptInterface + public void savePictureShare(String json) { + Logger.e("savePictureShare: " + json); + try { + CommonWebViewActivity activity = mActivity; + if (activity == null) { + return; + } + ShareInviteInfo info = new Gson().fromJson(json, ShareInviteInfo.class); + if (info.getType() != null) { + if (info.getType() == 1) { + activity.runOnUiThread(() -> { + new ShareInviteDialog(info).show(activity.getSupportFragmentManager(), "SHARE_INVITE#JS"); + }); + } else if (info.getType() == 2) { + activity.runOnUiThread(() -> { + new InviteImageHelper().saveToAlbum(activity, activity.getRxPermissions(), info, null); + }); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 调转钱包页 + */ + @JavascriptInterface + public void openPurse() { + LogUtil.i(TAG, "openPurse:"); + } + + /** + * 调转房间 + * + * @param uid 房主uid + */ + @JavascriptInterface + public void openRoom(String uid) { + LogUtil.i(TAG, "openRoom:" + uid); + if (!TextUtils.isEmpty(uid)) { + try { + long uidLong = Long.parseLong(uid); + AVRoomActivity.start(context, uidLong); + } catch (NumberFormatException e) { + e.printStackTrace(); + } + } + + } + + /** + * 调转房间 + * + * @param uid 房主uid + */ + @JavascriptInterface + public void openRoomForGiftId(String uid, int giftId) { + LogUtil.i(TAG, "openRoom:" + uid + "giftId=" + giftId); + if (!TextUtils.isEmpty(uid)) { + try { + long uidLong = Long.parseLong(uid); + mActivity.runOnUiThread(() -> AVRoomActivity.startForFromGiftId(context, uidLong, giftId)); + } catch (NumberFormatException e) { + e.printStackTrace(); + } + } + + } + + /** + * 获取用户ticket + * + * @return + */ + @JavascriptInterface + public String getTicket() { + return AuthModel.get().getTicket(); + } + + /** + * 获取设备ID + * + * @return 设备id + */ + @JavascriptInterface + public String getDeviceId() { + return DeviceUuidFactory.getDeviceId(BasicConfig.INSTANCE.getAppContext()); + } + + /** + * 获取房间的uid + * + * @return - + */ + @JavascriptInterface + public String getRoomUid() { + RoomInfo mCurrentRoomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (mCurrentRoomInfo == null || mCurrentRoomInfo.getUid() == 0) return null; + return String.valueOf(mCurrentRoomInfo.getUid()); + } + + /** + * 获取uid + * + * @return uid + */ + @JavascriptInterface + public String getUid() { + /* if (mActivity != null && mWebView != null) { + LogUtil.i(TAG, "getUid.........................."); + mActivity.runOnUiThread(new Runnable() { + @Override + public void run() { + String args = "'uid'," + String.valueOf(AuthModel.get().getCurrentUid()); + mWebView.loadUrl("javascript:getMessage(" + args + ")"); + } + }); + }*/ + return String.valueOf(AuthModel.get().getCurrentUid()); + } + + @JavascriptInterface + public String getPosition() { + return String.valueOf(mPosition); + } + + public void setPosition(int position) { + mPosition = position; + } + + @JavascriptInterface + public void challenge(long uid, String gameId) { + NimP2PMessageActivity.start(context, uid + "", gameId); + } + + @JavascriptInterface + public void clipboardToPhone(String content) { + ClipboardManager myClipboard; + myClipboard = (ClipboardManager) BasicConfig.INSTANCE.getAppContext().getSystemService(CLIPBOARD_SERVICE); + ClipData myClip; + myClip = ClipData.newPlainText("text", content); + if (myClipboard != null) + myClipboard.setPrimaryClip(myClip); + } + + @JavascriptInterface + public void initNav(String json) { + Logger.e("initNav: " + json); + WebJsBeanInfo webJsBeanInfo = JSON.parseObject(json, WebJsBeanInfo.class); + RxBus.get().post(new ShareH5Event().setWebJsBeanInfo(webJsBeanInfo)); + } + + /** + * 初始化导航栏 + * + * @param b true为显示,false为关闭 + */ + @JavascriptInterface + public void initShowNav(boolean b) { + Logger.e("initShowNav: " + b); + EventBus.getDefault().post(new ShowNavEvent(b)); + } + + /** + * 关闭浏览器 + */ + @JavascriptInterface + public void closeWebView() { + if (mActivity != null) mActivity.finish(); + } + + /** + * 成功通过人机验证 + */ + @JavascriptInterface + public void closeToVerify(boolean isVerify) { + if (mVerifyActivity != null){ + if (isVerify) { + mVerifyActivity.setResult(Activity.RESULT_OK); + } else { + mVerifyActivity.setResult(Activity.RESULT_CANCELED); + } + mVerifyActivity.finish(); + } + } + + /** + * 联系客服 + * + * @param uid 客服 UID + */ + @JavascriptInterface + public void contactSomeOne(String uid) { + NimP2PMessageActivity.start(context, uid); + } + +// @JavascriptInterface +// public boolean startRecode() { +// // recorder 实例 +// AuditRecorderConfiguration configuration = new AuditRecorderConfiguration.Builder() +// .uncompressed(true) +// .builder(); +// extAudioRecorder = new ExtAudioRecorder(configuration); +// // 录音地址 +// File sdcardDir = new File(context.getExternalFilesDir(Environment.DIRECTORY_MUSIC).getAbsolutePath() + +// File.separator + "wewawa"); +// if (!sdcardDir.exists()) { +// boolean mkdirResult = sdcardDir.mkdir(); +// Log.e(TAG, "startRecode: mkdirResult: " + mkdirResult); +// } +// myRecAudioFile = new File(sdcardDir.getAbsolutePath(), "wewawa-" + System.currentTimeMillis() + ".wav"); +// Log.i(TAG, "startRecode: myRecAudioFile path: " + myRecAudioFile.getAbsolutePath()); +// // 设置输出文件 +// extAudioRecorder.setOutputFile(myRecAudioFile.getAbsolutePath()); +// extAudioRecorder.prepare(); +// extAudioRecorder.start(); +// return true; +// } +// +// @JavascriptInterface +// public String stopRecode() { +// if (extAudioRecorder == null || myRecAudioFile == null) +// return null; +// if (!myRecAudioFile.exists()) { +// return null; +// } +// extAudioRecorder.stop(); +// extAudioRecorder.release(); +// String url = FileModel.get() +// .uploadFile(myRecAudioFile.getAbsolutePath()) +// .blockingGet(); +// myRecAudioFile.delete(); +// Log.i(TAG, "stopRecord: url: " + url); +// return url; +// } + + @JavascriptInterface + public void openFamilyPage(String familyId) { + } + + /** + * 打开装扮商城 + * + * @param type {@link DecorationStoreRouterType#TYPE_HEAD_WEAR} + * {@link DecorationStoreRouterType#TYPE_CAR} + * {@link DecorationStoreRouterType#TYPE_BACKGROUND} + */ + @JavascriptInterface + public void openDecorateMallPage(int type) { + if (type <= 0) return; + } + + /** + * 获取应用版本号 + */ + @JavascriptInterface + public String getAppVersion() { + return VersionUtil.getLocalName(context); + } + + /** + * 获取渠道 + * + * @return 渠道名称 + */ + @JavascriptInterface + public String getChannel() { + return AppMetaDataUtil.getChannelID(); + } + + /** + * 获取是否审核中状态 + * + * @return 1 正常审核中 + */ + @JavascriptInterface + public int loadingStatus() { + return MarketVerifyModel.get().isMarketChecking() ? 1 : 0; + } + + /** + * 根据 routerType 协议跳转不同的页面 + * + * @param json + */ + @JavascriptInterface + public void jumpAppointPage(String json) { + Logger.e("jumpAppointPage: " + json); + WebJsBeanInfo.DataBean webDataBean = JSON.parseObject(json, WebJsBeanInfo.DataBean.class); + if (Looper.myLooper() == Looper.getMainLooper()) { + RouterHandler.handle(context, webDataBean.getRouterType(), + String.valueOf(webDataBean.getRouterVal())); + } else { + mWebView.post(new Runnable() { + @Override + public void run() { + + RouterHandler.handle(context, webDataBean.getRouterType(), + String.valueOf(webDataBean.getRouterVal())); + } + }); + } + + } + + /** + * 获取 deviceInfo + * + * @return + */ + @JavascriptInterface + public String getDeviceInfo() { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("os", "android"); + jsonObject.put("osVersion", Build.VERSION.RELEASE); + jsonObject.put("app", XConstants.APP_MARK); + jsonObject.put("ispType", String.valueOf(SystemUtils.getIspType(context))); + jsonObject.put("netType", String.valueOf(SystemUtils.getNetworkType(context))); + jsonObject.put("model", SystemUtils.getPhoneModel()); + jsonObject.put("appVersion", VersionUtil.getLocalName(context)); + jsonObject.put("appVersionCode", String.valueOf(VersionUtil.getVersionCode(context))); + jsonObject.put("deviceId", DeviceUtil.getDeviceId(context)); + jsonObject.put("channel", AppMetaDataUtil.getChannelID()); + jsonObject.put("Accept-Language", LanguageHelper.INSTANCE.getCurrentLanguageType()); + Log.e(TAG, "getDeviceInfo: " + jsonObject); + return jsonObject.toJSONString(); + } + + + /** + * 刷脸 + *

+ * AUDIT_EXCEPTION = -2, //认证异常,网络不通或者环境问题 + * AUDIT_NOT = -1, //未认证,用户主动取消 + * AUDIT_IN_AUDIT = 0, //认证中 + * AUDIT_FAIL = 1, //审核失败 + * AUDIT_PASS = 2, //审核通过 + * + * @param verifyToken + */ + @JavascriptInterface + public void openFaceLiveness(String verifyToken) { + + } + + /** + * h5操作成功后,回调的客户端方法 + * + * @param json {"type": 1} + */ + @JavascriptInterface + public void onNotifyClient(String json) { + EventBus.getDefault().post(new H5NotifyClientEvent(json)); + } + + + /** + * h5更新当前登录用户信息 + */ + @JavascriptInterface + public void updateCurrentUserInfo() { + UserModel.get().updateCurrentUserInfo().subscribe(); + } + + @JavascriptInterface + public void h5CallAppStatistics(String json) { + try { + org.json.JSONObject jsonObject = new org.json.JSONObject(json); + String funcName = jsonObject.getString("funcName"); + String title = jsonObject.getString("title"); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + @JavascriptInterface + public void closeDialogWebView() { + if (mActivity instanceof TarotPayWebViewActivity) mActivity.finish(); + } + + /** + * 打开弹窗式 WebViewActivity + */ + @JavascriptInterface + public void openDialogWebview(String url) { + TarotPayWebViewActivity.start(mActivity, url); + } + + @JavascriptInterface + public void checkResultFinish(int result) { + EventBus.getDefault().post(new TaroPayResultEvent().setResult(result)); + if (mActivity instanceof TarotPayWebViewActivity) mActivity.finish(); + } + + /** + * 跳转app并且自动关注用户然后打开私聊页面 + */ + @JavascriptInterface + public void openAppConcernedChat(String uid) { + PraiseModel.get().praise(Long.parseLong(uid), true).subscribe(); + NimP2PMessageActivity.start(context, uid); + } + + /** + * 拉起 原生app 分享选择Action + */ + @JavascriptInterface + public boolean showShareAction(String url) { + if (mActivity == null) return false; + ShareManager.INSTANCE.showShareAction(mActivity,url); + return true; + } + + @Override + public void onCleared() { + if (paymentClient != null) { + paymentClient.onCleared(); + } + } + + public void setVerifyActivity(Activity mVerifyActivity) { + this.mVerifyActivity = mVerifyActivity; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/webview/ShareH5Event.java b/app/src/main/java/com/chwl/app/ui/webview/ShareH5Event.java new file mode 100644 index 0000000..ec52c0b --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/webview/ShareH5Event.java @@ -0,0 +1,21 @@ +package com.chwl.app.ui.webview; + +import com.chwl.core.web.bean.WebJsBeanInfo; + +/** + * Created by MadisonRong on 26/06/2018. + */ + +public class ShareH5Event { + + private WebJsBeanInfo webJsBeanInfo; + + public WebJsBeanInfo getWebJsBeanInfo() { + return webJsBeanInfo; + } + + public ShareH5Event setWebJsBeanInfo(WebJsBeanInfo webJsBeanInfo) { + this.webJsBeanInfo = webJsBeanInfo; + return this; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/webview/SimpleJSInterface.java b/app/src/main/java/com/chwl/app/ui/webview/SimpleJSInterface.java new file mode 100644 index 0000000..4d5b70b --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/webview/SimpleJSInterface.java @@ -0,0 +1,116 @@ +package com.chwl.app.ui.webview; + +import android.app.Activity; +import android.content.Context; +import android.text.TextUtils; +import android.util.Log; +import android.webkit.JavascriptInterface; + +import com.alibaba.fastjson2.JSONObject; +import com.orhanobut.logger.Logger; +import com.tencent.vasdolly.helper.ChannelReaderUtil; +import com.chwl.app.application.App; +import com.chwl.core.XConstants; +import com.chwl.core.Constants; +import com.chwl.library.utils.VersionUtil; + +/** + *

html js 与webview 交互接口

+ * Created by ${user} on 2017/11/6. + */ +public class SimpleJSInterface { + private static final String TAG = SimpleJSInterface.class.getSimpleName(); + private final Context context; + + public SimpleJSInterface(Context context) { + this.context = context; + } + + /** + * 获取设备ID + * + * @return 设备id + */ + @JavascriptInterface + public String getDeviceId() { + return ""; + } + + /** + * 获取uid + * + * @return uid + */ + @JavascriptInterface + public String getUid() { + return ""; + } + + @JavascriptInterface + public void initNav(String json) { + Logger.e("initNav: " + json); + } + + /** + * 关闭浏览器 + */ + @JavascriptInterface + public void closeWebView() { + if (context instanceof Activity) { + ((Activity) context).finish(); + } + } + + /** + * 获取用户ticket + * + * @return + */ + @JavascriptInterface + public String getTicket() { + return ""; + } + + + /** + * 获取应用版本号 + */ + @JavascriptInterface + public String getAppVersion() { + return VersionUtil.getLocalName(context); + } + + /** + * 获取渠道 + * + * @return 渠道名称 + */ + @JavascriptInterface + public String getChannel() { + String channel; + channel = ChannelReaderUtil.getChannel(App.instance()); + if (TextUtils.isEmpty(channel)) { + channel = Constants.GOOGLE; + } + return channel; + } + + + /** + * 获取 deviceInfo + * + * @return + */ + @JavascriptInterface + public String getDeviceInfo() { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("os", "android"); + jsonObject.put("app", XConstants.APP_MARK); + jsonObject.put("appVersion", VersionUtil.getLocalName(context)); + jsonObject.put("appVersionCode", String.valueOf(VersionUtil.getVersionCode(context))); + jsonObject.put("channel", getChannel()); + Log.e(TAG, "getDeviceInfo: " + jsonObject); + return jsonObject.toJSONString(); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/webview/SimpleWebViewActivity.java b/app/src/main/java/com/chwl/app/ui/webview/SimpleWebViewActivity.java new file mode 100644 index 0000000..5cfd2c3 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/webview/SimpleWebViewActivity.java @@ -0,0 +1,245 @@ +package com.chwl.app.ui.webview; + +import android.annotation.SuppressLint; +import android.annotation.TargetApi; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.net.Uri; +import android.net.http.SslError; +import android.os.Build; +import android.os.Bundle; +import android.os.Handler; +import android.text.TextUtils; +import android.view.View; +import android.webkit.SslErrorHandler; +import android.webkit.ValueCallback; +import android.webkit.WebChromeClient; +import android.webkit.WebSettings; +import android.webkit.WebView; +import android.webkit.WebViewClient; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.TextView; + +import androidx.annotation.LayoutRes; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; + +import com.netease.nim.uikit.StatusBarUtil; +import com.orhanobut.logger.Logger; +import com.chwl.app.R; +import com.chwl.app.utils.WebViewUtils; +import com.chwl.library.utils.ResUtil; + +import java.lang.ref.WeakReference; + + +/** + * 最简单的H5页面,用于隐私协议弹窗,不继承BaseActivity + */ +public class SimpleWebViewActivity extends AppCompatActivity { + + protected FrameLayout layoutTitleBar; + protected WebView webView; + private ProgressBar mProgressBar; + private WebChromeClient wvcc; + private ImageView mIvBack; + private ImageView mIvClose; + private TextView mTitle; + private String url; + + private int mProgress; + + private Handler mHandler = new Handler(); + + private ProgressRunnable mProgressRunnable = new ProgressRunnable(this); + + public static void start(Context context, String url) { + Intent intent = new Intent(context, SimpleWebViewActivity.class); + intent.putExtra("url", url); + context.startActivity(intent); + } + + @SuppressLint("CheckResult") + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(getLayoutId()); + Intent intent = getIntent(); + url = intent.getStringExtra("url"); + StatusBarUtil.transparencyBar(this); + StatusBarUtil.StatusBarLightMode(this); + initView(); + initData(); + setListener(); + showWebView(url); + } + + @LayoutRes + protected int getLayoutId() { + return R.layout.activity_simple_web_view; + } + + private void setListener() { + mIvBack.setOnClickListener(v -> { + if (webView.canGoBack()) { + webView.goBack(); + } else { + finish(); + } + }); + + mIvClose.setOnClickListener(v -> { + finish(); + }); + } + + @SuppressLint("SetJavaScriptEnabled") + private void initData() { + mHandler.post(mProgressRunnable); + webView.getSettings().setJavaScriptEnabled(true); + webView.getSettings().setUseWideViewPort(true); + webView.getSettings().setLoadWithOverviewMode(true); + // 设置 WebView 可以在 HTTPS 通道上加载 HTTP 资源,Android 4.4 后的暗坑 + // 因为 Android 4.4 后默认不允许在 HTTPS 通道上加载 HTTP 资源 + webView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE); + webView.getSettings().setTextZoom(100); + SimpleJSInterface jsInterface = new SimpleJSInterface(this); + webView.addJavascriptInterface(jsInterface, "androidJsObj"); + webView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE); + webView.setWebViewClient(new WebViewClient() { + + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + + if (!(url.startsWith("http") || url.startsWith("https"))) { + return true; + } + + view.loadUrl(url); + return true; + } + + @Override + public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { + // super.onReceivedSslError(view, handler, error); + AlertDialog.Builder builder = new AlertDialog.Builder(view.getContext()); + builder.setMessage(ResUtil.getString(R.string.ui_webview_simplewebviewactivity_01)); + builder.setPositiveButton(ResUtil.getString(R.string.ui_webview_simplewebviewactivity_02), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + handler.proceed();// 接受https所有网站的证书 + } + }); + + builder.setNegativeButton(ResUtil.getString(R.string.ui_webview_simplewebviewactivity_03), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + handler.cancel(); + } + }); + + AlertDialog dialog = builder.create(); + dialog.show(); + } + + @Override + public void onPageFinished(WebView view, String url) { + Logger.e("onPageFinished--------" + url); + mProgressBar.setProgress(100); + mProgressBar.setVisibility(View.GONE); + super.onPageFinished(view, url); + } + }); + //获取webviewtitle作为titlebar的title + wvcc = new WebChromeClient() { + + @Override + public void onReceivedTitle(WebView view, String title) { + super.onReceivedTitle(view, title); + mTitle.setText(title + ""); + } + + // For Android >= 4.1 + public void openFileChooser(ValueCallback uploadMsg, + String acceptType, String capture) { + + } + + // For Lollipop 5.0+ Devices + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + public boolean onShowFileChooser(WebView mWebView, + ValueCallback filePathCallback, + FileChooserParams fileChooserParams) { + + return false; + } + + }; + // 设置setWebChromeClient对象 + webView.setWebChromeClient(wvcc); + // 设置Webview的user-agent + webView.getSettings().setUserAgentString(webView.getSettings().getUserAgentString() + " molistarAppAndroid"); + } + + private void initView() { + layoutTitleBar = findViewById(R.id.layout_title_bar); + webView = (WebView) findViewById(R.id.webview); + mProgressBar = (ProgressBar) findViewById(R.id.progress_bar); + mIvBack = findViewById(R.id.iv_back); + mIvClose = findViewById(R.id.iv_close); + mTitle = findViewById(R.id.tv_title); + } + + public void showWebView(String url) { + Logger.d("ShowWebView--------" + url); + if (!TextUtils.isEmpty(url)) { + webView.loadUrl(url); + } else { + finish(); + } + } + + @Override + public void onBackPressed() { + if (webView.canGoBack()) { + webView.goBack(); + + } else { + this.finish(); + } + } + + @Override + protected void onDestroy() { + if (mHandler != null) { + mHandler.removeCallbacks(mProgressRunnable); + mProgressRunnable = null; + mHandler = null; + } + super.onDestroy(); + WebViewUtils.releaseWeb(webView); + } + + private static class ProgressRunnable implements Runnable { + private WeakReference mWeakReference; + + ProgressRunnable(SimpleWebViewActivity activity) { + mWeakReference = new WeakReference<>(activity); + } + + @Override + public void run() { + SimpleWebViewActivity activity = mWeakReference.get(); + if (activity == null) return; + if (activity.mProgress < 96) { + activity.mProgress += 3; + activity.mProgressBar.setProgress(activity.mProgress); + activity.mHandler.postDelayed(activity.mProgressRunnable, 10); + } + } + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/webview/TarotPayWebViewActivity.java b/app/src/main/java/com/chwl/app/ui/webview/TarotPayWebViewActivity.java new file mode 100644 index 0000000..0dffc6f --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/webview/TarotPayWebViewActivity.java @@ -0,0 +1,38 @@ +package com.chwl.app.ui.webview; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.view.Gravity; +import android.view.View; +import android.view.WindowManager; + +import com.netease.nim.uikit.common.util.sys.ScreenUtil; +import com.chwl.app.R; + + +/** + * 塔罗牌支付页面弹窗,仅塔罗牌支付使用 + */ +public class TarotPayWebViewActivity extends CommonWebViewActivity { + + public static void start(Context context, String url ) { + Intent intent = new Intent(context, TarotPayWebViewActivity.class); + intent.putExtra("url", url); + context.startActivity(intent); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setFinishOnTouchOutside(false); + getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT,ScreenUtil.dip2px(150)); + getWindow().setGravity(Gravity.CENTER); + layoutTitleBar.setVisibility(View.GONE); + } + + @Override + protected int getLayoutId() { + return R.layout.activity_tarot_pay_web_view; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/webview/baishun/BaiShunGameJSBridge.kt b/app/src/main/java/com/chwl/app/ui/webview/baishun/BaiShunGameJSBridge.kt new file mode 100644 index 0000000..8b3444b --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/webview/baishun/BaiShunGameJSBridge.kt @@ -0,0 +1,58 @@ +package com.chwl.app.ui.webview.baishun + +import android.webkit.JavascriptInterface +import androidx.annotation.Keep +import com.chwl.app.R +import com.chwl.app.common.widget.dialog.DialogUiHelper +import com.chwl.app.ui.pay.ChargeActivity +import com.example.lib_utils.log.ILog +import com.google.gson.Gson +import org.json.JSONObject + + +@Keep +class BaiShunGameJSBridge(val view: IBaiShunGameView) : ILog { + + @JavascriptInterface + public fun getConfig(params: String) { + logD("getConfig()") + try { + val obj = JSONObject(params) + val jsFunName = obj.optString("jsCallback") + val config = view.getGameConfig() + val str = (jsFunName + "(" + Gson().toJson(config) + ")") + callJs(str) + } catch (ex: Exception) { + ex.printStackTrace() + } + } + + @JavascriptInterface + public fun destroy(params: String) { + logD("游戏调⽤destroy") + view.getActivity2()?.runOnUiThread { + view.getListener()?.onGameClose() + } + } + + @JavascriptInterface + public fun gameRecharge(params: String) { + logD("游戏调⽤gameRecharge") + view.getActivity2()?.runOnUiThread { + DialogUiHelper.showNeedCharge(view.getActivity2(), view.getDialogManager2()) + } + } + + @JavascriptInterface + public fun gameLoaded(params: String) { + logD("游戏调⽤gameLoaded") + //游戏加载完毕 + view.getActivity2()?.runOnUiThread { + view.getDialogManager2().dismissDialog() + } + } + + private fun callJs(str: String) { + view.callJs(str) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/webview/baishun/BaiShunGameWebActivity.kt b/app/src/main/java/com/chwl/app/ui/webview/baishun/BaiShunGameWebActivity.kt new file mode 100644 index 0000000..78d0951 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/webview/baishun/BaiShunGameWebActivity.kt @@ -0,0 +1,49 @@ +package com.chwl.app.ui.webview.baishun + +import android.content.Context +import android.content.Intent +import android.view.View +import android.view.WindowManager +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.databinding.RoomGameActivityBinding +import com.chwl.core.room.game.bean.BaiShunGameConfig + +@Deprecated("改用房间内View-Fragment实现了,暂且保留一阵时间") +class BaiShunGameWebActivity : BaseViewBindingActivity() { + + companion object { + fun start(context: Context, url: String, config: BaiShunGameConfig) { + val intent = Intent(context, BaiShunGameWebActivity::class.java) + intent.putExtra("url", url) + intent.putExtra("config", config) + context.startActivity(intent) + } + } + + override fun init() { + window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_FULLSCREEN + or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) + window.setLayout( + WindowManager.LayoutParams.MATCH_PARENT, + WindowManager.LayoutParams.MATCH_PARENT + ) + val url = intent.getStringExtra("url") + val gameConfig = intent.getSerializableExtra("config") as? BaiShunGameConfig + if (url.isNullOrEmpty() || gameConfig == null) { + toast(R.string.utils_net_beanobserver_05) + finish() + return + } + val fragment = BaiShunGameWebFragment.newInstance(url, gameConfig) + fragment.setListener(object : IBaiShunGameListener { + override fun onGameClose() { + finish() + } + }) + supportFragmentManager.beginTransaction().add(R.id.layout_body, fragment) + .commitAllowingStateLoss() + } +} diff --git a/app/src/main/java/com/chwl/app/ui/webview/baishun/BaiShunGameWebFragment.kt b/app/src/main/java/com/chwl/app/ui/webview/baishun/BaiShunGameWebFragment.kt new file mode 100644 index 0000000..22bd5f7 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/webview/baishun/BaiShunGameWebFragment.kt @@ -0,0 +1,268 @@ +package com.chwl.app.ui.webview.baishun + +import android.annotation.SuppressLint +import android.app.Activity +import android.graphics.Bitmap +import android.net.http.SslError +import android.os.Build +import android.os.Bundle +import android.webkit.SslErrorHandler +import android.webkit.WebResourceError +import android.webkit.WebResourceRequest +import android.webkit.WebSettings +import android.webkit.WebView +import android.webkit.WebViewClient +import androidx.appcompat.app.AlertDialog +import androidx.core.view.isInvisible +import androidx.core.view.isVisible +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingFragment +import com.chwl.app.common.widget.dialog.DialogManager +import com.chwl.app.common.widget.dialog.DialogManager.OkCancelDialogListener +import com.chwl.app.databinding.RoomGameFragmentBinding +import com.chwl.core.auth.AuthModel +import com.chwl.core.pay.event.GetWalletInfoEvent +import com.chwl.core.pay.event.UpdateWalletInfoEvent +import com.chwl.core.room.game.bean.BaiShunGameConfig +import com.chwl.library.utils.ResUtil +import com.google.gson.Gson +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode + +class BaiShunGameWebFragment : BaseViewBindingFragment(), + IBaiShunGameView { + + private var gameConfig: BaiShunGameConfig? = null + + private var gameUrl = "" + + private var isLoadError = false + + private var listener: IBaiShunGameListener? = null + + companion object { + fun newInstance( + url: String, + config: BaiShunGameConfig + ): BaiShunGameWebFragment { + val bundle = Bundle() + bundle.putString("url", url) + bundle.putSerializable("config", config) + return BaiShunGameWebFragment().apply { + arguments = bundle + } + } + } + + override fun init() { + val url = arguments?.getString("url") + gameConfig = arguments?.getSerializable("config") as? BaiShunGameConfig + if (url.isNullOrEmpty() || gameConfig == null) { + toast(R.string.utils_net_beanobserver_05) + return + } + gameUrl = url + initView() + getViewBinding()?.webView?.isInvisible = true + getViewBinding()?.webView?.loadUrl(url) + } + + private fun initView() { + initWebView() + } + + @SuppressLint("SetJavaScriptEnabled", "JavascriptInterface") + private fun initWebView() { + //防⽌⽤浏览器打开⽹⻚ + getViewBinding()?.webView?.webViewClient = object : WebViewClient() { + + override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) { + super.onPageStarted(view, url, favicon) + isLoadError = false + if (url == gameUrl) { + context?.let { + dialogManager.showProgressDialog(it) + } + + } + } + + override fun onReceivedError( + view: WebView?, + errorCode: Int, + description: String?, + failingUrl: String? + ) { + super.onReceivedError(view, errorCode, description, failingUrl) + isLoadError = true + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + onReceivedError(failingUrl, errorCode, description) + } + } + + override fun onReceivedError( + view: WebView?, + request: WebResourceRequest?, + error: WebResourceError? + ) { + super.onReceivedError(view, request, error) + isLoadError = true + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + onReceivedError(request?.url?.toString(), error?.errorCode, error?.description) + } + } + + override fun onPageFinished(view: WebView?, url: String?) { + super.onPageFinished(view, url) + try { + if (!isLoadError) { + getViewBinding()?.webView?.isVisible = true + } + }catch (e:Exception){ + + } + + } + + override fun onReceivedSslError( + view: WebView, + handler: SslErrorHandler, + error: SslError? + ) { + // super.onReceivedSslError(view, handler, error); + val builder = AlertDialog.Builder(view.context) + builder.setMessage(ResUtil.getString(R.string.ui_webview_commonwebviewactivity_07)) + builder.setPositiveButton( + ResUtil.getString(R.string.ui_webview_commonwebviewactivity_08) + ) { dialog, which -> + handler.proceed() // 接受https所有网站的证书 + } + builder.setNegativeButton( + ResUtil.getString(R.string.ui_webview_commonwebviewactivity_09) + ) { dialog, which -> handler.cancel() } + val dialog = builder.create() + dialog.show() + } + } + //设置webview背景透明,默认为⽩⾊ + getViewBinding()?.webView?.setBackgroundColor(0) + //设置view背景透明,默认为⽩⾊ 可选(单独activity添加webView组件时需要添加) + getViewBinding()?.root?.setBackgroundColor(0) + + val settings = getViewBinding()?.webView?.settings + //设置⽀持Javascript + settings?.javaScriptEnabled = true + //设置默认⽂本编码 + settings?.defaultTextEncodingName = "UTF-8" + //设置可访问本地⽂件 + settings?.allowFileAccess = true + //设置允许通过file url加载的Javascript读取全部资源(包括⽂件,http,https) + settings?.allowUniversalAccessFromFileURLs = false + //设置优先加载缓存 + settings?.cacheMode = WebSettings.LOAD_CACHE_ELSE_NETWORK + //设置启⽤HTML5 DOM storage + settings?.domStorageEnabled = true + //设置开启数据库缓存 + settings?.databaseEnabled = true + settings?.databasePath = (context?.applicationContext?.filesDir?.absolutePath) + //设置⽀持缩放 + settings?.setSupportZoom(true) + //设置⾃适应 + settings?.useWideViewPort = true + //设置⾃动播放媒体 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + settings?.mediaPlaybackRequiresUserGesture = false + } + //设置5.0以上允许加载http和https混合的⻚⾯ + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + settings?.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW + } + + //游戏调⽤的类,必须定义为 NativeBridge + getViewBinding()?.webView?.addJavascriptInterface(BaiShunGameJSBridge(this), "NativeBridge") + } + + override fun callJs(str: String) { + getViewBinding()?.webView?.post { + getViewBinding()?.webView?.loadUrl("javascript:$str") + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onWalletInfoUpdate(event: UpdateWalletInfoEvent?) { + updateGameWallet() + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onGetWalletInfoEvent(event: GetWalletInfoEvent?) { + updateGameWallet() + } + + private fun updateGameWallet() { + try { + //数据只是参考值,需要根据⾃⼰APP进⾏赋值 + val map = HashMap() + map["userId"] = AuthModel.get().currentUid + val str = "walletUpdate" + "(" + Gson().toJson(map) + ")" + this.callJs(str) + } catch (e: Exception) { + e.printStackTrace() + } + } + + override fun getGameConfig() = gameConfig + + override fun getListener(): IBaiShunGameListener? { + return listener + } + + fun setListener(listener: IBaiShunGameListener) { + this.listener = listener + } + + override fun getActivity2(): Activity? { + return activity + } + + override fun getDialogManager2(): DialogManager { + return super.getDialogManager() + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + EventBus.getDefault().register(this) + } + + override fun onDestroy() { + super.onDestroy() + EventBus.getDefault().unregister(this) + } + + private fun onReceivedError(url: String?, code: Int?, message: CharSequence?) { + if (url == gameUrl) { + getViewBinding()?.webView?.isInvisible = true + dialogManager.dismissDialog() + showLoadErrorDialog(message?.toString() ?: "($code)") + } + } + + private fun showLoadErrorDialog(message: String) { + dialogManager.showOkCancelDialog( + getString(R.string.load_failed), + message, + getString(R.string.retry), + getString(R.string.exit_text), + false, false, true, object : OkCancelDialogListener { + override fun onOk() { + getViewBinding()?.webView?.reload() + } + + override fun onCancel() { + super.onCancel() + listener?.onGameClose() + } + }, null, false + ) + } +} diff --git a/app/src/main/java/com/chwl/app/ui/webview/baishun/IBaiShunGameListener.kt b/app/src/main/java/com/chwl/app/ui/webview/baishun/IBaiShunGameListener.kt new file mode 100644 index 0000000..07a8b21 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/webview/baishun/IBaiShunGameListener.kt @@ -0,0 +1,5 @@ +package com.chwl.app.ui.webview.baishun + +interface IBaiShunGameListener { + fun onGameClose() +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/webview/baishun/IBaiShunGameView.kt b/app/src/main/java/com/chwl/app/ui/webview/baishun/IBaiShunGameView.kt new file mode 100644 index 0000000..29ff6f6 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/webview/baishun/IBaiShunGameView.kt @@ -0,0 +1,19 @@ +package com.chwl.app.ui.webview.baishun + +import android.app.Activity +import android.content.Context +import com.chwl.app.base.BaseActivity +import com.chwl.app.common.widget.dialog.DialogManager +import com.chwl.core.room.game.bean.BaiShunGameConfig + +interface IBaiShunGameView { + fun getActivity2(): Activity? + + fun callJs(str: String) + + fun getDialogManager2(): DialogManager + + fun getGameConfig(): BaiShunGameConfig? + + fun getListener(): IBaiShunGameListener? +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/webview/baishun/JoyPlayGameWebFragment.kt b/app/src/main/java/com/chwl/app/ui/webview/baishun/JoyPlayGameWebFragment.kt new file mode 100644 index 0000000..1630696 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/webview/baishun/JoyPlayGameWebFragment.kt @@ -0,0 +1,314 @@ +package com.chwl.app.ui.webview.baishun + +import android.annotation.SuppressLint +import android.app.Activity +import android.graphics.Bitmap +import android.net.http.SslError +import android.os.Build +import android.os.Bundle +import android.text.TextUtils +import android.webkit.SslErrorHandler +import android.webkit.WebResourceError +import android.webkit.WebResourceRequest +import android.webkit.WebSettings +import android.webkit.WebView +import android.webkit.WebViewClient +import androidx.appcompat.app.AlertDialog +import androidx.core.view.isInvisible +import androidx.core.view.isVisible +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingFragment +import com.chwl.app.common.widget.dialog.DialogManager +import com.chwl.app.common.widget.dialog.DialogManager.OkCancelDialogListener +import com.chwl.app.databinding.RoomGameFragmentBinding +import com.chwl.core.pay.event.GetWalletInfoEvent +import com.chwl.core.pay.event.UpdateWalletInfoEvent +import com.chwl.core.room.game.bean.BaiShunGameConfig +import com.chwl.library.common.util.ClickUtils.click +import com.chwl.library.common.util.setVis +import com.chwl.library.utils.ResUtil +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode + +class JoyPlayGameWebFragment : BaseViewBindingFragment(), + IBaiShunGameView { + + private var gameConfig: BaiShunGameConfig? = null + + private var gameUrl = "" + + private var isLoadError = false + + private var listener: IBaiShunGameListener? = null + + var joyPlayJSBridge : JoyPlayJSBridge? = null + + companion object { + fun newInstance( + url: String, + config: BaiShunGameConfig + ): JoyPlayGameWebFragment { + val bundle = Bundle() + bundle.putString("url", url) + bundle.putSerializable("config", config) + return JoyPlayGameWebFragment().apply { + arguments = bundle + } + } + } + + + override fun init() { + val url = arguments?.getString("url") + gameConfig = arguments?.getSerializable("config") as? BaiShunGameConfig + if (url.isNullOrEmpty() || gameConfig == null) { + toast(R.string.utils_net_beanobserver_05) + return + } + gameUrl = url + initView() + getViewBinding()?.webView?.isInvisible = true + getViewBinding()?.webView?.loadUrl(url) + } + + private fun initView() { + initWebView() + } + + @SuppressLint("SetJavaScriptEnabled", "JavascriptInterface") + private fun initWebView() { + //防⽌⽤浏览器打开⽹⻚ + getViewBinding()?.webView?.webViewClient = object : WebViewClient() { + + private fun isContainCloudFront(view: WebView?, url: String?): Boolean { + if (!TextUtils.isEmpty(url)) { + if (url?.contains("cloudfront") == true) { + view?.loadUrl(url); + return true; + } + } + return false; + } + + + override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean { + if (isContainCloudFront(view, url)) { + return true + } + return super.shouldOverrideUrlLoading(view, url) + } + + + override fun shouldOverrideUrlLoading( + view: WebView?, + request: WebResourceRequest? + ): Boolean { + val url = request?.url?.toString() + if (isContainCloudFront(view, url)) { + return true + } + return super.shouldOverrideUrlLoading(view, request) + } + + + override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) { + super.onPageStarted(view, url, favicon) + isLoadError = false + if (url == gameUrl) { + dialogManager.showProgressDialog(context) + } + } + + override fun onReceivedError( + view: WebView?, + errorCode: Int, + description: String?, + failingUrl: String? + ) { + super.onReceivedError(view, errorCode, description, failingUrl) + isLoadError = true + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + onReceivedError(failingUrl, errorCode, description) + } + } + + override fun onReceivedError( + view: WebView?, + request: WebResourceRequest?, + error: WebResourceError? + ) { + super.onReceivedError(view, request, error) + isLoadError = true + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + onReceivedError(request?.url?.toString(), error?.errorCode, error?.description) + } + } + + override fun onPageFinished(view: WebView?, url: String?) { + super.onPageFinished(view, url) + if (!isLoadError) { + getViewBinding()?.webView?.isVisible = true + } + } + + override fun onReceivedSslError( + view: WebView, + handler: SslErrorHandler, + error: SslError? + ) { + // super.onReceivedSslError(view, handler, error); + val builder = AlertDialog.Builder(view.context) + builder.setMessage(ResUtil.getString(R.string.ui_webview_commonwebviewactivity_07)) + builder.setPositiveButton( + ResUtil.getString(R.string.ui_webview_commonwebviewactivity_08) + ) { dialog, which -> + handler.proceed() // 接受https所有网站的证书 + } + builder.setNegativeButton( + ResUtil.getString(R.string.ui_webview_commonwebviewactivity_09) + ) { dialog, which -> handler.cancel() } + val dialog = builder.create() + dialog.show() + } + } + + + //设置webview背景透明,默认为⽩⾊ + getViewBinding()?.webView?.setBackgroundColor(0) + //设置view背景透明,默认为⽩⾊ 可选(单独activity添加webView组件时需要添加) + getViewBinding()?.root?.setBackgroundColor(0) + + val settings = getViewBinding()?.webView?.settings + //设置⽀持Javascript + settings?.javaScriptEnabled = true + //设置默认⽂本编码 +// settings?.defaultTextEncodingName = "UTF-8" + //设置可访问本地⽂件 +// settings?.allowFileAccess = true + //设置允许通过file url加载的Javascript读取全部资源(包括⽂件,http,https) + settings?.allowUniversalAccessFromFileURLs = false + //设置优先加载缓存 + settings?.cacheMode = WebSettings.LOAD_DEFAULT + //设置启⽤HTML5 DOM storage + settings?.domStorageEnabled = true + //设置开启数据库缓存 + settings?.databaseEnabled = true + settings?.databasePath = (context?.applicationContext?.filesDir?.absolutePath) + //设置⽀持缩放 +// settings?.setSupportZoom(true) + //设置⾃适应 + settings?.useWideViewPort = true + //设置⾃动播放媒体 +// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { +// settings?.mediaPlaybackRequiresUserGesture = false +// } + //设置5.0以上允许加载http和https混合的⻚⾯ + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + settings?.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW + } + + //游戏调⽤的类,必须定义为 LingxianAndroid + joyPlayJSBridge = JoyPlayJSBridge(this) + getViewBinding()?.webView?.addJavascriptInterface(joyPlayJSBridge!!, "JSBridgeService") + + if (gameConfig?.showType == 2){ + getViewBinding()?.webView?.post { + getViewBinding()?.bg?.setVis(true) + getViewBinding()?.bg?.click { + joyPlayJSBridge?.newTppClose() + } + } + } + + getViewBinding()?.webView?.postDelayed({ dialogManager?.dismissDialog() }, 2000) + } + + override fun callJs(str: String) { + getViewBinding()?.webView?.post { + getViewBinding()?.webView?.loadUrl("javascript:$str") + } + } + + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onWalletInfoUpdate(event: UpdateWalletInfoEvent?) { + updateGameWallet() + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onGetWalletInfoEvent(event: GetWalletInfoEvent?) { + updateGameWallet() + } + + private fun updateGameWallet() { + try { + //"javascript:HttpTool.NativeToJs('recharge')" + this.callJs("HttpTool.NativeToJs('recharge')") + } catch (e: Exception) { + e.printStackTrace() + } + } + + override fun getGameConfig() = gameConfig + + override fun getListener(): IBaiShunGameListener? { + return listener + } + + fun setListener(listener: IBaiShunGameListener) { + this.listener = listener + } + + override fun getActivity2(): Activity? { + return activity + } + + override fun onResume() { + super.onResume() + updateGameWallet() + } + + override fun getDialogManager2(): DialogManager { + return super.getDialogManager() + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + EventBus.getDefault().register(this) + } + + override fun onDestroy() { + super.onDestroy() + EventBus.getDefault().unregister(this) + } + + private fun onReceivedError(url: String?, code: Int?, message: CharSequence?) { + if (url == gameUrl) { + getViewBinding()?.webView?.isInvisible = true + dialogManager.dismissDialog() + showLoadErrorDialog(message?.toString() ?: "($code)") + } + } + + private fun showLoadErrorDialog(message: String) { + dialogManager.showOkCancelDialog( + getString(R.string.load_failed), + message, + getString(R.string.retry), + getString(R.string.exit_text), + false, false, true, object : OkCancelDialogListener { + override fun onOk() { + getViewBinding()?.webView?.reload() + } + + override fun onCancel() { + super.onCancel() + listener?.onGameClose() + } + }, null, false + ) + } + + +} diff --git a/app/src/main/java/com/chwl/app/ui/webview/baishun/JoyPlayJSBridge.kt b/app/src/main/java/com/chwl/app/ui/webview/baishun/JoyPlayJSBridge.kt new file mode 100644 index 0000000..4ac07ef --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/webview/baishun/JoyPlayJSBridge.kt @@ -0,0 +1,62 @@ +package com.chwl.app.ui.webview.baishun + +import android.webkit.JavascriptInterface +import androidx.annotation.Keep +import com.chwl.app.R +import com.chwl.app.common.widget.dialog.DialogManager.OkCancelDialogListener +import com.chwl.app.common.widget.dialog.DialogUiHelper +import com.example.lib_utils.ktx.getString +import com.example.lib_utils.log.ILog +import org.json.JSONObject + + +@Keep +class JoyPlayJSBridge(var view: IBaiShunGameView) : ILog { + + + + @JavascriptInterface + public fun newTppClose() { + logD("游戏调⽤ newTppClose") + view.getActivity2()?.runOnUiThread { + showExitDialog() + } + } + + @JavascriptInterface + public fun clickRecharge() { + logD("游戏调⽤ clickRecharge") + startRecharge() + } + @JavascriptInterface + public fun recharge() { + logD("游戏调⽤ recharge") + startRecharge() + } + + private fun startRecharge() { + view.getActivity2()?.runOnUiThread { + DialogUiHelper.showNeedCharge(view.getActivity2(), view.getDialogManager2()) + } + } + + + + private fun showExitDialog() { + view.getDialogManager2().showOkCancelDialog( + R.string.tip_tips.getString(), + R.string.home_refresh_fungameview_01.getString(), + R.string.exit_text.getString(), + R.string.cancel.getString(), + false, false, true, object : OkCancelDialogListener { + override fun onOk() { + super.onCancel() + view?.getListener()?.onGameClose() + } + + override fun onCancel() { + } + }, null, false + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/webview/baishun/LeaderccGameWebFragment.kt b/app/src/main/java/com/chwl/app/ui/webview/baishun/LeaderccGameWebFragment.kt new file mode 100644 index 0000000..26e3e7a --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/webview/baishun/LeaderccGameWebFragment.kt @@ -0,0 +1,285 @@ +package com.chwl.app.ui.webview.baishun + +import android.annotation.SuppressLint +import android.app.Activity +import android.graphics.Bitmap +import android.net.http.SslError +import android.os.Build +import android.os.Bundle +import android.webkit.SslErrorHandler +import android.webkit.WebResourceError +import android.webkit.WebResourceRequest +import android.webkit.WebSettings +import android.webkit.WebView +import android.webkit.WebViewClient +import androidx.appcompat.app.AlertDialog +import androidx.core.view.isInvisible +import androidx.core.view.isVisible +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingFragment +import com.chwl.app.common.widget.dialog.DialogManager +import com.chwl.app.common.widget.dialog.DialogManager.OkCancelDialogListener +import com.chwl.app.databinding.RoomGameFragmentBinding +import com.chwl.core.auth.AuthModel +import com.chwl.core.pay.event.GetWalletInfoEvent +import com.chwl.core.pay.event.UpdateWalletInfoEvent +import com.chwl.core.room.game.bean.BaiShunGameConfig +import com.chwl.library.common.util.ClickUtils.click +import com.chwl.library.common.util.setVis +import com.chwl.library.utils.ResUtil +import com.google.gson.Gson +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode + +class LeaderccGameWebFragment : BaseViewBindingFragment(), + IBaiShunGameView { + + private var gameConfig: BaiShunGameConfig? = null + + private var gameUrl = "" + + private var isLoadError = false + + private var listener: IBaiShunGameListener? = null + + var leaderccJSBridge : LeaderccJSBridge? = null + + companion object { + fun newInstance( + url: String, + config: BaiShunGameConfig + ): LeaderccGameWebFragment { + val bundle = Bundle() + bundle.putString("url", url) + bundle.putSerializable("config", config) + return LeaderccGameWebFragment().apply { + arguments = bundle + } + } + } + + + override fun init() { + val url = arguments?.getString("url") + gameConfig = arguments?.getSerializable("config") as? BaiShunGameConfig + if (url.isNullOrEmpty() || gameConfig == null) { + toast(R.string.utils_net_beanobserver_05) + return + } + gameUrl = url + initView() + getViewBinding()?.webView?.isInvisible = true + getViewBinding()?.webView?.loadUrl(url) + } + + private fun initView() { + initWebView() + } + + @SuppressLint("SetJavaScriptEnabled", "JavascriptInterface") + private fun initWebView() { + //防⽌⽤浏览器打开⽹⻚ + getViewBinding()?.webView?.webViewClient = object : WebViewClient() { + + override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) { + super.onPageStarted(view, url, favicon) + isLoadError = false + if (url == gameUrl) { + dialogManager.showProgressDialog(context) + } + } + + override fun onReceivedError( + view: WebView?, + errorCode: Int, + description: String?, + failingUrl: String? + ) { + super.onReceivedError(view, errorCode, description, failingUrl) + isLoadError = true + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + onReceivedError(failingUrl, errorCode, description) + } + } + + override fun onReceivedError( + view: WebView?, + request: WebResourceRequest?, + error: WebResourceError? + ) { + super.onReceivedError(view, request, error) + isLoadError = true + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + onReceivedError(request?.url?.toString(), error?.errorCode, error?.description) + } + } + + override fun onPageFinished(view: WebView?, url: String?) { + super.onPageFinished(view, url) + if (!isLoadError) { + getViewBinding()?.webView?.isVisible = true + } + } + + override fun onReceivedSslError( + view: WebView, + handler: SslErrorHandler, + error: SslError? + ) { + // super.onReceivedSslError(view, handler, error); + val builder = AlertDialog.Builder(view.context) + builder.setMessage(ResUtil.getString(R.string.ui_webview_commonwebviewactivity_07)) + builder.setPositiveButton( + ResUtil.getString(R.string.ui_webview_commonwebviewactivity_08) + ) { dialog, which -> + handler.proceed() // 接受https所有网站的证书 + } + builder.setNegativeButton( + ResUtil.getString(R.string.ui_webview_commonwebviewactivity_09) + ) { dialog, which -> handler.cancel() } + val dialog = builder.create() + dialog.show() + } + } + //设置webview背景透明,默认为⽩⾊ + getViewBinding()?.webView?.setBackgroundColor(0) + //设置view背景透明,默认为⽩⾊ 可选(单独activity添加webView组件时需要添加) + getViewBinding()?.root?.setBackgroundColor(0) + + val settings = getViewBinding()?.webView?.settings + //设置⽀持Javascript + settings?.javaScriptEnabled = true + //设置默认⽂本编码 + settings?.defaultTextEncodingName = "UTF-8" + //设置可访问本地⽂件 + settings?.allowFileAccess = true + //设置允许通过file url加载的Javascript读取全部资源(包括⽂件,http,https) + settings?.allowUniversalAccessFromFileURLs = false + //设置优先加载缓存 + settings?.cacheMode = WebSettings.LOAD_CACHE_ELSE_NETWORK + //设置启⽤HTML5 DOM storage + settings?.domStorageEnabled = true + //设置开启数据库缓存 + settings?.databaseEnabled = true + settings?.databasePath = (context?.applicationContext?.filesDir?.absolutePath) + //设置⽀持缩放 + settings?.setSupportZoom(true) + //设置⾃适应 + settings?.useWideViewPort = true + //设置⾃动播放媒体 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + settings?.mediaPlaybackRequiresUserGesture = false + } + //设置5.0以上允许加载http和https混合的⻚⾯ + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + settings?.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW + } + + //游戏调⽤的类,必须定义为 LingxianAndroid + leaderccJSBridge = LeaderccJSBridge(this) + getViewBinding()?.webView?.addJavascriptInterface(leaderccJSBridge!!, "LingxianAndroid") + + if (gameConfig?.showType == 2){ + getViewBinding()?.webView?.post { + getViewBinding()?.bg?.setVis(true) + getViewBinding()?.bg?.click { + leaderccJSBridge?.closeGame() + } + } + } + + getViewBinding()?.webView?.postDelayed({ dialogManager?.dismissDialog() }, 2000) + } + + override fun callJs(str: String) { + getViewBinding()?.webView?.post { + getViewBinding()?.webView?.loadUrl("javascript:$str") + } + } + + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onWalletInfoUpdate(event: UpdateWalletInfoEvent?) { + updateGameWallet() + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onGetWalletInfoEvent(event: GetWalletInfoEvent?) { + updateGameWallet() + } + + private fun updateGameWallet() { + try { + //数据只是参考值,需要根据⾃⼰APP进⾏赋值 + val map = HashMap() + map["userId"] = AuthModel.get().currentUid + val str = "walletUpdate" + "(" + Gson().toJson(map) + ")" + this.callJs(str) + } catch (e: Exception) { + e.printStackTrace() + } + } + + override fun getGameConfig() = gameConfig + + override fun getListener(): IBaiShunGameListener? { + return listener + } + + fun setListener(listener: IBaiShunGameListener) { + this.listener = listener + } + + override fun getActivity2(): Activity? { + return activity + } + + override fun onResume() { + super.onResume() + leaderccJSBridge?.updateCoin() + } + + override fun getDialogManager2(): DialogManager { + return super.getDialogManager() + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + EventBus.getDefault().register(this) + } + + override fun onDestroy() { + super.onDestroy() + EventBus.getDefault().unregister(this) + } + + private fun onReceivedError(url: String?, code: Int?, message: CharSequence?) { + if (url == gameUrl) { + getViewBinding()?.webView?.isInvisible = true + dialogManager.dismissDialog() + showLoadErrorDialog(message?.toString() ?: "($code)") + } + } + + private fun showLoadErrorDialog(message: String) { + dialogManager.showOkCancelDialog( + getString(R.string.load_failed), + message, + getString(R.string.retry), + getString(R.string.exit_text), + false, false, true, object : OkCancelDialogListener { + override fun onOk() { + getViewBinding()?.webView?.reload() + } + + override fun onCancel() { + super.onCancel() + listener?.onGameClose() + } + }, null, false + ) + } + + +} diff --git a/app/src/main/java/com/chwl/app/ui/webview/baishun/LeaderccJSBridge.kt b/app/src/main/java/com/chwl/app/ui/webview/baishun/LeaderccJSBridge.kt new file mode 100644 index 0000000..e5d7cb4 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/webview/baishun/LeaderccJSBridge.kt @@ -0,0 +1,74 @@ +package com.chwl.app.ui.webview.baishun + +import android.webkit.JavascriptInterface +import androidx.annotation.Keep +import com.chwl.app.R +import com.chwl.app.common.widget.dialog.DialogManager.OkCancelDialogListener +import com.chwl.app.common.widget.dialog.DialogUiHelper +import com.chwl.app.ui.pay.ChargeActivity +import com.example.lib_utils.ktx.getString +import com.example.lib_utils.log.ILog +import com.google.gson.Gson +import org.json.JSONObject + + +@Keep +class LeaderccJSBridge(var view: IBaiShunGameView) : ILog { + + @JavascriptInterface + public fun updateCoin() { + logD("游戏调⽤ updateCoin()") + try { +// val obj = JSONObject() +// val jsFunName = obj.optString("updateCoin") +// val config = view.getGameConfig() +// val str = (jsFunName + "(" + Gson().toJson(config) + ")") +// callJs(str) + + val obj = JSONObject() + val jsFunName = obj.optString("updateCoin()") + callJs(jsFunName) + } catch (ex: Exception) { + ex.printStackTrace() + } + } + + @JavascriptInterface + public fun closeGame() { + logD("游戏调⽤ closeGame") + view.getActivity2()?.runOnUiThread { + showExitDialog() + } + } + + @JavascriptInterface + public fun pay() { + logD("游戏调⽤ pay") + view.getActivity2()?.runOnUiThread { + DialogUiHelper.showNeedCharge(view.getActivity2(), view.getDialogManager2()) + } + } + + @JavascriptInterface + private fun callJs(str: String) { + view.callJs(str) + } + + private fun showExitDialog() { + view.getDialogManager2().showOkCancelDialog( + R.string.tip_tips.getString(), + R.string.home_refresh_fungameview_01.getString(), + R.string.exit_text.getString(), + R.string.cancel.getString(), + false, false, true, object : OkCancelDialogListener { + override fun onOk() { + super.onCancel() + view?.getListener()?.onGameClose() + } + + override fun onCancel() { + } + }, null, false + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/webview/event/CloseDialogWebViewEvent.java b/app/src/main/java/com/chwl/app/ui/webview/event/CloseDialogWebViewEvent.java new file mode 100644 index 0000000..95103b0 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/webview/event/CloseDialogWebViewEvent.java @@ -0,0 +1,7 @@ +package com.chwl.app.ui.webview.event; + +/** + * create by lvzebiao @2019/12/3 + */ +public class CloseDialogWebViewEvent { +} diff --git a/app/src/main/java/com/chwl/app/ui/webview/event/H5NotifyClientEvent.java b/app/src/main/java/com/chwl/app/ui/webview/event/H5NotifyClientEvent.java new file mode 100644 index 0000000..548fde4 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/webview/event/H5NotifyClientEvent.java @@ -0,0 +1,15 @@ +package com.chwl.app.ui.webview.event; + +import com.chwl.core.base.BaseBusEvent; + +/** + * h5通知客户端的事件 + * Created by lvzebiao on 2019/2/25. + */ + +public class H5NotifyClientEvent extends BaseBusEvent{ + + public H5NotifyClientEvent(String data) { + super(data); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/webview/event/ShowNavEvent.java b/app/src/main/java/com/chwl/app/ui/webview/event/ShowNavEvent.java new file mode 100644 index 0000000..fef504a --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/webview/event/ShowNavEvent.java @@ -0,0 +1,19 @@ +package com.chwl.app.ui.webview.event; + +import lombok.Data; + +/** + * 初始化导航栏 + */ +@Data +public class ShowNavEvent { + private boolean isShowNav; + + public ShowNavEvent(boolean isShowNav) { + this.isShowNav = isShowNav; + } + + public boolean isShowNav() { + return isShowNav; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/webview/event/TaroPayResultEvent.java b/app/src/main/java/com/chwl/app/ui/webview/event/TaroPayResultEvent.java new file mode 100644 index 0000000..e33cdba --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/webview/event/TaroPayResultEvent.java @@ -0,0 +1,20 @@ +package com.chwl.app.ui.webview.event; + + +/** + * Created by MadisonRong on 26/06/2018. + */ + +public class TaroPayResultEvent { + + private int result; + + public int getResult() { + return result; + } + + public TaroPayResultEvent setResult(int result) { + this.result = result; + return this; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/webview/room_banner/RoomBannerTabAdapter.kt b/app/src/main/java/com/chwl/app/ui/webview/room_banner/RoomBannerTabAdapter.kt new file mode 100644 index 0000000..17ab03b --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/webview/room_banner/RoomBannerTabAdapter.kt @@ -0,0 +1,47 @@ +package com.chwl.app.ui.webview.room_banner + +import android.view.View +import android.widget.ImageView +import androidx.core.view.isInvisible +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.ui.utils.load +import com.chwl.core.home.bean.BannerInfo + +/** + * Created by Max on 2023/11/17 12:30 + * Desc: + **/ +class RoomBannerTabAdapter : + BaseQuickAdapter(R.layout.room_banner_item_tab) { + + private var selectedPosition = -1 + override fun convert(helper: BaseViewHolder, item: BannerInfo?) { + helper.getView(R.id.iv_content).load(item?.bannerUrl) + convertState(helper, item) + } + + override fun convertPayloads( + helper: BaseViewHolder, + item: BannerInfo?, + payloads: MutableList + ) { + super.convertPayloads(helper, item, payloads) + convertState(helper, item) + } + + private fun convertState(helper: BaseViewHolder, item: BannerInfo?) { + helper.getView(R.id.v_selector).isInvisible = + helper.absoluteAdapterPosition != selectedPosition + } + + fun getSelectedPosition(): Int { + return selectedPosition + } + + fun select(position: Int) { + this.selectedPosition = position + notifyItemRangeChanged(0, itemCount, true) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/webview/room_banner/RoomBannerWebDialogActivity.kt b/app/src/main/java/com/chwl/app/ui/webview/room_banner/RoomBannerWebDialogActivity.kt new file mode 100644 index 0000000..6f58978 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/webview/room_banner/RoomBannerWebDialogActivity.kt @@ -0,0 +1,91 @@ +package com.chwl.app.ui.webview.room_banner + +import android.content.Context +import android.content.Intent +import android.graphics.Color +import android.os.Bundle +import android.view.View +import android.view.WindowManager +import androidx.recyclerview.widget.RecyclerView +import com.example.lib_utils.UiUtils +import com.chwl.app.R +import com.chwl.app.ui.webview.CommonWebViewActivity +import com.chwl.core.home.bean.BannerInfo + + +/** + * Created by Max on 2023/11/17 11:38 + * Desc:房间内-Banner-WEB展示页面 + **/ +class RoomBannerWebDialogActivity : CommonWebViewActivity() { + + private var recyclerView: RecyclerView? = null + private var adapter: RoomBannerTabAdapter? = null + + companion object { + @JvmStatic + fun start(context: Context, position: Int, list: List) { + val newList = ArrayList() + newList.addAll(list) + val intent = Intent(context, RoomBannerWebDialogActivity::class.java) + intent.putExtra("position", position) + intent.putExtra("list", newList) + context.startActivity(intent) + } + } + + override fun getLayoutId(): Int { + return R.layout.room_banner_dialog + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_FULLSCREEN + or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) + window.setLayout( + WindowManager.LayoutParams.MATCH_PARENT, + WindowManager.LayoutParams.MATCH_PARENT + ) + val topView = findViewById(R.id.v_top) + topView.setOnClickListener { v: View? -> finish() } + val params = topView.layoutParams + params.height = UiUtils.dip2px(168f) + topView.layoutParams = params + webView.setBackgroundColor(Color.parseColor("#C9CBD1")) + recyclerView = findViewById(R.id.recyclerView) + val position = 0.coerceAtLeast(intent.getIntExtra("position", 0)) + val list = intent.getSerializableExtra("list") as? ArrayList +// if ((list?.size ?: 0) <= 1) { +// recyclerView?.isVisible = false +// } + adapter = RoomBannerTabAdapter().apply { + setOnItemClickListener { adapter, view, position -> + if (this@RoomBannerWebDialogActivity.adapter?.getSelectedPosition() == position) { + return@setOnItemClickListener + } + switchTab(position) + } + } + recyclerView?.adapter = adapter + adapter?.setNewData(list) + switchTab(position) + } + + private fun switchTab(position: Int) { + val url = adapter?.getItem(position)?.getSkipUri() + showWebView(url) + adapter?.select(position) + recyclerView?.post { + recyclerView?.scrollToPosition(position) + } + } + + override fun showWebView(url: String?) { + if (url.isNullOrEmpty()) { + return + } + super.showWebView(url) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/webview/room_banner/RoomWebDialogActivity.kt b/app/src/main/java/com/chwl/app/ui/webview/room_banner/RoomWebDialogActivity.kt new file mode 100644 index 0000000..545ee1d --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/webview/room_banner/RoomWebDialogActivity.kt @@ -0,0 +1,27 @@ +package com.chwl.app.ui.webview.room_banner + +import android.content.Context +import android.content.Intent +import com.chwl.app.ui.webview.DialogWebViewActivity +import com.chwl.app.ui.widget.rollviewpager.Util + +/** + * Created by Max on 2024/2/20 17:47 + * Desc:房间半屏Web弹窗 + **/ +class RoomWebDialogActivity : DialogWebViewActivity() { + + companion object { + fun start(context: Context?, url: String, showTitleBar: Boolean) { + if (context == null) return + val intent = Intent(context, RoomWebDialogActivity::class.java) + intent.putExtra("url", url) + intent.putExtra("showTitleBar", showTitleBar) + context.startActivity(intent) + } + } + + override fun getTopMargin(): Int { + return Util.dip2px(this, 168f) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/widget/Anticlockwise.java b/app/src/main/java/com/chwl/app/ui/widget/Anticlockwise.java new file mode 100644 index 0000000..c63e210 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/Anticlockwise.java @@ -0,0 +1,91 @@ +package com.chwl.app.ui.widget; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.util.AttributeSet; +import android.widget.Chronometer; + +import java.text.SimpleDateFormat; +import java.util.Date; + +@SuppressLint( + {"ViewConstructor", "SimpleDateFormat"}) +public class Anticlockwise extends Chronometer { + public Anticlockwise(Context context, AttributeSet attrs) { + super(context, attrs); + mTimeFormat = new SimpleDateFormat("mm:ss"); + this.setOnChronometerTickListener(listener); + } + + private long mTime; + private long mNextTime; + private OnTimeCompleteListener mListener; + private SimpleDateFormat mTimeFormat; + + public Anticlockwise(Context context) { + super(context); + + } + + public void reStart(long _time_s) { + if (_time_s == -1) { + mNextTime = mTime; + } else { + mTime = mNextTime = _time_s; + } + this.start(); + } + + public void reStart() { + reStart(-1); + } + + public void onResume() { + this.start(); + } + public void onPause() { + this.stop(); + } + + public void setTimeFormat(String pattern) { + mTimeFormat = new SimpleDateFormat(pattern); + } + + public void setOnTimeCompleteListener(OnTimeCompleteListener l) { + mListener = l; + } + + OnChronometerTickListener listener = new OnChronometerTickListener() { + @Override + public void onChronometerTick(Chronometer chronometer) { + if (mNextTime <= 0) { + if (mNextTime == 0) { + Anticlockwise.this.stop(); + if (null != mListener) + mListener.onTimeComplete(); + } + mNextTime = 0; + updateTimeText(); + return; + } + + mNextTime--; + + updateTimeText(); + } + }; + + public void initTime(long _time_s) { + mTime = mNextTime = _time_s; + updateTimeText(); + } + + private void updateTimeText() { + this.setText(mTimeFormat.format(new Date(mNextTime * 1000))); + } + + public interface OnTimeCompleteListener { + void onTimeComplete(); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/AppBarLayoutBehavior.java b/app/src/main/java/com/chwl/app/ui/widget/AppBarLayoutBehavior.java new file mode 100644 index 0000000..758b3b7 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/AppBarLayoutBehavior.java @@ -0,0 +1,176 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.widget.OverScroller; + +import androidx.coordinatorlayout.widget.CoordinatorLayout; + +import com.google.android.material.appbar.AppBarLayout; + +import org.jetbrains.annotations.NotNull; + +import java.lang.reflect.Field; + +public class AppBarLayoutBehavior extends AppBarLayout.Behavior { + + private static final String TAG = "AppbarLayoutBehavior"; + private static final int TYPE_FLING = 1; + private boolean isFlinging; + private boolean shouldBlockNestedScroll; + + public AppBarLayoutBehavior(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + public boolean onInterceptTouchEvent(@NotNull CoordinatorLayout parent, AppBarLayout child, MotionEvent ev) { + shouldBlockNestedScroll = isFlinging; + switch (ev.getActionMasked()) { + case MotionEvent.ACTION_DOWN: + //手指触摸屏幕的时候停止fling事件 + stopAppbarLayoutFling(child); + break; + default: + break; + } + return super.onInterceptTouchEvent(parent, child, ev); + } + + /** + * 反射获取私有的flingRunnable 属性,考虑support 28以后变量名修改的问题 + * @return Field + * @throws NoSuchFieldException + */ + private Field getFlingRunnableField() throws NoSuchFieldException { + Class superclass = this.getClass().getSuperclass(); + try { + // support design 27及一下版本 + Class headerBehaviorType = null; + if (superclass != null) { + headerBehaviorType = superclass.getSuperclass(); + } + if (headerBehaviorType != null) { + return headerBehaviorType.getDeclaredField("mFlingRunnable"); + }else { + return null; + } + } catch (NoSuchFieldException e) { + // 可能是28及以上版本 + Class headerBehaviorType = superclass.getSuperclass().getSuperclass(); + if (headerBehaviorType != null) { + return headerBehaviorType.getDeclaredField("flingRunnable"); + } else { + return null; + } + } + } + + /** + * 反射获取私有的scroller 属性,考虑support 28以后变量名修改的问题 + * @return Field + * @throws NoSuchFieldException + */ + private Field getScrollerField() throws NoSuchFieldException { + Class superclass = this.getClass().getSuperclass(); + try { + // support design 27及一下版本 + Class headerBehaviorType = null; + if (superclass != null) { + headerBehaviorType = superclass.getSuperclass(); + } + if (headerBehaviorType != null) { + return headerBehaviorType.getDeclaredField("mScroller"); + }else { + return null; + } + } catch (NoSuchFieldException e) { + // 可能是28及以上版本 + Class headerBehaviorType = superclass.getSuperclass().getSuperclass(); + if (headerBehaviorType != null) { + return headerBehaviorType.getDeclaredField("scroller"); + }else { + return null; + } + } + } + + /** + * 停止appbarLayout的fling事件 + * @param appBarLayout + */ + private void stopAppbarLayoutFling(AppBarLayout appBarLayout) { + //通过反射拿到HeaderBehavior中的flingRunnable变量 + try { + Field flingRunnableField = getFlingRunnableField(); + Field scrollerField = getScrollerField(); + if (flingRunnableField != null) { + flingRunnableField.setAccessible(true); + } + if (scrollerField != null) { + scrollerField.setAccessible(true); + } + Runnable flingRunnable = null; + if (flingRunnableField != null) { + flingRunnable = (Runnable) flingRunnableField.get(this); + } + OverScroller overScroller = (OverScroller) scrollerField.get(this); + if (flingRunnable != null) { + appBarLayout.removeCallbacks(flingRunnable); + flingRunnableField.set(this, null); + } + if (overScroller != null && !overScroller.isFinished()) { + overScroller.abortAnimation(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public boolean onStartNestedScroll(@NotNull CoordinatorLayout parent, @NotNull AppBarLayout child, + @NotNull View directTargetChild, View target, + int nestedScrollAxes, int type) { + stopAppbarLayoutFling(child); + return super.onStartNestedScroll(parent, child, directTargetChild, target, + nestedScrollAxes, type); + } + + @Override + public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, + AppBarLayout child, View target, + int dx, int dy, int[] consumed, int type) { + //type返回1时,表示当前target处于非touch的滑动, + //该bug的引起是因为appbar在滑动时,CoordinatorLayout内的实现NestedScrollingChild2接口的滑动 + //子类还未结束其自身的fling + //所以这里监听子类的非touch时的滑动,然后block掉滑动事件传递给AppBarLayout + if (type == TYPE_FLING) { + isFlinging = true; + } + if (!shouldBlockNestedScroll) { + super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type); + } + } + + @Override + public void onNestedScroll(@NotNull CoordinatorLayout coordinatorLayout, AppBarLayout child, + View target, int dxConsumed, int dyConsumed, int + dxUnconsumed, int dyUnconsumed, int type) { + if (!shouldBlockNestedScroll) { + super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, + dyConsumed, dxUnconsumed, dyUnconsumed, type); + } + } + + @Override + public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, @NotNull AppBarLayout abl, + View target, int type) { + super.onStopNestedScroll(coordinatorLayout, abl, target, type); + isFlinging = false; + shouldBlockNestedScroll = false; + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/widget/BonsellaJoinAttackButtonView.kt b/app/src/main/java/com/chwl/app/ui/widget/BonsellaJoinAttackButtonView.kt new file mode 100644 index 0000000..576dd68 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/BonsellaJoinAttackButtonView.kt @@ -0,0 +1,176 @@ +package com.chwl.app.ui.widget + +import android.animation.ObjectAnimator +import android.annotation.SuppressLint +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View +import android.widget.FrameLayout +import androidx.core.view.isGone +import com.chwl.app.databinding.ViewBonsellaJoinAttackButtonBinding +import com.chwl.core.utils.ComboUtil +import com.chwl.library.common.util.ClickUtils.click +import com.chwl.library.common.util.doLog +import com.example.lib_utils.ktx.singleClick + +class BonsellaJoinAttackButtonView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null +) : FrameLayout(context, attrs) { + + var onGiftComboEndListener: OnGiftComboEndListener? = null + private var comboNum = 0 + private var comboCount = 0 + + private val objectAnimator: ObjectAnimator by lazy { + ObjectAnimator.ofFloat(mBinding.pvBg, "percent", 100F, 0F).apply { + duration = DOWN_COUNT_TIME + } + } + + private var mBinding : ViewBonsellaJoinAttackButtonBinding = ViewBonsellaJoinAttackButtonBinding.inflate(LayoutInflater.from(context), this,true) + + fun getBtnView() = mBinding.tvText + fun getSvgaView() = mBinding.svga + + fun setComboClick(listener: OnClickListener) { + mBinding.tvText.singleClick (listener,300) + } + + init { + mBinding.ivBtn.isLongClickable = false + mBinding.pvBg.setProgressChangeListener{ + if(it == 0f){ + isGone = true + comboNum = 0 + comboCount = 0 + ComboUtil.comboCount = comboCount+1 + mBinding.tvNum.text = "" + onGiftComboEndListener?.onGiftComboEnd() + } + } + + mBinding.btnRoot.click { + "避免误触".doLog() + } + + } + + fun onBtnDown(){ + +// mBinding.ivBtn.animate().cancel() +// mBinding.ivBtn.animate() +// .scaleX(0.875f) +// .scaleY(0.875f) +// .setDuration(50) +// .withEndAction { +// onBtnUp() +// } +// .start() +// mBinding.pvBg.animate().cancel() +// mBinding.pvBg.animate() +// .scaleX(0.875f) +// .scaleY(0.875f) +// .setDuration(50) +// .start() +// mBinding.ivBg.animate().cancel() +// mBinding.ivBg.alpha = 0f +// mBinding.ivBg.scaleX = 1f +// mBinding.ivBg.scaleY = 1f + + mBinding.svga.stopAnimation() + mBinding.svga.startAnimation() + + + } + + private fun onBtnUp(){ + mBinding.ivBtn.animate() + .scaleX(1f) + .scaleY(1f) + .setDuration(50) + .withEndAction { } + .start() + mBinding.pvBg.animate() + .scaleX(1f) + .scaleY(1f) + .setDuration(50) + .start() + mBinding.ivBg.alpha = 1f + mBinding.ivBg.animate() + .alpha(0f) + .scaleX(1.3f) + .scaleY(1.3f) + .start() + } + + fun getComboNum():Int{ + return comboNum + } + + + fun isInCombo():Boolean{ + return comboNum > 0 + } + + fun cancel() { + objectAnimator.cancel() + mBinding.pvBg.percent = 0f + } + + fun start() { + objectAnimator.start() + } + + fun waitStart() { + mBinding.pvBg.percent = 100f + objectAnimator.pause() + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + cancel() + mBinding.svga.clear() + objectAnimator.removeAllListeners() + objectAnimator.removeAllUpdateListeners() + } + + /** + * 用于更新按钮上的文字 + */ + @SuppressLint("SetTextI18n") + fun updateNumber(num: Int) { + comboNum += num + comboCount++ + mBinding.tvNum.text = "x$comboCount" + mBinding.tvNum.scaleX = 1.3f + mBinding.tvNum.scaleY = 1.3f + mBinding.tvNum.animate() + .setDuration(100) + .scaleX(1f) + .scaleY(1f) + .start() + ComboUtil.comboCount = comboCount+1 + } + + fun interface OnGiftComboEndListener { + fun onGiftComboEnd() + } + + companion object { + /** + * 倒计时时间,毫秒为单位 + */ + const val DOWN_COUNT_TIME = 5 * 1000L + } + + fun showView(isVis : Boolean){ + if (isVis) { + if (visibility != View.VISIBLE) visibility = View.VISIBLE + }else{ + if (visibility == View.VISIBLE) visibility = View.INVISIBLE + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/widget/BonsellaJoinAttackLayout.kt b/app/src/main/java/com/chwl/app/ui/widget/BonsellaJoinAttackLayout.kt new file mode 100644 index 0000000..f17f21c --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/BonsellaJoinAttackLayout.kt @@ -0,0 +1,356 @@ +package com.chwl.app.ui.widget + +import android.animation.ObjectAnimator +import android.animation.PropertyValuesHolder +import android.annotation.SuppressLint +import android.content.Context +import android.os.Handler +import android.os.Looper +import android.os.Message +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View +import android.view.animation.Animation +import android.view.animation.AnimationUtils +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import androidx.appcompat.widget.AppCompatTextView +import androidx.core.view.isGone +import androidx.core.view.isVisible +import com.chwl.app.R +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.app.ui.utils.SoftPool +import com.chwl.core.gift.bean.BonsellaJoinAttack +import com.chwl.core.gift.bean.GiftMultiReceiverInfo +import com.chwl.core.gift.bean.GiftType +import com.chwl.core.utils.LogUtils +import com.chwl.library.common.util.setRL +import com.chwl.library.utils.ResUtil +import com.example.lib_utils.UiUtils +import java.util.LinkedList + +class BonsellaJoinAttackLayout @JvmOverloads constructor( + context: Context?, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0, + defStyleRes: Int = 0 +) : LinearLayout(context, attrs, defStyleAttr, defStyleRes){ + + private val showingList = LinkedList() + private val waitingList = LinkedList() + private val comboMap = linkedMapOf() + private val cacheView = SoftPool(2) + private val inflater = LayoutInflater.from(context) + + private val handle = Handler(Looper.getMainLooper()) { + if (it.what == 1) { + viewOut(it.obj as? BonsellaJoinAttack, false) + } + true + } + + init { + if(isInEditMode){ + inflater.inflate(R.layout.item_bonsella_join_attack_view, this, true) + inflater.inflate(R.layout.item_bonsella_join_attack_view, this, true) + } + orientation = VERTICAL + } + + /** + * 创建 + */ + private fun getComboChildView(): View { + val view = cacheView.acquire { + inflater.inflate(R.layout.item_bonsella_join_attack_view, this, false) + }.apply { + createViewHolder(this) + isVisible = true + } + return view + } + + /** + * add data + */ + fun add(bonsellaJoinAttack: BonsellaJoinAttack?) { + //没有绑定之前不能添加 + if (!isAttachedToWindow) { + return + } + if (bonsellaJoinAttack == null) { + return + } + + + var addToWaiting = true + for (comboInfo in showingList) { + if(comboInfo.sentUserid == bonsellaJoinAttack.sentUserid && comboInfo.giftId == bonsellaJoinAttack.giftId){ + comboInfo.giftNumber = bonsellaJoinAttack.giftNumber + comboInfo.comboCount = bonsellaJoinAttack.comboCount + comboInfo.receiverNumber = bonsellaJoinAttack.receiverNumber + updateNum(comboInfo) + addToWaiting = false + } + } + + for (comboInfo in waitingList) { + if(comboInfo.sentUserid == bonsellaJoinAttack.sentUserid && comboInfo.giftId == bonsellaJoinAttack.giftId){ + comboInfo.giftNumber = bonsellaJoinAttack.giftNumber + comboInfo.comboCount = bonsellaJoinAttack.comboCount + comboInfo.receiverNumber = bonsellaJoinAttack.receiverNumber + addToWaiting = false + } + } + + if(addToWaiting){ + waitingList.add(bonsellaJoinAttack) + } + + showNext() + } + + /** + * 更新数量 + */ + private fun updateNum(bonsellaJoinAttack: BonsellaJoinAttack) { + val view = comboMap[bonsellaJoinAttack] ?: return + val viewHolder = getViewHolder(view) + viewHolder?.refreshNum(bonsellaJoinAttack, true) + handle.removeMessages(1, bonsellaJoinAttack) + handle.sendMessageDelayed(Message.obtain(handle, 1, bonsellaJoinAttack), COMBO_STAY_TIME * 1000L) + } + + + + /** + * 显示下一个 + */ + private fun showNext() { + if(waitingList.isEmpty()){ + return + } + + val comboChildView = getComboChildView() + addView(comboChildView,0) + val giftComboInfo = waitingList.remove() + showingList.add(giftComboInfo) + + comboMap[giftComboInfo] = comboChildView + val viewHolder = getViewHolder(comboChildView) + viewHolder?.showUi(giftComboInfo) + viewAnimationIn(comboChildView) + + handle.sendMessageDelayed(Message.obtain(handle, 1, giftComboInfo), COMBO_STAY_TIME * 1000L) + + if(showingList.size > MAX_SHOWING){ + handle.removeMessages(1, showingList[0]) + viewOut(showingList.remove(), true) + return + } + } + + + /** + * 移除动画 + */ + private fun viewOut(bonsellaJoinAttack: BonsellaJoinAttack?, isDirectRemove: Boolean) { + bonsellaJoinAttack ?: return + val comboView = comboMap.remove(bonsellaJoinAttack) ?: return + + val runnable = { + val viewHolder = getViewHolder(comboView) + viewHolder?.clear() + if(!isDirectRemove){ + showingList.remove(bonsellaJoinAttack) + } + removeView(comboView) + cacheView.release(comboView) + showNext() + } + + if(isDirectRemove){ + comboView.isGone = true + post(runnable) + }else{ + val animOut = AnimationUtils.loadAnimation(context, R.anim.alpha_out) + animOut.setAnimationListener(object : Animation.AnimationListener { + override fun onAnimationStart(animation: Animation?) { + } + + override fun onAnimationEnd(animation: Animation?) { + post(runnable) + } + + override fun onAnimationRepeat(animation: Animation?) { + } + }) + comboView.startAnimation(animOut) + } + } + + + /** + * 飞入动画 + */ + private fun viewAnimationIn(view: View) { + view.alpha = 1f + val animIn = AnimationUtils.loadAnimation(context,if (UiUtils.isRtl(context)) R.anim.left_to_right else R.anim.right_to_left ) +// animIn.fillAfter = true +// animIn.isFillEnabled = true + view.startAnimation(animIn) + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + if(isInEditMode) return +// RoomMsgManager.addCustomMsgListener(this) + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + handle.removeCallbacksAndMessages(null) +// RoomMsgManager.removeCustomMsgListener(this) + } + + fun onRoomCustomMsg(giftInfo: GiftMultiReceiverInfo?) { + LogUtils.d(" GiftComboLayout onRoomCustomMsg " ) + if (giftInfo==null) return + if (giftInfo.comboCount == 0) return + if (giftInfo.gift != null && giftInfo.gift.giftType == GiftType.GIFT_TYPE_NORMAL + || giftInfo.gift.giftType == GiftType.GIFT_TYPE_SUPER_LUCKY + || giftInfo.gift.giftType == GiftType.GIFT_TYPE_LUCKY_24 + || giftInfo.gift.giftType == GiftType.GIFT_TYPE_BRAVO + || giftInfo.gift.giftType == GiftType.GIFT_TYPE_LUCKY_25 + ) { + val comboInfo = BonsellaJoinAttack().apply { + giftId = giftInfo.giftId + sentUserid = giftInfo.uid + sentUserName = giftInfo.nick + sentAvatar = giftInfo.avatar + receiverUserName = giftInfo.targetUsers?.getOrNull(0)?.nick?:"" + receiverNumber = giftInfo.targetUsers?.size?: giftInfo.targetUids?.size?: 1 + giftNumber = giftInfo.giftNum + giftImgUrl = giftInfo.gift?.giftUrl?:"" + comboCount = giftInfo.comboCount + isMulti = giftInfo.isMulti + } + add(comboInfo) + } + } + + + + private fun createViewHolder(view: View) { + getViewHolder(view) ?: ViewHolder(view) + } + + private fun getViewHolder(view: View): ViewHolder? { + return view.tag as? ViewHolder + } + + private inner class ViewHolder(view: View) { + var tvNumber: AppCompatTextView = view.findViewById(R.id.giftComboNumber) + var ivGift: ImageView = view.findViewById(R.id.giftImg) + var tvNick: TextView = view.findViewById(R.id.sentUserName) + var tvReceiverNick: TextView = view.findViewById(R.id.receiverUserName) + var ivAvatar: ImageView = view.findViewById(R.id.sentUserAvatar) + var ivLayoutBg: ImageView = view.findViewById(R.id.layoutBg) + + init { + view.tag = this + } + + @SuppressLint("SetTextI18n") + fun showUi(bonsellaJoinAttack: BonsellaJoinAttack) { + + ivLayoutBg.setRL() + + refreshNum(bonsellaJoinAttack) + tvNick.text = bonsellaJoinAttack.sentUserName + if (bonsellaJoinAttack.receiverNumber == 1) { + tvReceiverNick.text = bonsellaJoinAttack.receiverUserName + } else { + if (bonsellaJoinAttack.isMulti) { + tvReceiverNick.text = ResUtil.getString(R.string.Multiplayer) + } else { + tvReceiverNick.text = ResUtil.getString(R.string.All_mic) + } + } +// tvNumber.text = "x${giftComboInfo.giftNumber * giftComboInfo.receiverNumber * giftComboInfo.comboCount}" + ImageLoadUtils.loadImage(ivGift, bonsellaJoinAttack.giftImgUrl) + ImageLoadUtils.loadImage(ivAvatar, bonsellaJoinAttack.sentAvatar) + ivAvatar.tag = bonsellaJoinAttack + } + + /** + * 用于刷新数量 + */ + @SuppressLint("SetTextI18n") + fun refreshNum(bonsellaJoinAttack: BonsellaJoinAttack, isAnim: Boolean = false) { + val num = bonsellaJoinAttack.giftNumber * bonsellaJoinAttack.receiverNumber * bonsellaJoinAttack.comboCount + if(num == 0){ + tvNumber.isVisible = false + return + } +// val old = tvNumber.tag as? Int +// //兼容上一个比下一个数还要大 +// if (old != null && old > num) { +// return +// } + tvNumber.isVisible = true + tvNumber.tag = num + tvNumber.text = "x$num" + if (isAnim) { + tvNumber.animate().cancel() + tvNumber.requestLayout() + post { + val scaleUp: ObjectAnimator = ObjectAnimator.ofPropertyValuesHolder( + tvNumber, + PropertyValuesHolder.ofFloat(SCALE_X, 1f, 1.3f, 1f), + PropertyValuesHolder.ofFloat(SCALE_Y, 1f, 1.3f, 1f) + ) + scaleUp.setDuration(100) + scaleUp.start() + } + + } + } + + + /** + * 清空UI数据 + */ + fun clear() { + LogUtils.d(" ComboView clear -- clear ") + tvNumber.animate().cancel() + tvNumber.scaleX = 1f + tvNumber.scaleY = 1f + tvNumber.tag = 0 + ivAvatar.tag = null + } + } + + companion object { + /** + * 最大显示个数 + */ + const val MAX_SHOWING = 2 + + /** + * 连击停留时间 + */ + const val COMBO_STAY_TIME = 5 + } + +// override fun onClick(v: View) { +// val giftComboInfo = v.tag as? GiftComboInfo ?: return +// val sendUid = giftComboInfo.senderUid +// if (sendUid == 0L) { +// return +// } +// RoomUserInfoDialog.show(sendUid) +// } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/widget/ButtonItem.java b/app/src/main/java/com/chwl/app/ui/widget/ButtonItem.java new file mode 100644 index 0000000..972f868 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/ButtonItem.java @@ -0,0 +1,108 @@ +package com.chwl.app.ui.widget; + + +import android.view.View; + +import com.chwl.app.R; + +public class ButtonItem { + public static final int BUTTON_TYPE_NORMAL = 0; + public static final int BUTTON_TYPE_CANCEL = 1; + + /**房间个人信息的弹窗button,放在网格里面的*/ + public static final int BUTTON_TYPE_GIRD = 2; + /**房间个人信息的弹窗button,放在底下的,和主页按钮一起的*/ + public static final int BUTTON_TYPE_BOTTOM = 3; + + + /** 发送礼物 */ + public static final int SEND_GIFT_ITEM = 0; + /** 锁坑 */ + public static final int SEND_LOCK_MIC_ITEM = 1; + /** 踢下麦 个人弹窗 */ + public static final int KICKDOWN_MIC_ITEM = 2; + /** 踢出房间 */ + public static final int KICKOUT_ROOM_ITEM = 3; + /** 查看个人信息 */ + public static final int SEND_SHOW_USER_INCO_ITEM = 4; + /** 下麦 */ + public static final int DOWN_MIC_ITEM = 5; + /** 释放麦 */ + public static final int SEND_FREE_MIC_ITEM = 6; + /** 设置管理员 */ + public static final int SET_MANAGER_ITEM = 7; + /** 取消管理员 */ + public static final int CLEAR_MANAGER_ITEM = 11; + /** 加入黑名单 */ + public static final int MARK_BLACK_ITEM = 8; + + /** 个人资料开麦 */ + public static final int OPEN_MUTE_ITEM = 9; + /** 个人资料闭麦 */ + public static final int CLOSE_MUTE_ITEM = 10; + /** 抱上麦 */ + public static final int SEND_INVITE_MIC_ITEM = 12; + /** 发起竞拍 */ + public static final int START_AUCTION = 13; + /** 送魔法 */ + public static final int SEND_MAGIC_ITEM = 14; + /** 送装扮 */ + public static final int SEND_DECORATION_ITEM = 15; + /** 关注or取消 */ + public static final int ATTENT_ITEM = 15; + + public String mText; + public int textColor; + public int mLayout; + public View mView; + public OnClickListener mClickListener; + public int mButtonType; + public int mTheme = -1; + public int mIcon; + + public ButtonItem() { + } + + public ButtonItem(String text, int icon, OnClickListener clickListener) { + this(text, icon, BUTTON_TYPE_GIRD, R.layout.room_user_dialog_grid_button, clickListener); + } + +// public ButtonItem(String text, int buttonType, OnClickListener l) { +// mText = text; +// mClickListener = l; +// mButtonType = buttonType; +// resourceID = R.layout.layout_common_popup_dialog_button; +// +// } + public ButtonItem(String text, OnClickListener l) { + this(text, 0, BUTTON_TYPE_NORMAL, R.layout.layout_common_popup_dialog_button, l); + } + + public ButtonItem(String text, int icon, int buttonType, int layout, OnClickListener clickListener) { + mText = text; + mIcon = icon; + mClickListener = clickListener; + mButtonType = buttonType; + mLayout = layout; + } + + public void setText(String text) { + this.mText = text; + } + + public int getTextColor() { + return textColor; + } + + public void setTextColor(int textColor) { + this.textColor = textColor; + } + + public void setClickListener(OnClickListener mClickListener) { + this.mClickListener = mClickListener; + } + + public interface OnClickListener { + void onClick(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/widget/CharAlignTextView.java b/app/src/main/java/com/chwl/app/ui/widget/CharAlignTextView.java new file mode 100644 index 0000000..f41499f --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/CharAlignTextView.java @@ -0,0 +1,68 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.text.TextPaint; +import android.text.TextUtils; +import android.util.AttributeSet; + +import androidx.annotation.Nullable; +import androidx.appcompat.widget.AppCompatTextView; + +/** + * create by lvzebiao @2019/12/2 + */ +public class CharAlignTextView extends AppCompatTextView { + + private TextPaint textPaint; + + private float textYOffset; + + private Rect rect; + + public CharAlignTextView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + + rect = new Rect(); + textPaint = getPaint(); + //textPaint.setColor(textColor); + textPaint.setTextAlign(Paint.Align.CENTER); + //textPaint.setTextSize(textSize); + Paint.FontMetrics textFontMetrics = textPaint.getFontMetrics(); + /* + * drawText从baseline开始,baseline的值为0,baseline的上面为负值,baseline的下面为正值, + * 即这里ascent为负值,descent为正值。 + * 比如ascent为-20,descent为5,那需要移动的距离就是20 - (20 + 5)/ 2 + */ + textYOffset = -textFontMetrics.ascent - (-textFontMetrics.ascent + textFontMetrics.descent) / 2; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int height = MeasureSpec.getSize(heightMeasureSpec); + int textWidth = 0; + String text = getText().toString(); + if (!TextUtils.isEmpty(getText()) && text.length() >= 2) { + //测量文本的长度 + rect.setEmpty(); + textPaint.getTextBounds(text, 0, text.length(), rect); + textWidth = rect.width(); + } + //noinspection SuspiciousNameCombination + setMeasuredDimension(textWidth, height); + } + + @Override + protected void onDraw(Canvas canvas) { + if (getCurrentTextColor() != 0) { + textPaint.setColor(getCurrentTextColor()); + } + String text = getText().toString(); + if (!TextUtils.isEmpty(text)) { + canvas.drawText(text, (float) getWidth() / 2, (float) getHeight() / 2 + textYOffset, + textPaint); + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/ColorfulRingProgressView.kt b/app/src/main/java/com/chwl/app/ui/widget/ColorfulRingProgressView.kt new file mode 100644 index 0000000..817ceb7 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/ColorfulRingProgressView.kt @@ -0,0 +1,295 @@ +package com.chwl.app.ui.widget + +import android.content.Context +import android.graphics.Canvas +import android.graphics.LinearGradient +import android.graphics.Paint +import android.graphics.RectF +import android.graphics.Shader +import android.util.AttributeSet +import android.view.View +import androidx.annotation.Keep +import com.chwl.app.R +import com.chwl.library.utils.SizeUtils + +class ColorfulRingProgressView(context: Context, attrs: AttributeSet?) : View(context, attrs) { + + private var mPercent = 0f + + private var mStrokeWidth = 0f + + private var mStartAngle = 0f + + private var mFgColorStart = 0xffb900 + + private var mFgColorEnd = 0xffb900 + + private var widthDiff = 3 + + private var mBgColor = -0xa0a0b + + private var mShader: LinearGradient? = null + + private var mOval = RectF() + + private val progressPaint = Paint() + + private var mNegative = false //������ ���㵹���������� ��100-0�� + + private val circlePaint = Paint() + + + + private var progressChangeListener: OnProgressChangeListener? = null + + + + init { + + val a = context.theme.obtainStyledAttributes(attrs, R.styleable.ColorfulRingProgressView, 0, 0) + + try { + + mFgColorEnd = a.getColor(R.styleable.ColorfulRingProgressView_fgColorEnd, 0xffb900) + + mFgColorStart = a.getColor(R.styleable.ColorfulRingProgressView_fgColorStart, 0xffb900) + + mPercent = a.getFloat(R.styleable.ColorfulRingProgressView_currentPercent, 75f) + + mStartAngle = a.getFloat(R.styleable.ColorfulRingProgressView_ringProgress_startAngle, 0f) + 270 + + mStrokeWidth = a.getDimensionPixelSize(R.styleable.ColorfulRingProgressView_circleStrokeWidth, 21).toFloat() + + widthDiff = a.getDimensionPixelSize(R.styleable.ColorfulRingProgressView_circle_width_diff, 3) + + mBgColor = a.getColor(R.styleable.ColorfulRingProgressView_circle_bg_color, -0xa0a0b) + + mNegative = a.getBoolean(R.styleable.ColorfulRingProgressView_crp_negative, false) + + } finally { + + a.recycle() + + } + + + + progressPaint.isAntiAlias = true + + progressPaint.style = Paint.Style.STROKE + + progressPaint.strokeWidth = mStrokeWidth + + progressPaint.strokeCap = Paint.Cap.ROUND + + circlePaint.style = Paint.Style.STROKE + + circlePaint.isAntiAlias = true + + circlePaint.color = mBgColor + + circlePaint.strokeWidth = mStrokeWidth + widthDiff + + } + + + + override fun onDraw(canvas: Canvas) { + + super.onDraw(canvas) + + + + canvas.drawCircle( + + (mOval.right + mOval.left) / 2, + + (mOval.bottom + mOval.top) / 2, + + (mOval.bottom - mOval.top) / 2, + + circlePaint + + ) + + progressPaint.setShader(mShader) + + if (mNegative) { + + canvas.drawArc(mOval, mStartAngle + (100 - mPercent) * 3.6f, 360 - (100 - mPercent) * 3.6f, false, progressPaint) + + } else { + + canvas.drawArc(mOval, mStartAngle, mPercent * 3.6f, false, progressPaint) + + } + + } + + + + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + + super.onSizeChanged(w, h, oldw, oldh) + + updateOval() + + mShader = LinearGradient( + + mOval.left, mOval.top, + + mOval.left, mOval.bottom, mFgColorStart, mFgColorEnd, Shader.TileMode.MIRROR + + ) + + } + + + + @set:Keep + var percent: Float + get() = mPercent + set(mPercent) { + this.mPercent = mPercent + postInvalidate() + if (progressChangeListener != null) { + progressChangeListener?.onProgressChange(mPercent) + } + } + + + + fun setProgressChangeListener(progressChangeListener: OnProgressChangeListener?) { + + this.progressChangeListener = progressChangeListener + + } + + + + var strokeWidth: Float + + get() = mStrokeWidth + + set(mStrokeWidth) { + + this.mStrokeWidth = mStrokeWidth + + progressPaint.strokeWidth = mStrokeWidth + + updateOval() + + refreshTheLayout() + + } + private fun updateOval() { + + val xp = paddingLeft + paddingRight + + val yp = paddingBottom + paddingTop + + mOval = RectF( + + paddingLeft + mStrokeWidth, paddingTop + mStrokeWidth, + + paddingLeft + (width - xp) - mStrokeWidth, + + paddingTop + (height - yp) - mStrokeWidth + + ) + + } + + + + fun setStrokeWidthDp(dp: Float) { + + this.mStrokeWidth = SizeUtils.dp2px(context,dp).toFloat() + + progressPaint.strokeWidth = mStrokeWidth + + updateOval() + + refreshTheLayout() + + } + + + + private fun refreshTheLayout() { + + invalidate() + + requestLayout() + + } + + + + var fgColorStart: Int + + get() = mFgColorStart + + set(mFgColorStart) { + + this.mFgColorStart = mFgColorStart + + mShader = LinearGradient( + + mOval.left, mOval.top, + + mOval.left, mOval.bottom, mFgColorStart, mFgColorEnd, Shader.TileMode.MIRROR + + ) + + refreshTheLayout() + + } + + + + var fgColorEnd: Int + + get() = mFgColorEnd + + set(mFgColorEnd) { + + this.mFgColorEnd = mFgColorEnd + + mShader = LinearGradient( + + mOval.left, mOval.top, + + mOval.left, mOval.bottom, mFgColorStart, mFgColorEnd, Shader.TileMode.MIRROR + + ) + + refreshTheLayout() + + } + + + + + + var startAngle: Float + + get() = mStartAngle + + set(mStartAngle) { + + this.mStartAngle = mStartAngle + 270 + + refreshTheLayout() + + } + + + + fun interface OnProgressChangeListener { + + fun onProgressChange(mPercent: Float) + + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/CustomExpandableText.java b/app/src/main/java/com/chwl/app/ui/widget/CustomExpandableText.java new file mode 100644 index 0000000..3402fac --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/CustomExpandableText.java @@ -0,0 +1,257 @@ +package com.chwl.app.ui.widget; + +import android.annotation.TargetApi; +import android.content.Context; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.util.SparseBooleanArray; +import android.view.MotionEvent; +import android.view.View; +import android.view.animation.Animation; +import android.view.animation.Transformation; +import android.widget.ImageButton; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.chwl.app.R; + +public class CustomExpandableText extends LinearLayout implements View.OnClickListener { + protected TextView mTv; + protected ImageButton mButton; + private boolean mRelayout; + private boolean mCollapsed; + private int mCollapsedHeight; + private int mTextHeightWithMaxLines; + private int mMaxCollapsedLines; + private int mMarginBetweenTxtAndBottom; + private Drawable mExpandDrawable; + private Drawable mCollapseDrawable; + private int mAnimationDuration; + private boolean mAnimating; + private CustomExpandableText.OnExpandStateChangeListener mListener; + private SparseBooleanArray mCollapsedStatus; + private int mPosition; + + public CustomExpandableText(Context context) { + this(context, null); + } + + public CustomExpandableText(Context context, AttributeSet attrs) { + super(context, attrs); + this.mCollapsed = true; + this.init(attrs); + } + + @TargetApi(11) + public CustomExpandableText(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + this.mCollapsed = true; + this.init(attrs); + } + + public void setOrientation(int orientation) { + super.setOrientation(orientation); + } + + public void onClick(View view) { + if (this.mButton.getVisibility() == VISIBLE) { + this.mCollapsed = !this.mCollapsed; + this.mButton.setImageDrawable(this.mCollapsed ? this.mExpandDrawable : this.mCollapseDrawable); + if (this.mCollapsedStatus != null) { + this.mCollapsedStatus.put(this.mPosition, this.mCollapsed); + } + + this.mAnimating = true; + CustomExpandableText.ExpandCollapseAnimation animation; + if (this.mCollapsed) { + if (this.mCollapsedHeight == 0) + this.mCollapsedHeight = this.getHeight(); + animation = new CustomExpandableText.ExpandCollapseAnimation(this, this.getHeight(), this.mCollapsedHeight); + } else { + if (this.mTextHeightWithMaxLines == 0) + this.mTextHeightWithMaxLines = this.getHeight(); + animation = new CustomExpandableText.ExpandCollapseAnimation(this, this.getHeight(), this.mTextHeightWithMaxLines); + } + + animation.setFillAfter(true); + animation.setAnimationListener(new Animation.AnimationListener() { + public void onAnimationStart(Animation animation) { + } + + public void onAnimationEnd(Animation animation) { + CustomExpandableText.this.clearAnimation(); + CustomExpandableText.this.mAnimating = false; + if (CustomExpandableText.this.mListener != null) { + CustomExpandableText.this.mListener.onExpandStateChanged(CustomExpandableText.this.mTv, !CustomExpandableText.this.mCollapsed); + } + + } + + public void onAnimationRepeat(Animation animation) { + } + }); + this.clearAnimation(); + this.startAnimation(animation); + } + } + + public boolean onInterceptTouchEvent(MotionEvent ev) { + return this.mAnimating; + } + + protected void onFinishInflate() { + super.onFinishInflate(); + this.findViews(); + } + + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (this.mRelayout && this.getVisibility() != GONE) { + this.mRelayout = false; + this.mTv.setMaxLines(2147483647); + + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + if (this.mTv.getLineCount() > this.mMaxCollapsedLines) { + this.mTextHeightWithMaxLines = getRealTextViewHeight(this.mTv); + + if (this.mCollapsed) { + this.mTv.setMaxLines(this.mMaxCollapsedLines); + } + + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + if (this.mCollapsed) { + this.mTv.post(() -> + CustomExpandableText.this.mMarginBetweenTxtAndBottom = CustomExpandableText.this.getHeight() - CustomExpandableText.this.mTv.getHeight() + ); + } + + } + } else { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + + //避免首次高度获取失败 + if (this.mCollapsedHeight == 0) + this.mCollapsedHeight = this.getMeasuredHeight(); + } + + public void setOnExpandStateChangeListener(@Nullable CustomExpandableText.OnExpandStateChangeListener listener) { + this.mListener = listener; + } + + public void setText(@Nullable CharSequence text) { + this.mRelayout = true; + this.mTv.setText(text); + this.setVisibility(TextUtils.isEmpty(text) ? GONE : VISIBLE); + } + + public void setTextColor(int textColor) { + this.mTv.setTextColor(textColor); + } + + public void setText(@Nullable CharSequence text, @NonNull SparseBooleanArray collapsedStatus, int position) { + this.mCollapsedStatus = collapsedStatus; + this.mPosition = position; + boolean isCollapsed = collapsedStatus.get(position, true); + this.clearAnimation(); + this.mCollapsed = isCollapsed; + this.mButton.setImageDrawable(this.mCollapsed ? this.mExpandDrawable : this.mCollapseDrawable); + this.setText(text); + this.getLayoutParams().height = -2; + this.requestLayout(); + } + + @Nullable + public CharSequence getText() { + return this.mTv == null ? "" : this.mTv.getText(); + } + + private void init(AttributeSet attrs) { + TypedArray typedArray = this.getContext().obtainStyledAttributes(attrs, R.styleable.CustomExpandableText); + this.mMaxCollapsedLines = typedArray.getInt(R.styleable.CustomExpandableText_cus_maxCollapsedLines, 8); + this.mAnimationDuration = typedArray.getInt(R.styleable.CustomExpandableText_cus_animDuration, 300); + this.mExpandDrawable = typedArray.getDrawable(R.styleable.CustomExpandableText_cus_expandDrawable); + this.mCollapseDrawable = typedArray.getDrawable(R.styleable.CustomExpandableText_cus_collapseDrawable); + if (this.mExpandDrawable == null) { + this.mExpandDrawable = getDrawable(this.getContext(), R.drawable.ic_textview_close); + } + + if (this.mCollapseDrawable == null) { + this.mCollapseDrawable = getDrawable(this.getContext(), R.drawable.ic_textview_open); + } + + typedArray.recycle(); + this.setVisibility(GONE); + } + + private void findViews() { + this.mTv = this.findViewById(R.id.cus_expandable_text); + this.mTv.setOnClickListener(this); + this.mButton = this.findViewById(R.id.cus_expand_collapse); + this.mButton.setImageDrawable(this.mCollapsed ? this.mExpandDrawable : this.mCollapseDrawable); + this.mButton.setOnClickListener(this); + } + + private static boolean isPostLollipop() { + return Build.VERSION.SDK_INT >= 21; + } + + @TargetApi(21) + private static Drawable getDrawable(@NonNull Context context, int resId) { + Resources resources = context.getResources(); + return isPostLollipop() ? resources.getDrawable(resId, context.getTheme()) : resources.getDrawable(resId); + } + + private static int getRealTextViewHeight(@NonNull TextView textView) { + int textHeight = textView.getLayout().getLineTop(textView.getLineCount()); + int padding = textView.getCompoundPaddingTop() + textView.getCompoundPaddingBottom(); + + return textHeight + padding; + } + + public interface OnExpandStateChangeListener { + void onExpandStateChanged(TextView var1, boolean var2); + } + + class ExpandCollapseAnimation extends Animation { + private final View mTargetView; + private final int mStartHeight; + private final int mEndHeight; + + ExpandCollapseAnimation(View view, int startHeight, int endHeight) { + this.mTargetView = view; + this.mStartHeight = startHeight; + this.mEndHeight = endHeight; + this.setDuration((long)CustomExpandableText.this.mAnimationDuration); + } + + protected void applyTransformation(float interpolatedTime, Transformation t) { + int newHeight = (int)((float)(this.mEndHeight - this.mStartHeight) * interpolatedTime + (float)this.mStartHeight); + + if (mStartHeight < mEndHeight) { + CustomExpandableText.this.mTv.setMaxHeight(newHeight + CustomExpandableText.this.mMarginBetweenTxtAndBottom); + this.mTargetView.getLayoutParams().height = newHeight + CustomExpandableText.this.mMarginBetweenTxtAndBottom; + } else { + CustomExpandableText.this.mTv.setMaxHeight(newHeight - CustomExpandableText.this.mMarginBetweenTxtAndBottom); + this.mTargetView.getLayoutParams().height = newHeight; + } + + this.mTargetView.requestLayout(); + } + + public void initialize(int width, int height, int parentWidth, int parentHeight) { + super.initialize(width, height, parentWidth, parentHeight); + } + + public boolean willChangeBounds() { + return true; + } + } +} + diff --git a/app/src/main/java/com/chwl/app/ui/widget/DatingSelectDialog.kt b/app/src/main/java/com/chwl/app/ui/widget/DatingSelectDialog.kt new file mode 100644 index 0000000..c088fbe --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/DatingSelectDialog.kt @@ -0,0 +1,24 @@ +package com.chwl.app.ui.widget + +import com.netease.nim.uikit.common.util.sys.ScreenUtil +import com.chwl.app.R +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.databinding.DialogDatingSelectBinding +import com.chwl.core.room.event.DatingSelectUserEvent +import com.chwl.library.utils.ResUtil +import org.greenrobot.eventbus.EventBus + +class DatingSelectDialog(val position: Int, val uid: Long, private val myUid: Long, val roomUid: Long) : BaseDialogFragment() { + + override fun init() { + width = ScreenUtil.dip2px(200f) + binding?.tvMessage?.text = ResUtil.getString(R.string.ui_widget_datingselectdialog_01) + (position + 1) + ResUtil.getString(R.string.ui_widget_datingselectdialog_02) + binding?.btnCancel?.setOnClickListener { + dismissAllowingStateLoss() + } + binding?.btnOk?.setOnClickListener { + EventBus.getDefault().post(DatingSelectUserEvent(uid, myUid, roomUid)) + dismissAllowingStateLoss() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/widget/DefaultToolBar.java b/app/src/main/java/com/chwl/app/ui/widget/DefaultToolBar.java new file mode 100644 index 0000000..79cd252 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/DefaultToolBar.java @@ -0,0 +1,94 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.annotation.Nullable; +import androidx.appcompat.widget.Toolbar; +import androidx.core.content.ContextCompat; + +import com.chwl.app.R; + +/** + *

默认工具toolbar 界面

+ * + * @author Administrator + * @date 2017/11/29 + */ +public class DefaultToolBar extends Toolbar implements View.OnClickListener { + private TextView mTvCenterTitle; + private TextView mTvRightText; + + public DefaultToolBar(Context context) { + this(context, null); + } + + public DefaultToolBar(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public DefaultToolBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + inflate(context, R.layout.default_toolbar_layout, this); + //ThemeOverlay.AppCompat.Dark.ActionBar + + MarginLayoutParams layoutParams = new MarginLayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, + getResources().getDimensionPixelOffset(R.dimen.common_toolbar_height)); + setLayoutParams(layoutParams); + setContentInsetsAbsolute(0, 0); + setContentInsetsRelative(0, 0); + setBackgroundColor(ContextCompat.getColor(context,R.color.white)); + setPopupTheme(R.style.AppTheme_PopupOverlay); + setId(R.id.toolbar); + mTvCenterTitle = (TextView) findViewById(R.id.tv_center_title); + mTvRightText = (TextView) findViewById(R.id.tv_right_text); + + + mTvRightText.setVisibility(GONE); + mTvRightText.setOnClickListener(this); + } + + public void setCenterTitle(int resId) { + mTvCenterTitle.setText(resId); + } + + public void setCenterTitle(CharSequence title) { + mTvCenterTitle.setText(title); + } + + public void setRightText(CharSequence rightText) { + mTvRightText.setVisibility(TextUtils.isEmpty(rightText) ? GONE : VISIBLE); + mTvRightText.setText(rightText); + } + + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.toolbar: + + break; + case R.id.tv_right_text: + if (mOnRightTextClickListener != null) { + mOnRightTextClickListener.onRightTextClick(); + } + break; + default: + } + } + + private OnRightTextClickListener mOnRightTextClickListener; + + public void setOnRightTextClickListener(OnRightTextClickListener onRightTextClickListener) { + mOnRightTextClickListener = onRightTextClickListener; + } + + public interface OnRightTextClickListener { + void onRightTextClick(); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/DividerItemDecoration.java b/app/src/main/java/com/chwl/app/ui/widget/DividerItemDecoration.java new file mode 100644 index 0000000..5292628 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/DividerItemDecoration.java @@ -0,0 +1,119 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.util.TypedValue; +import android.view.View; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.chwl.app.R; +import com.chwl.library.utils.ResUtil; + + +/** + * Created by moon.zhong on 2015/2/11. + */ +public class DividerItemDecoration extends RecyclerView.ItemDecoration{ + + /* + * RecyclerView的布局方向,默认先赋值 + * 为纵向布局 + * RecyclerView 布局可横向,也可纵向 + * 横向和纵向对应的分割想画法不一样 + * */ + private int mOrientation = LinearLayoutManager.VERTICAL ; + + /** + * item之间分割线的size,默认为1 + */ + private int mItemSize = 1 ; + + /** + * 绘制item分割线的画笔,和设置其属性 + * 来绘制个性分割线 + */ + private Paint mPaint ; + + /** + * 构造方法传入布局方向,不可不传 + * @param context + * @param orientation + */ + public DividerItemDecoration(Context context, int orientation, int mItemSize, int colorResId) { + this.mOrientation = orientation; + this.mItemSize = mItemSize; + if(orientation != LinearLayoutManager.VERTICAL && orientation != LinearLayoutManager.HORIZONTAL){ + throw new IllegalArgumentException(ResUtil.getString(R.string.ui_widget_divideritemdecoration_01)) ; + } + mItemSize = (int) TypedValue.applyDimension(mItemSize, TypedValue.COMPLEX_UNIT_DIP,context.getResources().getDisplayMetrics()); + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG) ; + mPaint.setColor(context.getResources().getColor(colorResId)); + /*设置填充*/ + mPaint.setStyle(Paint.Style.FILL); + } + + @Override + public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { + if(mOrientation == LinearLayoutManager.VERTICAL){ + drawVertical(c,parent) ; + }else { + drawHorizontal(c,parent) ; + } + } + + /** + * 绘制纵向 item 分割线 + * @param canvas + * @param parent + */ + private void drawVertical(Canvas canvas, RecyclerView parent){ + final int left = parent.getPaddingLeft() ; + final int right = parent.getMeasuredWidth() - parent.getPaddingRight() ; + final int childSize = parent.getChildCount() ; + for(int i = 0 ; i < childSize ; i ++){ + final View child = parent.getChildAt( i ) ; + RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams(); + final int top = child.getBottom() + layoutParams.bottomMargin ; + final int bottom = top + mItemSize ; + canvas.drawRect(left,top,right,bottom,mPaint); + } + } + + /** + * 绘制横向 item 分割线 + * @param canvas + * @param parent + */ + private void drawHorizontal(Canvas canvas, RecyclerView parent){ + final int top = parent.getPaddingTop() ; + final int bottom = parent.getMeasuredHeight() - parent.getPaddingBottom() ; + final int childSize = parent.getChildCount() ; + for(int i = 0 ; i < childSize ; i ++){ + final View child = parent.getChildAt( i ) ; + RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams(); + final int left = child.getRight() + layoutParams.rightMargin ; + final int right = left + mItemSize ; + canvas.drawRect(left,top,right,bottom,mPaint); + } + } + + /** + * 设置item分割线的size + * @param outRect + * @param view + * @param parent + * @param state + */ + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { + if(mOrientation == LinearLayoutManager.VERTICAL){ + outRect.set(0,0,0,mItemSize); + }else { + outRect.set(0,0,mItemSize,0); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/widget/DividerUtil.java b/app/src/main/java/com/chwl/app/ui/widget/DividerUtil.java new file mode 100644 index 0000000..ebd610f --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/DividerUtil.java @@ -0,0 +1,80 @@ +package com.chwl.app.ui.widget; + +import android.graphics.Rect; +import android.view.View; + +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.chwl.library.utils.SizeUtils; + +public class DividerUtil { + public static void addhorizontalDivider(RecyclerView recyclerView, float dp) { + final int px = SizeUtils.dp2px(recyclerView.getContext(), dp); + recyclerView.addItemDecoration(new RecyclerView.ItemDecoration() { + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { + super.getItemOffsets(outRect, view, parent, state); + outRect.set(0, 0, px, 0); + } + }); + } + + /** + * + * 添加水平间隔 + * @param dp 普通间隔 比如有个些界面10dp间隔 + * @param lastDp 最后一项间隔,为15dp + */ + public static void addhorizontalDivider(RecyclerView recyclerView, float dp, float lastDp) { + final int px = SizeUtils.dp2px(recyclerView.getContext(), dp); + final int lastPx = SizeUtils.dp2px(recyclerView.getContext(), lastDp); + recyclerView.addItemDecoration(new RecyclerView.ItemDecoration() { + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { + super.getItemOffsets(outRect, view, parent, state); + //最后一项的间距重新画 + int position = parent.getChildAdapterPosition(view); + if (lastPx > 0 && position == (parent.getAdapter().getItemCount() - 1)) { + outRect.set(0, 0, lastPx, 0); + } else { + outRect.set(0, 0, px, 0); + } + + } + }); + } + + /** + * 先简单添加,后续再优化成通用方法 + * @param recyclerView recyclerView + * @param dp dp + */ + public static void addGridlDivider(RecyclerView recyclerView, float dp) { + final int px = SizeUtils.dp2px(recyclerView.getContext(), dp); + int spanCount = ((GridLayoutManager) recyclerView.getLayoutManager()).getSpanCount(); + recyclerView.addItemDecoration(new RecyclerView.ItemDecoration() { + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { + super.getItemOffsets(outRect, view, parent, state); + int pos = parent.getChildAdapterPosition(view); + int top; + if (pos < spanCount) { // 第一行 + top = px; + } else { + top = 0; + } + int left, right; + if (pos % spanCount == 0) { //第一列 + left = 0; + right = px / 2; + } else { + left = px / 2; + right = 0; + } + outRect.set(left, top, right, px); + } + }); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/EdgeTransparentView.java b/app/src/main/java/com/chwl/app/ui/widget/EdgeTransparentView.java new file mode 100644 index 0000000..b3fc66c --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/EdgeTransparentView.java @@ -0,0 +1,141 @@ +/* + * Copyright 2017. SHENQINCI(沈钦赐)<946736079@qq.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.LinearGradient; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.Shader; +import android.util.AttributeSet; +import android.view.View; +import android.widget.FrameLayout; + +import com.chwl.app.R; + + +/** + * 任意View边沿透明,默认高度为高度的一半(需求就是一半...) + * Created by shenqinci on 2016/12/3. + */ +public class EdgeTransparentView extends FrameLayout { + private Paint mPaint; + private int position; + private float drawSize; + + private int topMask = 0x01; + private int bottomMask = topMask << 1; + private int leftMask = topMask << 2; + private int rightMask = topMask << 3; + + private int mWidth; + private int mHeight; + + public EdgeTransparentView(Context context) { + this(context, null); + } + + public EdgeTransparentView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public EdgeTransparentView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context, attrs); + } + + private void init(Context context, AttributeSet attrs) { + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mPaint.setStyle(Paint.Style.FILL); + mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); + + + final TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.EdgeTransparentView); + position = typedArray.getInt(R.styleable.EdgeTransparentView_edge_position, 0); + drawSize = typedArray.getDimension(R.styleable.EdgeTransparentView_edge_width, 0); + typedArray.recycle(); + } + + + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + mWidth = getWidth(); + mHeight = getHeight(); + if (drawSize == 0) drawSize = mHeight / 2f; + initShader(); + } + + //渐变颜色 + private final int[] mGradientColors = {0xffffffff, 0x00000000}; + //渐变位置 + private final float[] mGradientPosition = new float[]{0, 1}; + + private void initShader() { + mPaint.setShader(new LinearGradient(0, 0, 0, drawSize, mGradientColors, mGradientPosition, Shader.TileMode.CLAMP)); + } + + + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + int layerSave = canvas.saveLayer(0, 0, getWidth(), getHeight(), null, Canvas.ALL_SAVE_FLAG); + boolean drawChild = super.drawChild(canvas, child, drawingTime); + if (position == 0 || (position & topMask) != 0) { + canvas.drawRect(0, 0, mWidth, drawSize, mPaint); + } + + if (position == 0 || (position & bottomMask) != 0) { + int save = canvas.save(); + canvas.rotate(180, mWidth / 2f, mHeight / 2f); + canvas.drawRect(0, 0, mWidth, drawSize, mPaint); + canvas.restoreToCount(save); + } + + int offset = (mHeight - mWidth) / 2; + if (position == 0 || (position & leftMask) != 0) { + int saveCount = canvas.save(); + canvas.rotate(90, mWidth / 2f, mHeight / 2f); + canvas.translate(0, offset); + canvas.drawRect(-offset, 0, mWidth + offset, drawSize, mPaint); + canvas.restoreToCount(saveCount); + } + + if (position == 0 || (position & rightMask) != 0) { + int saveCount = canvas.save(); + canvas.rotate(270, mWidth / 2f, mHeight / 2f); + canvas.translate(0, offset); + canvas.drawRect(-offset, 0, mWidth + offset, drawSize, mPaint); + canvas.restoreToCount(saveCount); + } + + canvas.restoreToCount(layerSave); + return drawChild; + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/FixedTouchViewPager.java b/app/src/main/java/com/chwl/app/ui/widget/FixedTouchViewPager.java new file mode 100644 index 0000000..a0b0f24 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/FixedTouchViewPager.java @@ -0,0 +1,62 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; + +import androidx.viewpager.widget.ViewPager; + +import com.chwl.library.utils.log.MLog; + + +/** + * Created by wa on 14-9-28. + */ +public class FixedTouchViewPager extends ViewPager { + private boolean isCanScroll = true; + + public FixedTouchViewPager(Context context) { + super(context); + } + + public FixedTouchViewPager(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + try { + if(!isCanScroll){ + return false; + } + return super.onTouchEvent(ev); + } catch (Throwable ex) { + MLog.error(this, "xuwakao, onTouchEvent fix touch viewpager error happens, ev = " + ev); + } + return false; + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + try { + if(!isCanScroll){ + return false; + } + return super.onInterceptTouchEvent(ev); + } catch (Exception ex) { + MLog.error(this, "xuwakao, onInterceptTouchEvent fix touch viewpager error happens, ev= " + ev); + } + return false; + } + + public void setCanScroll(boolean isCanScroll){ + this.isCanScroll = isCanScroll; + } + + @Override + public void scrollTo(int x, int y){ + if (isCanScroll){ + super.scrollTo(x, y); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/widget/FlickerAvatarView.java b/app/src/main/java/com/chwl/app/ui/widget/FlickerAvatarView.java new file mode 100644 index 0000000..01dc017 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/FlickerAvatarView.java @@ -0,0 +1,104 @@ +package com.chwl.app.ui.widget; + +import android.animation.Animator; +import android.animation.ObjectAnimator; +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.view.animation.AccelerateInterpolator; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.databinding.DataBindingUtil; + +import com.chwl.app.R; +import com.chwl.app.databinding.LayoutFlickerAvatarBinding; + +import java.util.concurrent.TimeUnit; + +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; + +public class FlickerAvatarView extends FrameLayout { + private LayoutFlickerAvatarBinding mBinding; + private Disposable subscribe; + + public FlickerAvatarView(@NonNull Context context) { + this(context, null); + } + + public FlickerAvatarView(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + init(); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + subscribe = Observable.interval(5, TimeUnit.SECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(aLong -> { + animSmall(mBinding.ivAvatar1); + postDelayed(() -> animSmall(mBinding.ivAvatar2), 500); + postDelayed(() -> animSmall(mBinding.ivAvatar3), 1000); + }); + } + + @Override + protected void onDetachedFromWindow() { + if (subscribe != null) { + subscribe.dispose(); + } + super.onDetachedFromWindow(); + } + + private void init() { + inflate(getContext(), R.layout.layout_flicker_avatar, this); + mBinding = DataBindingUtil.bind(findViewById(R.id.root)); + } + + private void animBig(View view) { + ObjectAnimator transY = ObjectAnimator.ofFloat(view, "scaleY", 0, 1); + transY.setDuration(800).start(); + transY.setInterpolator(new AccelerateInterpolator()); + ObjectAnimator transX = ObjectAnimator.ofFloat(view, "scaleX", 0, 1); + transX.setDuration(800).start(); + transX.setInterpolator(new AccelerateInterpolator()); + + } + + private void animSmall(View view) { + ObjectAnimator transY = ObjectAnimator.ofFloat(view, "scaleY", 1, 0); + transY.setDuration(800).start(); + transY.setInterpolator(new AccelerateInterpolator()); + + ObjectAnimator transX = ObjectAnimator.ofFloat(view, "scaleX", 1, 0); + transX.setDuration(800).start(); + transX.setInterpolator(new AccelerateInterpolator()); + + transX.addListener(new Animator.AnimatorListener() { + @Override + public void onAnimationStart(Animator animation) { + + } + + @Override + public void onAnimationEnd(Animator animation) { + animBig(view); + } + + @Override + public void onAnimationCancel(Animator animation) { + + } + + @Override + public void onAnimationRepeat(Animator animation) { + + } + }); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/GiftAvatarAdapter.java b/app/src/main/java/com/chwl/app/ui/widget/GiftAvatarAdapter.java new file mode 100644 index 0000000..c9104af --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/GiftAvatarAdapter.java @@ -0,0 +1,219 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import androidx.recyclerview.widget.RecyclerView; + +import com.chwl.app.R; +import com.chwl.app.common.widget.CircleImageView; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.room.pk.bean.PKTeamInfo; +import com.chwl.core.room.queue.bean.MicMemberInfo; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; +import com.coorchice.library.SuperTextView; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by chenran + * on 2017/10/25. + */ + +public class GiftAvatarAdapter extends RecyclerView.Adapter implements View.OnClickListener { + public final static int SELECT_TYPE_WHOLE_MIC = 0; + public final static int SELECT_TYPE_MULTI_MIC = 1; + + private List micMemberInfos; + private Context context; + private OnItemSelectedListener onItemSelectedListener; + private int selectType = SELECT_TYPE_MULTI_MIC;//0:全麦,1: 非全麦 + + + public GiftAvatarAdapter(Context context) { + this.context = context; + } + + public void setOnItemSelectedListener(OnItemSelectedListener onItemSelectedListener) { + this.onItemSelectedListener = onItemSelectedListener; + } + + public void setMicMemberInfos(List micMemberInfos) { + this.micMemberInfos = micMemberInfos; + } + + public int getSelectType() { + return selectType; + } + + public void setSelectType(int selectType) { + this.selectType = selectType; + } + + public List getSelectedMember() { + if (selectType == SELECT_TYPE_WHOLE_MIC) { + return micMemberInfos; + } else { + List selectedMembers = new ArrayList<>(); + for (MicMemberInfo micMemberInfo : micMemberInfos) { + if (micMemberInfo.isSelected()) { + selectedMembers.add(micMemberInfo); + } + } + return selectedMembers; + } + } + + @Override + public GiftAvatarAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View item = LayoutInflater.from(parent.getContext()). + inflate(R.layout.list_item_gift_avatar, parent, false); + return new GiftAvatarAdapter.ViewHolder(item); + } + + @Override + public void onBindViewHolder(GiftAvatarAdapter.ViewHolder holder, int position) { + holder.avatarContainer.setTag(holder.getAdapterPosition()); + if (position == 0) { + holder.allMicState.setVisibility(View.GONE); + holder.micNumber.setVisibility(View.GONE); + holder.avatar.setVisibility(View.GONE); + holder.ivAll.setVisibility(View.VISIBLE); + holder.ivAll.setAlpha(selectType == SELECT_TYPE_WHOLE_MIC ? 1f : 0.5f); + holder.avatarCover.setVisibility(View.GONE); + holder.micNumberCover.setVisibility(View.GONE); + } else { + holder.avatar.setVisibility(View.VISIBLE); + holder.ivAll.setVisibility(View.GONE); + final MicMemberInfo micMemberInfo = micMemberInfos.get(position - 1); + holder.allMicState.setVisibility(View.GONE); + ImageLoadUtils.loadCircleImage(context, micMemberInfo.getAvatar(), holder.avatar,R.drawable.default_avatar); + // 强制给一个透明的边框,避免因为复用导致的出现边框 + holder.avatar.setBorderColor(context.getResources().getColor(R.color.transparent)); + + if (AvRoomDataManager.get().isHomeParty()) { + if (micMemberInfo.getMicPosition() == AvRoomDataManager.POSITION_BOSS_MIC) { + holder.micNumber.setText(ResUtil.getString(R.string.ui_widget_giftavataradapter_01)); + } else if (micMemberInfo.getMicPosition() == AvRoomDataManager.POSITION_VIP_MIC) { + holder.micNumber.setText("VIP"); + } else { + holder.micNumber.setText(String.valueOf(micMemberInfo.getMicPosition() + 1)); + } + } else { + if (micMemberInfo.getMicPosition() == AvRoomDataManager.POSITION_VIP_MIC) { + holder.micNumber.setText("VIP"); + } else { + holder.micNumber.setText(String.valueOf(micMemberInfo.getMicPosition() + 2)); + } + } + + if (micMemberInfo.isInPkMode()) { + int boardColor = context.getResources().getColor(R.color.color_FFFFFF); + int solidColor = context.getResources().getColor(R.color.appColor); + if (micMemberInfo.getTeamId() == PKTeamInfo.TEAM_RED) { + boardColor = solidColor = context.getResources().getColor(R.color.color_female_FE3F77); + } else if (micMemberInfo.getTeamId() == PKTeamInfo.TEAM_BLUE) { + boardColor = solidColor = context.getResources().getColor(R.color.color_male_16AEFD); + } + holder.micNumber.setSolid(solidColor); + holder.avatar.setBorderColor(boardColor); + } + if (selectType == SELECT_TYPE_WHOLE_MIC && micMemberInfo.isSelected()) { + //选中 + holder.avatarCover.setVisibility(View.GONE); + holder.micNumberCover.setVisibility(View.GONE); + holder.avatar.setBorderColor(context.getResources().getColor(R.color.appColor)); + } else if (micMemberInfo.isSelected()) { + //选中 + holder.avatarCover.setVisibility(View.GONE); + holder.micNumberCover.setVisibility(View.GONE); + holder.avatar.setBorderColor(context.getResources().getColor(R.color.appColor)); + } else { + holder.micNumberCover.setVisibility(View.VISIBLE); + holder.avatarCover.setVisibility(View.VISIBLE); + } + } + } + + @Override + public int getItemCount() { + if (ListUtils.isListEmpty(micMemberInfos)) { + return 0; + } else { + return micMemberInfos.size() + 1; + } + } + + @Override + public void onClick(View v) { + Integer position = (Integer) v.getTag(); + if (position > 0) { + micMemberInfos.get(position - 1).setSelected(!micMemberInfos.get(position - 1).isSelected()); + if (selectType == SELECT_TYPE_WHOLE_MIC && !isSelectAll()) { + selectType = SELECT_TYPE_MULTI_MIC; + } else if (selectType == SELECT_TYPE_MULTI_MIC && isSelectAll()) { + selectType = SELECT_TYPE_WHOLE_MIC; + } + } else { + if (selectType == SELECT_TYPE_WHOLE_MIC && position == 0) { + selectType = SELECT_TYPE_MULTI_MIC; + for (MicMemberInfo micMemberInfo : micMemberInfos) { + micMemberInfo.setSelected(false); + } + } else { + selectType = SELECT_TYPE_WHOLE_MIC; + for (MicMemberInfo micMemberInfo : micMemberInfos) { +// micMemberInfo.setSelected(!AvRoomDataManager.get().isOwner(micMemberInfo.getAccount())); + micMemberInfo.setSelected(true); + } + } + } + notifyDataSetChanged(); + if (onItemSelectedListener != null) { + onItemSelectedListener.onItemSelected(position); + } + } + + private boolean isSelectAll() { + for (MicMemberInfo micMemberInfo : micMemberInfos) { +// if (!micMemberInfo.isSelected() && !AvRoomDataManager.get().isOwner(micMemberInfo.getAccount())) { + if (!micMemberInfo.isSelected()) { + return false; + } + } + return true; + } + + public interface OnItemSelectedListener { + void onItemSelected(int position); + } + + public class ViewHolder extends RecyclerView.ViewHolder { + private CircleImageView avatar; + private View avatarCover; + private SuperTextView micNumber; + private TextView allMicState; + private RelativeLayout avatarContainer; + private View micNumberCover; + private View ivAll; + + public ViewHolder(View itemView) { + super(itemView); + avatar = itemView.findViewById(R.id.avatar); + avatarCover = itemView.findViewById(R.id.avatar_cover); + micNumber = itemView.findViewById(R.id.mic_number); + allMicState = itemView.findViewById(R.id.all_mic_state); + avatarContainer = itemView.findViewById(R.id.avatar_container); + avatarContainer.setOnClickListener(GiftAvatarAdapter.this); + micNumberCover = itemView.findViewById(R.id.mic_number_cover); + ivAll = itemView.findViewById(R.id.iv_all); + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/GiftDialog.java b/app/src/main/java/com/chwl/app/ui/widget/GiftDialog.java new file mode 100644 index 0000000..1bbf214 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/GiftDialog.java @@ -0,0 +1,1980 @@ +package com.chwl.app.ui.widget; + +import static com.chwl.app.ui.widget.magicindicator.GiftIndicator.TYPE_BRAVO; +import static com.chwl.app.ui.widget.magicindicator.GiftIndicator.TYPE_COUNTRY; +import static com.chwl.app.ui.widget.magicindicator.GiftIndicator.TYPE_CP; +import static com.chwl.app.ui.widget.magicindicator.GiftIndicator.TYPE_CUSTOM; +import static com.chwl.app.ui.widget.magicindicator.GiftIndicator.TYPE_LUCKY; +import static com.chwl.app.ui.widget.magicindicator.GiftIndicator.TYPE_NOBLE; +import static com.chwl.app.ui.widget.magicindicator.GiftIndicator.TYPE_NORMAL; +import static com.chwl.app.ui.widget.magicindicator.GiftIndicator.TYPE_SING_ROOM; +import static com.chwl.app.ui.widget.magicindicator.GiftIndicator.TYPE_SUPER_LUCKY; +import static com.chwl.app.ui.widget.magicindicator.GiftIndicator.TYPE_SUPER_LUCKY_24; +import static com.chwl.app.ui.widget.magicindicator.GiftIndicator.TYPE_WEEK; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Context; +import android.content.res.ColorStateList; +import android.graphics.Color; +import android.graphics.Typeface; +import android.os.Bundle; +import android.text.Editable; +import android.text.TextUtils; +import android.text.style.ForegroundColorSpan; +import android.util.DisplayMetrics; +import android.util.Log; +import android.util.SparseArray; +import android.view.Display; +import android.view.Gravity; +import android.view.View; +import android.view.WindowManager; +import android.view.animation.Animation; +import android.view.animation.LinearInterpolator; +import android.view.animation.RotateAnimation; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.constraintlayout.widget.ConstraintLayout; +import androidx.constraintlayout.widget.Group; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.chwl.app.R; +import com.chwl.app.application.IReportConstants; +import com.chwl.app.application.ReportManager; +import com.chwl.app.base.BaseActivity; +import com.chwl.app.common.widget.CircleImageView; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.app.radish.task.activity.TaskCenterActivity; +import com.chwl.app.ui.adapter.GiftAdapter; +import com.chwl.app.ui.adapter.StarWeekAdapter; +import com.chwl.app.ui.gift.dialog.GiftInfoVm; +import com.chwl.app.ui.gift.dialog.PageIndicatorView; +import com.chwl.app.ui.pay.ChargeActivity; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.app.ui.webview.DialogWebViewActivity; +import com.chwl.app.ui.widget.adapter.GiftDialogNumberAdapter; +import com.chwl.app.ui.widget.dialog.GiftManualQuantityDialog; +import com.chwl.app.ui.widget.drawgift.DrawGiftHelper; +import com.chwl.app.ui.widget.drawgift.DrawGiftView; +import com.chwl.app.ui.widget.magicindicator.GiftIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.ui.widget.recyclerview.decoration.VerticalDecoration; +import com.chwl.app.utils.LoginSuccessManager; +import com.chwl.app.utils.RegexUtil; +import com.chwl.app.utils.RoomHelperManager; +import com.chwl.app.utils.SpannableBuilder; +import com.chwl.app.vip.VipCenterActivity; +import com.chwl.core.UriProvider; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.bean.RoomQueueInfo; +import com.chwl.core.gift.GiftModel; +import com.chwl.core.gift.bean.BravoNoticeInfo; +import com.chwl.core.gift.bean.GiftInfo; +import com.chwl.core.gift.bean.GiftTab; +import com.chwl.core.gift.bean.GiftType; +import com.chwl.core.gift.bean.LuckyBagNoticeInfo; +import com.chwl.core.gift.bean.SimpleUserInfo; +import com.chwl.core.gift.bean.TagsInfo; +import com.chwl.core.gift.event.GiftComboEvent; +import com.chwl.core.gift.event.UpdateKnapEvent; +import com.chwl.core.gift.event.UpdateKnapFreeGiftDataEvent; +import com.chwl.core.gift.event.UpdateKnapFreeGiftEvent; +import com.chwl.core.gift.event.UpdateKnapFreeGiftNumEvent; +import com.chwl.core.im.custom.bean.RoomFreeGiftMsgBean; +import com.chwl.core.initial.InitialModel; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.manager.IMNetEaseManager; +import com.chwl.core.manager.RoomEvent; +import com.chwl.core.pay.PayModel; +import com.chwl.core.pay.bean.WalletInfo; +import com.chwl.core.pay.event.UpdateWalletInfoEvent; +import com.chwl.core.room.anotherroompk.ShowUserInfoDialogEvent; +import com.chwl.core.room.pk.model.PkModel; +import com.chwl.core.room.queue.bean.MicMemberInfo; +import com.chwl.core.user.UserModel; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.core.utils.extension.StringExtensionKt; +import com.chwl.core.utils.net.RxHelper; +import com.chwl.core.widget.layoutmanager.pagergridlayoutmanager.PagerGridLayoutManager; +import com.chwl.library.bindinglist.IItem; +import com.chwl.library.common.util.OtherExtKt; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; +import com.chwl.library.utils.TextWatcherWrapper; +import com.chwl.library.widget.text.DrawableTextView; +import com.example.lib_utils.UiUtils; +import com.example.lib_utils.ktx.ResourcesKtxKt; +import com.example.lib_utils.spannable.SpannableTextBuilder; +import com.google.android.material.bottomsheet.BottomSheetBehavior; +import com.google.android.material.bottomsheet.BottomSheetDialog; +import com.netease.nim.uikit.common.util.sys.ScreenUtil; +import com.trello.rxlifecycle3.components.support.RxAppCompatActivity; +import com.zhpan.bannerview.BannerViewPager; +import com.zhpan.bannerview.utils.BannerUtils; +import com.zyyoona7.lib.EasyPopup; +import com.zyyoona7.lib.HorizontalGravity; +import com.zyyoona7.lib.VerticalGravity; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +import io.reactivex.Observable; +import io.reactivex.Single; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.disposables.Disposable; + +/** + * @author chenran + * @date 2017/7/27 + */ + +public class GiftDialog extends BottomSheetDialog implements View.OnClickListener, GiftAvatarAdapter.OnItemSelectedListener { + + private static final String TAG = "GiftDialog"; + private static final int ITEM_TYPE_GOLD = 0; // 钻石 + private static final int ITEM_TYPE_RADISH = 1; // 萝卜 + private static final int MAX_DRAW_SIZE = 300; + public static String GIFT_DIALOG_FROM = ""; // 埋点用,标识从哪个位置打开弹框 + private final Context context; + /** + * 被送礼物的人的uid + */ + private long uid; + private final int giftId; + private final boolean isInRoom; + /** + * 被选中的uid是否在麦上 + */ + private final boolean userOnMic; + private View mContentView; + private RecyclerView gridView; + private GiftAdapter giftAdapter; + private PagerGridLayoutManager giftLayoutManger; + private PageIndicatorView indicatorView; + private RecyclerView avatarList; + private GiftAvatarAdapter avatarListAdapter; + @Nullable + private GiftInfo currentGiftInfo; + private List currentGiftInfoList; + private OnGiftDialogBtnClickListener giftDialogBtnClickListener; + private CircleImageView avatarImage; + private TextView nickText; + private EasyPopup easyPopup; + private TextView giftNumberText; + private ImageView giftNumberOptions; + private ImageView ivOpenNoble; +// private TextView tvGiftValue; + private EditText etSendMessage; + private Button sendGiftButton; + private View layoutEmpty; + private View layoutLoading; + private View layoutLoadFiled; + private View loadingView; + private View reloadView; + private GiftIndicator giftIndicator; + private int giftNumber = 1; + private View sendContainer; + private TextView tvTextGold; + private DrawableTextView tvRecharge; + private List micMemberInfos; + private View giftNumLayout; + private Disposable mSubscribe; + private CompositeDisposable compositeDisposable; + private GiftInfoVm lastSelectedItem; + private List pagerList; + private WalletInfo goldWalletInfo = PayModel.get().getCurrentWalletInfo(); + private int itemType = ITEM_TYPE_GOLD; + private View rlGifts; + private View llTabs; + private View llDrawGift; + private TextView tvDrawGiftTips; + private View ivDrawGiftRemoveLast; + private View ivDrawGiftRemoveAll; + private View ivDrawGiftClose; + private boolean isShowDrawGiftModel; + @Nullable + private DrawGiftHelper drawGiftHelper; + private ImageView ivSuperLuckyGiftTips; + private View flLuckyDesc; + private RecyclerView rvLuckyMsg; + + + @Nullable + private Disposable mBravoBannerDisposable; + private BaseQuickAdapter mBravoBannerAdapter; + private Group mGroupBravoBanner; + private RecyclerView mRvBravoBanner; + private DrawableTextView mBravoBannerIncome; + private ConstraintLayout mBravoBannerDesc; + private ImageView mBravoBannerIcon; + private View mBgBravoBanner; + private View mRvBravoBannerClick; + + + private BannerViewPager mStarWeekBanner; + + private TextView tvLuckyBagIntro; + + @Nullable + private Disposable luckyMsgDisposable; + private BaseQuickAdapter luckyMsgAdapter; + + + private ImageView ivAvatarCharm; + private ImageView ivAvatarLevel; + private TextView tvNickCharm; + private TextView tvNickLevel; + private View llStarWeek; + + private GiftDialogNumberAdapter mGiftDialogNumberAdapter; + + + public GiftDialog(Context context, int giftId) { + this(context, 0, true, false, true, giftId); + } + + public GiftDialog(Context context, long OtherUid, boolean isInRoom, boolean isMagic, boolean isHideMagicTab) { + this(context, OtherUid, isInRoom, isMagic, isHideMagicTab, 0); + } + + /*** + * + * @param context context + * @param OtherUid 默认选中的人 如果0则表示没选中任何人 + * @param isInRoom true表示在房间内且在麦上,并且此时OtherUid就是默认选中人,礼物框显示麦上用户 + * false表示不在房间,此时OtherUid就是被赠送人的ID + * @param isHideMagicTab true则隐藏魔法,默认false + */ + public GiftDialog(Context context, long OtherUid, boolean isInRoom, @Deprecated boolean isMagic, @Deprecated boolean isHideMagicTab, int giftId) { + super(context, R.style.ErbanBottomSheetDialog); + this.context = context; + this.uid = OtherUid; + this.giftId = giftId; + this.micMemberInfos = new ArrayList<>(); + this.micMemberInfos.addAll(transformAvatarList(OtherUid)); + this.isInRoom = isInRoom; + //判断用户在不在麦上 + this.userOnMic = AvRoomDataManager.get().checkIsOnMicByAccount(String.valueOf(uid)); + } + + public void setGiftDialogBtnClickListener(OnGiftDialogBtnClickListener giftDialogBtnClickListener) { + this.giftDialogBtnClickListener = giftDialogBtnClickListener; + } + + private List transformAvatarList(long account) { + List micMemberInfos = new ArrayList<>(); + SparseArray micMemberMap = AvRoomDataManager.get().mMicQueueMemberMap; + if (micMemberMap == null) { + micMemberMap = new SparseArray<>(); + } + for (int i = 0; i < micMemberMap.size(); i++) { + MicMemberInfo micMemberInfo = new MicMemberInfo(); + RoomQueueInfo roomQueueInfo = micMemberMap.get(micMemberMap.keyAt(i)); + MicMemberInfo mChatRoomMember = roomQueueInfo.mChatRoomMember; + if (mChatRoomMember == null) continue; + // 合法判断 + if (TextUtils.isEmpty(mChatRoomMember.getAccount()) || + TextUtils.isEmpty(mChatRoomMember.getNick()) || + TextUtils.isEmpty(mChatRoomMember.getAvatar())) continue; + // 排除自己 +// if (AvRoomDataManager.get().isOwner(mChatRoomMember.getAccount())) continue; + // 设置默认人员 + if (String.valueOf(account).equals(mChatRoomMember.getAccount())) { + micMemberInfo.setSelected(true); + } + // 设置房主 + if (AvRoomDataManager.get().isRoomOwner(mChatRoomMember.getAccount())) { + micMemberInfo.setRoomOwnner(true); + } + + micMemberInfo.setInPkMode(AvRoomDataManager.get().isOpenPKMode()); + micMemberInfo.setTeamId(PkModel.get().getTeamIdInPKMemberList(mChatRoomMember.getAccount())); + micMemberInfo.setNick(mChatRoomMember.getNick()); + micMemberInfo.setAvatar(mChatRoomMember.getAvatar()); + micMemberInfo.setMicPosition(micMemberMap.keyAt(i)); + micMemberInfo.setAccount(mChatRoomMember.getAccount()); + //添加性别信息 + micMemberInfo.setGender(mChatRoomMember.getGender()); + micMemberInfos.add(micMemberInfo); + } + + // 离开模式本地添加房主 + if (AvRoomDataManager.get().isLeaveMode() && + !AvRoomDataManager.get().isRoomOwner() && + !AvRoomDataManager.get().isOnMic(AvRoomDataManager.get().getRoomUid())) { + MicMemberInfo micMemberInfo = new MicMemberInfo(); + micMemberInfo.setRoomOwnner(true); + micMemberInfo.setInPkMode(AvRoomDataManager.get().isOpenPKMode()); + micMemberInfo.setTeamId(PkModel.get().getTeamIdInPKMemberList(String.valueOf(AvRoomDataManager.get().getRoomUid()))); + micMemberInfo.setNick(AvRoomDataManager.get().nick); + micMemberInfo.setAvatar(AvRoomDataManager.get().avatar); + micMemberInfo.setMicPosition(-1); + micMemberInfo.setAccount(String.valueOf(AvRoomDataManager.get().getRoomUid())); + //添加性别信息 + micMemberInfo.setGender(AvRoomDataManager.get().gender); + micMemberInfos.add(0, micMemberInfo); + } + + return micMemberInfos; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + EventBus.getDefault().register(this); + setCanceledOnTouchOutside(true); + setContentView(R.layout.dialog_bottom_gift); + compositeDisposable = new CompositeDisposable(); + mContentView = findViewById(R.id.ll_dialog_bottom_gift); + init(mContentView); + WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + Display d = windowManager.getDefaultDisplay(); + DisplayMetrics realDisplayMetrics = new DisplayMetrics(); + d.getRealMetrics(realDisplayMetrics); + WindowManager.LayoutParams params = getWindow().getAttributes(); + params.width = WindowManager.LayoutParams.MATCH_PARENT; + params.height = WindowManager.LayoutParams.MATCH_PARENT; + params.dimAmount = 0f; + getWindow().setAttributes(params); + mSubscribe = IMNetEaseManager.get().getChatRoomEventObservable().subscribe(this::onReceiveRoomEvent); + disableSlideClose(); + } + + private void disableSlideClose() { + BottomSheetBehavior bottomSheetBehavior = getBottomSheetBehavior(); + if (bottomSheetBehavior != null) { + bottomSheetBehavior.addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() { + @Override + public void onStateChanged(@NonNull View bottomSheet, int newState) { + if (newState == BottomSheetBehavior.STATE_DRAGGING) { + bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); + } + } + + @Override + public void onSlide(@NonNull View bottomSheet, float slideOffset) { + + } + }); + } + } + + protected View getBottomSheetLayout() { + return getDelegate().findViewById(com.google.android.material.R.id.design_bottom_sheet); + } + + protected BottomSheetBehavior getBottomSheetBehavior() { + View view = getBottomSheetLayout(); + if (view != null) { + return BottomSheetBehavior.from(view); + } + return null; + } + + @Override + protected void onStop() { + super.onStop(); + GIFT_DIALOG_FROM = ""; + } + + private void onReceiveRoomEvent(RoomEvent roomEvent) { + int event = roomEvent.getEvent(); + switch (event) { + case RoomEvent.GIFT_OUT_OF_DATE: + onGiftOutOfDate(roomEvent.getMessage()); + break; + default: + break; + } + + } + + @SuppressLint("CheckResult") + private void init(View root) { + root.findViewById(R.id.tv_recharge).setOnClickListener(this); + tvLuckyBagIntro = findViewById(R.id.tv_lucky_bag_intro); + tvLuckyBagIntro.setOnClickListener(this); + mStarWeekBanner = findViewById(R.id.star_week_list); + flLuckyDesc = findViewById(R.id.fl_lucky_desc); + rvLuckyMsg = findViewById(R.id.rv_lucky_msg); + sendGiftButton = root.findViewById(R.id.btn_send); + layoutEmpty = root.findViewById(R.id.layout_empty); + layoutLoading = root.findViewById(R.id.layout_loading); + layoutLoadFiled = root.findViewById(R.id.layout_load_failed); + reloadView = root.findViewById(R.id.tv_reload); + reloadView.setOnClickListener(this); + loadingView = root.findViewById(R.id.iv_loading); + rlGifts = root.findViewById(R.id.rl_gifts); + llTabs = root.findViewById(R.id.ll_tabs); + llDrawGift = root.findViewById(R.id.ll_draw_gift); + tvDrawGiftTips = root.findViewById(R.id.tv_draw_gift_tips); + ivDrawGiftRemoveLast = root.findViewById(R.id.iv_draw_gift_remove_last); + ivDrawGiftRemoveAll = root.findViewById(R.id.iv_draw_gift_remove_all); + ivDrawGiftClose = root.findViewById(R.id.iv_draw_gift_close); + ivSuperLuckyGiftTips = findViewById(R.id.iv_super_lucky_gift_tips); + + mRvBravoBanner = findViewById(R.id.rvBravoBanner); + mGroupBravoBanner = findViewById(R.id.groupBravoBanner); + mBravoBannerIncome = findViewById(R.id.btnBravoIncome); + mBravoBannerDesc = findViewById(R.id.flBravoDesc); + mBravoBannerIcon = findViewById(R.id.bravoBannerIcon); + mBgBravoBanner = findViewById(R.id.bgBravoBanner); + mRvBravoBannerClick = findViewById(R.id.rvBravoBannerClick); + mRvBravoBannerClick.setOnClickListener(v -> { + + }); + mBravoBannerIncome.setOnClickListener(v -> { + DialogManager dialogManager = new DialogManager(context); + dialogManager.showOkCancelDialog(ResourcesKtxKt.getString(R.string.v26_income_tips), + ResourcesKtxKt.getString(R.string.v26_income_content),ResourcesKtxKt.getString(R.string.ok),"",false,() -> {}); + }); + + ivDrawGiftClose.setOnClickListener(this); + ivDrawGiftRemoveLast.setOnClickListener(this); + ivDrawGiftRemoveAll.setOnClickListener(this); + showLoadingView(); + showLoadingAnimation(); + sendGiftButton.setOnClickListener(this); + giftNumLayout = root.findViewById(R.id.gift_number_layout); + giftNumLayout.setOnClickListener(this); + + List tabInfoList = updateTabs(); + // MARK: 获取到新 API 数据后,tab 按这里的方式更新 +// List tabInfoList = new ArrayList<>(); +// tabInfoList.add(new GiftTab(GiftIndicator.TYPE_NORMAL, ResUtil.getString(R.string.ui_widget_giftdialog_01), ResUtil.getString(R.string.ui_widget_giftdialog_02))); +// tabInfoList.add(new GiftTab(GiftIndicator.TYPE_LUCKY, ResUtil.getString(R.string.ui_widget_giftdialog_03), ResUtil.getString(R.string.ui_widget_giftdialog_04))); +// tabInfoList.add(new GiftTab(GiftIndicator.TYPE_NOBLE, ResUtil.getString(R.string.ui_widget_giftdialog_05), ResUtil.getString(R.string.ui_widget_giftdialog_06))); +// tabInfoList.add(new GiftTab(GiftIndicator.TYPE_WEEK, ResUtil.getString(R.string.ui_widget_giftdialog_07), ResUtil.getString(R.string.ui_widget_giftdialog_08))); +// tabInfoList.add(new GiftTab(GiftIndicator.TYPE_DRAW_GIFT, ResUtil.getString(R.string.ui_widget_giftdialog_09), ResUtil.getString(R.string.ui_widget_giftdialog_010))); +// tabInfoList.add(new GiftTab(GiftIndicator.TYPE_SING_ROOM, ResUtil.getString(R.string.ui_widget_giftdialog_hot), ResUtil.getString(R.string.ui_widget_giftdialog_hot))); +// tabInfoList.add(new GiftTab(GiftIndicator.TYPE_KNAP, ResUtil.getString(R.string.ui_widget_giftdialog_011), ResUtil.getString(R.string.ui_widget_giftdialog_012))); + giftIndicator = root.findViewById(R.id.gift_indicator); + giftIndicator.initTab( + tabInfoList, + context.getResources().getColor(R.color.color_999999), + context.getResources().getColor(R.color.color_ffbc51) + ); + //noinspection ResultOfMethodCallIgnored + giftIndicator.addClick() + .subscribeOn(AndroidSchedulers.mainThread()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(integer -> { + updateGiftView(integer); + //福袋礼物有定时更新逻辑,每次点击都需要刷新福袋礼物信息 + if (integer == GiftIndicator.TYPE_LUCKY) { + reloadData(false); + } + }); + + if (isInRoom) { + giftIndicator.showPosition(GiftIndicator.TYPE_LUCKY); + } else { + giftIndicator.hidePosition(GiftIndicator.TYPE_LUCKY); + giftIndicator.hidePosition(GiftIndicator.TYPE_DRAW_GIFT); + } + gridView = root.findViewById(R.id.gridView); + indicatorView = root.findViewById(R.id.indicator); + indicatorView.setVisibility(View.INVISIBLE); + tvTextGold = root.findViewById(R.id.tv_text_gold); + tvRecharge = root.findViewById(R.id.tv_recharge); + + ivAvatarCharm = root.findViewById(R.id.iv_avatar_charm); + ivAvatarLevel = root.findViewById(R.id.iv_avatar_level); + tvNickCharm = root.findViewById(R.id.tv_nick_charm); + tvNickLevel = root.findViewById(R.id.tv_nick_level); + llStarWeek = root.findViewById(R.id.ll_star_week); + + giftNumberText = root.findViewById(R.id.gift_number_text); + giftNumberOptions = root.findViewById(R.id.iv_gift_number_options); + avatarImage = root.findViewById(R.id.avatar); + nickText = root.findViewById(R.id.nick); + avatarList = root.findViewById(R.id.avatar_list); + LinearLayoutManager mLayoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false); + avatarList.setLayoutManager(mLayoutManager); + avatarList.addItemDecoration(new VerticalDecoration(UIUtil.dip2px(context, 10), false, true)); + + ivOpenNoble = root.findViewById(R.id.iv_open_noble); + etSendMessage = root.findViewById(R.id.et_gift_message); + if (UiUtils.INSTANCE.isRtl(context)) { + ivOpenNoble.setScaleType(ImageView.ScaleType.FIT_START); + } + ivOpenNoble.setOnClickListener(this); + sendContainer = root.findViewById(R.id.send_container); + layoutEmpty.setVisibility(View.GONE); +// tvGiftValue = root.findViewById(R.id.tv_gift_value); + + + giftAdapter = new GiftAdapter(); + giftAdapter.setOnItemClickListener((adapter, view, position) -> { + GiftInfoVm item = giftAdapter.getData().get(position); + if (item.data.isSendMsg()) { + etSendMessage.setVisibility(View.VISIBLE); + } else { + etSendMessage.setVisibility(View.GONE); + } + if (lastSelectedItem != null) { + lastSelectedItem.isSelect.set(false); + } + item.isSelect.set(true); + lastSelectedItem = item; + currentGiftInfo = item.data; + setGoldOrRadishText(lastSelectedItem); + isShowDrawGiftModel = true; + updateLuckyBagIntro(); + updateSuperLuckyGiftTips(); + updateWeekStarDesc(); + updateDrawGift(); + }); + giftLayoutManger = new PagerGridLayoutManager(2,4,PagerGridLayoutManager.HORIZONTAL,false); + giftLayoutManger.setPagerChangedListener(new PagerGridLayoutManager.PagerChangedListener() { + @Override + public void onPagerCountChanged(int pagerCount) { + + } + + @Override + public void onPagerIndexSelected(int prePagerIndex, int currentPagerIndex) { + OtherExtKt.doLog(" 翻页 PagerIndex = "+currentPagerIndex); + indicatorView.setSelectedPage(currentPagerIndex); + } + }); + gridView.setAdapter(giftAdapter); + gridView.setLayoutManager(giftLayoutManger); + + if (giftId == 0) { + // 更新所有礼物 + giftIndicator.setPosition(TYPE_NORMAL); + updateGiftView(giftIndicator.getCurrrentType()); + } else { + int indicatorType = TYPE_NORMAL; + GiftInfo giftInfo = GiftModel.get().findGiftInfoById(giftId); + if (giftInfo != null) { + switch (giftInfo.getGiftType()) { + case GiftType.GIFT_TYPE_NORMAL: + indicatorType = TYPE_NORMAL; + break; + case GiftType.GIFT_TYPE_LUCKY: + indicatorType = GiftIndicator.TYPE_LUCKY; + break; + case GiftType.GIFT_TYPE_SUPER_LUCKY: + indicatorType = TYPE_SUPER_LUCKY; + break; + case GiftType.GIFT_TYPE_VIP: + indicatorType = TYPE_NOBLE; + break; + case GiftType.GIFT_TYPE_COUNTRY: + indicatorType = TYPE_COUNTRY; + break; + case GiftType.GIFT_TYPE_WEEK_STAR: + indicatorType = TYPE_WEEK; + break; + } + } + giftIndicator.setPosition(indicatorType); + updateGiftView(giftIndicator.getCurrrentType(), giftInfo); + } + if (AvRoomDataManager.get().isSingleRoom()) { + giftIndicator.showPosition(GiftIndicator.TYPE_SING_ROOM); + } else { + giftIndicator.hidePosition(GiftIndicator.TYPE_SING_ROOM); + } + + View descLayout = root.findViewById(R.id.desc_layout); + View seatLayout = root.findViewById(R.id.rl_avatars); + if (isInRoom && (userOnMic || uid == 0)) { + descLayout.setVisibility(View.GONE); + avatarList.setVisibility(View.VISIBLE); + if (micMemberInfos != null && micMemberInfos.size() > 0) { + avatarListAdapter = new GiftAvatarAdapter(getContext()); + avatarListAdapter.setMicMemberInfos(micMemberInfos); + avatarListAdapter.setOnItemSelectedListener(this); + avatarList.setAdapter(avatarListAdapter); + seatLayout.setVisibility(View.VISIBLE); + }else{ + seatLayout.setVisibility(View.GONE); + } + } else { + avatarList.setVisibility(View.GONE); + descLayout.setVisibility(View.VISIBLE); + seatLayout.setVisibility(View.VISIBLE); + + Single single = UserModel.get().getUserInfo(uid); + + if (context instanceof RxAppCompatActivity) { + single = single.compose(((RxAppCompatActivity) context).bindToLifecycle()); + } + single.subscribe(userInfo -> { + nickText.setText(RegexUtil.getPrintableString(userInfo.getNick())); + ImageLoadUtils.loadAvatar(context, userInfo.getAvatar(), avatarImage); + }); + } + + etSendMessage.addTextChangedListener(new TextWatcherWrapper() { + @Override + public void afterTextChanged(Editable s) { + if (s.toString().trim().length() > 15) { + SingleToastUtil.showToast(getContext().getString(R.string.tips_input_gift_message_limit)); + sendGiftButton.setEnabled(false); + } + } + }); + + compositeDisposable.add(GiftModel.get().requestKnapGiftInfos().subscribe()); + PayModel.get().getMyRemoteWalletInfo().compose(RxHelper.bindContext(context)) + .subscribe(info -> { + goldWalletInfo = info; + setGoldOrRadishText(lastSelectedItem); + }); + + if (!LoginSuccessManager.Companion.getInstance().getMFirstRechargeStatus()) { + tvRecharge.changeGradientColor(Color.parseColor("#FFE347"), -1, Color.parseColor("#FF9A51")); + tvRecharge.setDrawableEmpty(ResourcesKtxKt.getDrawable(R.drawable.ic_coin_84), null, null, null); + tvRecharge.setTextColor(ResourcesKtxKt.getColor(R.color.color_313131)); + ImageView iv = findViewById(R.id.ivRechargeArrow); + if (iv != null) { + iv.setImageTintList(ColorStateList.valueOf(Color.BLACK)); + } + } else { + tvRecharge.setDrawableSize(Gravity.START,0,0,true); + } + + + } + + private List updateTabs() { + List tabInfoList = new ArrayList<>(); + if (GiftModel.get().getTabList() != null) { + for (TagsInfo info: GiftModel.get().getTabList()) { + tabInfoList.add(new GiftTab(swithGiftTypeToTabType(info), info.tagName(), info.tagName())); + } + } + return tabInfoList; + } + + private int swithGiftTypeToTabType(TagsInfo info) { + switch (info.tagGiftType()) { + case GiftType.GIFT_TYPE_NORMAL: + return TYPE_NORMAL; + case GiftType.GIFT_TYPE_LUCKY: + return TYPE_LUCKY; + case GiftType.GIFT_TYPE_SUPER_LUCKY: + return TYPE_SUPER_LUCKY; + case GiftType.GIFT_TYPE_VIP: + return TYPE_NOBLE; + case GiftType.GIFT_TYPE_WEEK_STAR: + return TYPE_WEEK; + case GiftType.GIFT_TYPE_COUNTRY: + return TYPE_COUNTRY; + case GiftType.GIFT_TYPE_SINGLE_ROOM: + return TYPE_SING_ROOM; + case GiftType.GIFT_TYPE_LUCKY_24: + return TYPE_SUPER_LUCKY_24; + case GiftType.GIFT_TYPE_CP: + return TYPE_CP; + case GiftType.GIFT_TYPE_CUSTOM: + return TYPE_CUSTOM; + case GiftType.GIFT_TYPE_BRAVO: + return TYPE_BRAVO; + } + return TYPE_NORMAL; + } + + private void showLoadingAnimation() { + Animation rotateAnimation = new RotateAnimation(0, 360, + Animation.RELATIVE_TO_SELF, 0.5f, + Animation.RELATIVE_TO_SELF, 0.5f); + rotateAnimation.setFillAfter(true); + rotateAnimation.setDuration(1000); + rotateAnimation.setRepeatCount(-1); + rotateAnimation.setInterpolator(new LinearInterpolator()); + loadingView.startAnimation(rotateAnimation); + } + + private void setGoldOrRadishText(IItem lastSelectedItem) { + itemType = ITEM_TYPE_GOLD; + + if (lastSelectedItem == null) { + setTvGoldText(); + return; + } + + if (lastSelectedItem instanceof GiftInfoVm) { + GiftInfoVm giftInfoVm = (GiftInfoVm) lastSelectedItem; + GiftInfo giftInfo = giftInfoVm.data; + sendGiftButton.setEnabled(true); + switch (giftInfo.getConsumeType()) { + case GiftInfo.CONSUME_TYPE_FREE_GIFT: + case GiftInfo.CONSUME_TYPE_GOLD: + setTvGoldText(); + break; + default: + // 未匹配的类型,不允许进行交易 + sendGiftButton.setEnabled(false); + setUpdateTipsText(); + } + } + } + + private void setTvGoldText() { + itemType = ITEM_TYPE_GOLD; + + tvRecharge.setVisibility(View.VISIBLE); + tvRecharge.setText(context.getText(R.string.charge)); + if (goldWalletInfo == null) { + return; + } + if (goldWalletInfo.canGoldSendGift) { + findViewById(R.id.iv_plus).setVisibility(View.VISIBLE); + findViewById(R.id.iv_gold).setVisibility(View.VISIBLE); + BigDecimal total = BigDecimal.valueOf(goldWalletInfo.getDiamondNum()); + total = total.add(BigDecimal.valueOf(goldWalletInfo.getGoldNum())); + tvTextGold.setText(OtherExtKt.formatToString(total.doubleValue())); + } else { + findViewById(R.id.iv_plus).setVisibility(View.GONE); + findViewById(R.id.iv_gold).setVisibility(View.GONE); + tvTextGold.setText(OtherExtKt.formatToString(goldWalletInfo.getDiamondNum())); + } + } + + private void setUpdateTipsText() { + tvRecharge.setVisibility(View.GONE); + tvTextGold.setText(context.getText(R.string.text_need_update)); + } + + private void updateGiftView(int position) { + updateGiftView(position, null); + } + + private void updateGiftView(int position, @Nullable GiftInfo selectGiftInfo) { + showDataView(); + // 获得对应的普通礼物/贵族礼物/背包礼物 + List nobleGiftInfos = getNobleGiftInfos(); + if (position == GiftIndicator.TYPE_KNAP) { + currentGiftInfoList = GiftModel.get().getKnapList(); + } else if (position == TYPE_NOBLE) { + currentGiftInfoList = nobleGiftInfos; + } else if (position == TYPE_NORMAL) { + currentGiftInfoList = getNormalGiftInfos(); + } else if (position == GiftIndicator.TYPE_LUCKY) { + currentGiftInfoList = getLuckyGiftInfos(); + } else if (position == TYPE_WEEK) { + currentGiftInfoList = getWeekStarGiftInfos(); + } else if (position == GiftIndicator.TYPE_DRAW_GIFT) { + currentGiftInfoList = getDrawGiftInfos(); + } else if (position == GiftIndicator.TYPE_SING_ROOM) { + currentGiftInfoList = getSingleRoomGiftInfos(); + } else if (position == TYPE_SUPER_LUCKY) { + currentGiftInfoList = getSuperLuckyGiftInfos(); + } else if (position == TYPE_COUNTRY) { + currentGiftInfoList = getCountryGiftInfos(); + }else if (position == TYPE_CP) { + currentGiftInfoList = getCpGiftInfos(); + }else if (position == TYPE_CUSTOM) { + currentGiftInfoList = getCustomGiftInfos(); + }else if (position == TYPE_BRAVO) { + currentGiftInfoList = getBravoGiftInfos(); + } + // 有贵族礼物才显示贵族礼物的tab + if (ListUtils.isListEmpty(nobleGiftInfos)) { + giftIndicator.hidePosition(TYPE_NOBLE); + } else { + giftIndicator.showPosition(TYPE_NOBLE); + } + // 有塗鴉礼物才显示塗鴉礼物的tab +// if (ListUtils.isListEmpty(getDrawGiftInfos())) { +// giftIndicator.hidePosition(GiftIndicator.TYPE_DRAW_GIFT); +// } else { +// giftIndicator.showPosition(GiftIndicator.TYPE_DRAW_GIFT); +// } + //是否背包礼物 + final boolean isKnap = (position == GiftIndicator.TYPE_KNAP); + initEasyPop(isKnap); + if (ListUtils.isListEmpty(currentGiftInfoList)) { + currentGiftInfo = null; + if (isKnap) { +// tvGiftValue.setVisibility(View.VISIBLE); + showEmptyView(); + } else if (position == GiftIndicator.TYPE_LUCKY || + position == TYPE_SUPER_LUCKY || + position == TYPE_WEEK || + position == GiftIndicator.TYPE_SING_ROOM || + position == GiftIndicator.TYPE_DRAW_GIFT || + position == TYPE_COUNTRY) { + showEmptyView(); + updateWeekStarDesc(); + isShowDrawGiftModel = false; + updateDrawGift(); + updateSuperLuckyGiftTips(); + } else { + showLoadFailedView(); + } + return; + } + currentGiftInfo = selectGiftInfo == null ? currentGiftInfoList.get(0) : selectGiftInfo; + if (currentGiftInfo.isSendMsg()) { + etSendMessage.setVisibility(View.VISIBLE); + } + + + pagerList = beanTransformVm(context, currentGiftInfoList, isKnap, position == TYPE_WEEK ? 4 : 8, currentGiftInfo); + setGridViewData(pagerList); + + + if (isKnap) { +// tvGiftValue.setVisibility(View.VISIBLE); + updateTotalPrice(); + } else { + if (giftNumber == -1) { + updateNumber(1); + } + } + isShowDrawGiftModel = false; + updateLuckyBagIntro(); + updateSuperLuckyGiftTips(); + updateWeekStarDesc(); + updateDrawGift(); + giftIndicator.post(() -> { + boolean isRTL = UiUtils.INSTANCE.isRtl(getContext()); +// if (position < TYPE_WEEK) { GiftModel.get().getTabList().size()/2; + int centerIndex = GiftModel.get().getTabList().size()/2; + if (position < centerIndex) { + giftIndicator.fullScroll(isRTL ? View.FOCUS_RIGHT : View.FOCUS_LEFT); + } else { + giftIndicator.fullScroll(isRTL ? View.FOCUS_LEFT : View.FOCUS_RIGHT); + } + }); + } + + + private List beanTransformVm(Context context, + List data, + boolean isKnap, + int pageSize, + @Nullable GiftInfo selectGiftInfo) { + List result = new ArrayList<>(); + if (ListUtils.isListEmpty(data)) { + return result; + } + boolean hasSelectGift = false; + for (int i = 0; i < data.size(); i++) { + + boolean select = false; + if (selectGiftInfo != null && selectGiftInfo.getGiftId() == data.get(i).getGiftId()) { + hasSelectGift = true; + select = true; + } + GiftInfoVm item = new GiftInfoVm(context, data.get(i), select, isKnap); + result.add(item); + } + if (!hasSelectGift) { + result.get(0).isSelect.set(true); + } + return result; + } + + private void setGridViewData(List pagerList) { + if (ListUtils.isListEmpty(pagerList)) { + return; + } + indicatorView.initIndicator((int) Math.ceil((pagerList.size() / 8.0f))); + int defaultSelectPage = 0; + int defaultSelectItem = 0; + wai: + for (int i = 0; i < pagerList.size(); i++) { + GiftInfoVm iItem = pagerList.get(i); + if (iItem != null && iItem.isSelect.get()) { + defaultSelectPage = i % 8; //当前第几页 + defaultSelectItem = i; + break wai; + } + } + indicatorView.setSelectedPage(defaultSelectPage); + layoutEmpty.setVisibility(View.GONE); + gridView.setVisibility(View.VISIBLE); + + indicatorView.setVisibility(pagerList.size() > 1 ? View.VISIBLE : View.INVISIBLE); + lastSelectedItem = pagerList.get(defaultSelectItem); + setGoldOrRadishText(lastSelectedItem); + + if (giftLayoutManger != null) { + giftLayoutManger.scrollToPagerIndex(defaultSelectPage); + } + if (giftAdapter != null) { + giftAdapter.setNewData(pagerList); + + } + } + + + private void updateSuperLuckyGiftTips() { + if (currentGiftInfo == null || TextUtils.isEmpty(currentGiftInfo.getBannerUrl()) || currentGiftInfo.getGiftType() != GiftType.GIFT_TYPE_SUPER_LUCKY) { + ivSuperLuckyGiftTips.setVisibility(View.GONE); + } else { + ivSuperLuckyGiftTips.setVisibility(View.VISIBLE); + ImageLoadUtils.loadImage(ivSuperLuckyGiftTips.getContext(), currentGiftInfo.getBannerUrl(), ivSuperLuckyGiftTips); + ivSuperLuckyGiftTips.setOnClickListener(v -> { + if (!TextUtils.isEmpty(currentGiftInfo.getSkipUrl())) { + DialogWebViewActivity.start(context, currentGiftInfo.getSkipUrl(), true); + } + }); + } + } + + + private void updateLuckyBagIntro() { + + flLuckyDesc.setVisibility(View.GONE); + mBravoBannerDesc.setVisibility(View.GONE); + + if (currentGiftInfo == null || (TextUtils.isEmpty(currentGiftInfo.getGiftExplainUrl()) && currentGiftInfo.getGiftType() != GiftType.GIFT_TYPE_LUCKY)) { + tvLuckyBagIntro.setVisibility(View.GONE); + } else { + tvLuckyBagIntro.setVisibility(View.VISIBLE); + } + + if (currentGiftInfo != null && (currentGiftInfo.getGiftType() == GiftType.GIFT_TYPE_LUCKY)) { + flLuckyDesc.setVisibility(View.VISIBLE); + + if (luckyMsgDisposable != null) return; + if (luckyMsgAdapter == null) { + luckyMsgAdapter = new BaseQuickAdapter<>(R.layout.item_lucky_gift_msg) { + @Override + protected void convert(@NonNull BaseViewHolder helper, LuckyBagNoticeInfo noticeInfo) { + TextView tvName = helper.getView(R.id.tv_name); + TextView tvLucky = helper.getView(R.id.tv_luck); + TextView tvLuckyName = helper.getView(R.id.tv_luck_name); + String nickName = RegexUtil.getPrintableString(noticeInfo.getNick()); + tvName.setText(nickName); + tvLucky.setText(noticeInfo.getLuckyBagName()); + tvLuckyName.setText(noticeInfo.getGiftName()); + } + }; + rvLuckyMsg.setAdapter(luckyMsgAdapter); + rvLuckyMsg.setLayoutManager(new ScollLinearLayoutManager(context, ScollLinearLayoutManager.HORIZONTAL, false)); + rvLuckyMsg.setOnTouchListener((v, event) -> true); + } + + + luckyMsgDisposable = GiftModel.get().getLuckyGiftMsgList() + .compose(RxHelper.bindContext(context)) + .doOnSuccess(luckyBagNoticeInfos -> luckyMsgAdapter.setNewData(luckyBagNoticeInfos)) + .toObservable() + .flatMap(luckyBagNoticeInfos -> Observable.intervalRange(0, Integer.MAX_VALUE, 0, 5, TimeUnit.SECONDS)) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(aLong -> { + int index = aLong.intValue() % luckyMsgAdapter.getItemCount(); + if (index == 0) { + rvLuckyMsg.scrollToPosition(index); + } else { + rvLuckyMsg.smoothScrollToPosition(index); + } + }); + + + }else if(currentGiftInfo != null && currentGiftInfo.getGiftType() == GiftType.GIFT_TYPE_BRAVO) { + + mBravoBannerDesc.setVisibility(View.VISIBLE); + OtherExtKt.setRL(mBravoBannerIcon); + if (mBravoBannerDisposable != null) return; + + if (mBravoBannerAdapter == null) { + mBravoBannerAdapter = new BaseQuickAdapter<>(R.layout.item_bravo_gift_msg) { + @Override + protected void convert(@NonNull BaseViewHolder helper, BravoNoticeInfo info) { + ImageLoadUtils.loadAvatar(context,info.getAvatar(),helper.getView(R.id.avatar)); + + String nickStr = info.getNick(); + if (nickStr.length()>3){ + nickStr = info.getNick().substring(0, 3) + "..."; + } + List textStyles = new ArrayList<>(); + SpannableTextBuilder.TextStyleBean nick = new SpannableTextBuilder.TextStyleBean(); + nick.setTextColor(ResourcesKtxKt.getColor(R.color.white)); + nick.setText(nickStr); + textStyles.add(nick); + + SpannableTextBuilder.TextStyleBean giftName = new SpannableTextBuilder.TextStyleBean(); + giftName.setTextColor(Color.parseColor("#FFEC6F")); + giftName.setText(info.getGiftName()); + giftName.setTextSize(13); + giftName.setTextStyle(Typeface.BOLD); + textStyles.add(giftName); + + String coinStr = OtherExtKt.formatToString(info.getCoin()); + SpannableTextBuilder.TextStyleBean coin = new SpannableTextBuilder.TextStyleBean(); + coin.setTextColor(Color.parseColor("#FFEC6F")); + coin.setText(coinStr); + coin.setTextStyle(Typeface.BOLD); + coin.setTextSize(16); + textStyles.add(coin); + + StringBuffer textStr = new StringBuffer(); + textStr.append(nickStr); + textStr.append(ResourcesKtxKt.getString(R.string.send)); + textStr.append(info.getGiftName()); + textStr.append(ResourcesKtxKt.getString(R.string.win)); + textStr.append(coinStr); + + DrawableTextView text = helper.getView(R.id.text); + new SpannableTextBuilder(text) + .appendText(textStr.toString()) + .addTextStyleList(textStyles) + .apply(); + + + View root = helper.getView(R.id.root); + OtherExtKt.postSafe(root,() -> { + int maxWidth = root.getWidth() - OtherExtKt.toDP(30); + text.setMaxWidth(maxWidth); + return null; + }); + + + } + }; + mRvBravoBanner.setAdapter(mBravoBannerAdapter); + mRvBravoBanner.setLayoutManager(new ScollLinearLayoutManager(context, ScollLinearLayoutManager.HORIZONTAL, false)); + mRvBravoBanner.setOnTouchListener((v, event) -> true); + OtherExtKt.setRL(mBgBravoBanner); + } + + mBravoBannerDisposable = GiftModel.get().getBravoGiftMsgList() + .compose(RxHelper.bindContext(context)) + .doOnSuccess(luckyBagNoticeInfos -> { + mBravoBannerAdapter.setNewData(luckyBagNoticeInfos); + }) + .toObservable() + .flatMap(luckyBagNoticeInfos -> Observable.intervalRange(0, Integer.MAX_VALUE, 0, 5, TimeUnit.SECONDS)) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(aLong -> { + int index = aLong.intValue() % mBravoBannerAdapter.getItemCount(); + if (index == 0) { + mRvBravoBanner.scrollToPosition(index); + } else { + mRvBravoBanner.smoothScrollToPosition(index); + } + }); + + }else { + flLuckyDesc.setVisibility(View.GONE); + mBravoBannerDesc.setVisibility(View.GONE); + } + } + + private void updateWeekStarDesc() { + + if (giftIndicator.getCurrrentType() == TYPE_WEEK) { + flLuckyDesc.setVisibility(View.GONE); + llStarWeek.setVisibility(View.GONE); + mStarWeekBanner.setVisibility(View.VISIBLE); + } else { + llStarWeek.setVisibility(View.GONE); + mStarWeekBanner.setVisibility(View.GONE); + return; + } + + if (currentGiftInfo == null) { + llStarWeek.setVisibility(View.INVISIBLE); + mStarWeekBanner.setVisibility(View.GONE); + return; + } + + SimpleUserInfo firstCharmRankUser = currentGiftInfo.getFirstCharmRankUser(); + if (firstCharmRankUser != null) { + ImageLoadUtils.loadImage(getContext(), firstCharmRankUser.getAvatar(), ivAvatarCharm); + ivAvatarCharm.setOnClickListener(v -> { + if (firstCharmRankUser.getUid() == 0) return; + EventBus.getDefault().post(new ShowUserInfoDialogEvent(String.valueOf(firstCharmRankUser.getUid()))); + }); + tvNickCharm.setText(StringExtensionKt.subAndReplaceDot(firstCharmRankUser.getNick(), 10)); + } else { + ivAvatarCharm.setOnClickListener(null); + ivAvatarCharm.setImageResource(R.drawable.default_avatar); + tvNickCharm.setText(ResUtil.getString(R.string.ui_widget_giftdialog_013)); + } + + SimpleUserInfo firstLevelRankUser = currentGiftInfo.getFirstLevelRankUser(); + if (firstLevelRankUser != null) { + ImageLoadUtils.loadImage(getContext(), firstLevelRankUser.getAvatar(), ivAvatarLevel); + ivAvatarLevel.setOnClickListener(v -> { + if (firstLevelRankUser.getUid() == 0) return; + EventBus.getDefault().post(new ShowUserInfoDialogEvent(String.valueOf(firstLevelRankUser.getUid()))); + }); + tvNickLevel.setText(StringExtensionKt.subAndReplaceDot(firstLevelRankUser.getNick(), 10)); + } else { + ivAvatarLevel.setOnClickListener(null); + ivAvatarLevel.setImageResource(R.drawable.default_avatar); + tvNickLevel.setText(ResUtil.getString(R.string.ui_widget_giftdialog_014)); + } + + List list = new ArrayList<>(); + if (firstCharmRankUser != null) { + list.add(firstCharmRankUser); + } else { + list.add(new SimpleUserInfo()); + } + if (firstLevelRankUser != null) { + list.add(firstLevelRankUser); + } else { + list.add(new SimpleUserInfo()); + } + + mStarWeekBanner.setAdapter(new StarWeekAdapter()); + mStarWeekBanner.setPageMargin(UIUtil.dip2px(context, 10)) + .setScrollDuration(1200) + .setInterval(4500) + .setRevealWidth(BannerUtils.dp2px(0f)) + .setOnPageClickListener((clickedView, position) -> { + DialogWebViewActivity.start(context, UriProvider.getWeekStarUrl(), true); + }) + .create(list); + } + + private void updateDrawGift() { + if (drawGiftHelper == null) { + drawGiftHelper = new DrawGiftHelper((Activity) context); + } + if (isShowDrawGiftModel && + currentGiftInfo != null && + giftIndicator.getCurrrentType() == GiftIndicator.TYPE_DRAW_GIFT) { + drawGiftHelper.lazyDrawGiftView( + ScreenUtil.dip2px(160) + ScreenUtil.getStatusBarHeight(context), + new DrawGiftView.DrawGiftListener() { + + @Override + public void onReachMaxDrawSize() { + SingleToastUtil.showToast(ResUtil.getString(R.string.ui_widget_giftdialog_015) + MAX_DRAW_SIZE + ResUtil.getString(R.string.ui_widget_giftdialog_016)); + } + + @Override + public void onGiftPainted(DrawGiftView drawGiftView, int giftId) { + updateDrawGiftTips(); + } + + @Override + public void onTouchEventUpWhenDrawDisable(DrawGiftView drawGiftView) { + dismiss(); + } + } + ); + drawGiftHelper.setCurrentGift( + currentGiftInfo.getGiftId(), + currentGiftInfo.getGiftUrl(), + currentGiftInfo.getGoldPrice() + ); + drawGiftHelper.setMaxDrawSize(MAX_DRAW_SIZE); + rlGifts.setVisibility(View.GONE); + llTabs.setVisibility(View.GONE); + giftNumLayout.setVisibility(View.GONE); + llDrawGift.setVisibility(View.VISIBLE); + drawGiftHelper.setDrawEnable(true); + sendGiftButton.setEnabled(false); + WindowManager.LayoutParams params = getWindow().getAttributes(); + if (params.dimAmount != 0.7f) { + params.dimAmount = 0.7f; + getWindow().setAttributes(params); + } + } else { + WindowManager.LayoutParams params = getWindow().getAttributes(); + if (params.dimAmount != 0f) { + params.dimAmount = 0f; + getWindow().setAttributes(params); + } + rlGifts.setVisibility(View.VISIBLE); + llTabs.setVisibility(View.VISIBLE); + llDrawGift.setVisibility(View.GONE); + drawGiftHelper.setDrawEnable(false); + drawGiftHelper.resetDrawGiftView(); + boolean isDrawGiftTab = giftIndicator.getCurrrentType() == GiftIndicator.TYPE_DRAW_GIFT; + sendGiftButton.setEnabled(!isDrawGiftTab); + giftNumLayout.setVisibility(isDrawGiftTab ? View.GONE : View.VISIBLE); + } + } + + private void updateDrawGiftTips() { + if (drawGiftHelper == null) return; + if (drawGiftHelper.getDrawGiftSize() >= 10) { + int memberSize = 0; + if (!userOnMic && uid > 0) { + memberSize = 1; + } else if (avatarListAdapter != null && avatarListAdapter.getSelectedMember().size() > 0) { + memberSize = avatarListAdapter.getSelectedMember().size(); + } + SpannableBuilder spannableBuilder = new SpannableBuilder(); + spannableBuilder.append(ResUtil.getString(R.string.ui_widget_giftdialog_017)) + .append(String.valueOf(drawGiftHelper.getDrawGiftSize()), new ForegroundColorSpan(Color.parseColor("#FFBC51"))) + .append(ResUtil.getString(R.string.ui_widget_giftdialog_018)) + .append(String.valueOf(memberSize * drawGiftHelper.getTotalPrice()), new ForegroundColorSpan(Color.parseColor("#FFBC51"))) + .append(ResUtil.getString(R.string.avroom_widget_messageview_027)); + tvDrawGiftTips.setText(spannableBuilder.build()); + sendGiftButton.setEnabled(true); + } else { + boolean isDrawGiftTab = giftIndicator.getCurrrentType() == GiftIndicator.TYPE_DRAW_GIFT; + sendGiftButton.setEnabled(!isDrawGiftTab); + tvDrawGiftTips.setText(ResUtil.getString(R.string.ui_widget_giftdialog_020)); + } + } + + private void updateTotalPrice() { +// String diamond = ""; +// double totalValue = 0; +// for (int i = 0; i < currentGiftInfoList.size(); i++) { +// totalValue += currentGiftInfoList.get(i).getCount() * currentGiftInfoList.get(i).getGoldPrice(); +// } +// if (totalValue >= 10000) { +// totalValue = totalValue / 10000.0f; +// diamond = FormatUtils.formatBigDecimal(totalValue) + "W+"; +// } else { +// diamond = String.valueOf((int) totalValue); +// } +// SpannableBuilder text = new SpannableBuilder() +// .append(ResUtil.getString(R.string.ui_widget_giftdialog_021), new ForegroundColorSpan(Color.parseColor("#7A797A"))) +// .append(diamond + ResUtil.getString(R.string.avroom_widget_messageview_027), new ForegroundColorSpan(Color.WHITE)); +// tvGiftValue.setText(text.build()); + } + + private void showEmptyView() { + //tab对应的礼物列表为空的情况 + layoutEmpty.setVisibility(View.VISIBLE); + layoutLoadFiled.setVisibility(View.GONE); + layoutLoading.setVisibility(View.GONE); + gridView.setVisibility(View.INVISIBLE); + etSendMessage.setVisibility(View.GONE); + indicatorView.setVisibility(View.INVISIBLE); + } + + private void showLoadFailedView() { + layoutLoading.setVisibility(View.GONE); + layoutLoadFiled.setVisibility(View.VISIBLE); + layoutEmpty.setVisibility(View.GONE); + gridView.setVisibility(View.GONE); + etSendMessage.setVisibility(View.GONE); + indicatorView.setVisibility(View.GONE); + } + + private void showLoadingView() { + layoutLoading.setVisibility(View.VISIBLE); + layoutLoadFiled.setVisibility(View.GONE); + layoutEmpty.setVisibility(View.GONE); + } + + private void showDataView() { + layoutLoading.setVisibility(View.GONE); + layoutLoadFiled.setVisibility(View.GONE); + layoutEmpty.setVisibility(View.GONE); + etSendMessage.setVisibility(View.GONE); +// tvGiftValue.setVisibility(View.GONE); + llStarWeek.setVisibility(View.GONE); + + gridView.setVisibility(View.VISIBLE); + indicatorView.setVisibility(View.VISIBLE); + sendContainer.setVisibility(View.VISIBLE); + } + + + + private List loadGiftInfoList() { + List giftInfos; + String roomUid = null; + if (isInRoom) { + if (AvRoomDataManager.get().getRoomUid() > 0) { + // 如果在房间内,就用房间的 UID + roomUid = String.valueOf(AvRoomDataManager.get().getRoomUid()); + } else { + // 如果是在公聊大厅,那就用公聊大厅的 UID + roomUid = InitialModel.get().getPublicChatHallUid(); + } + //房间送礼面板 + giftInfos = GiftModel.get().getGiftInfosByType(roomUid, GiftType.GIFT_TYPE_NORMAL); + } else { + // 私聊送礼面板 不在房间内,直接在普通的列表里选出房间礼物进行显示 + giftInfos = GiftModel.get().getGiftInfoList(GiftType.GIFT_TYPE_NORMAL); + } + if (ListUtils.isListEmpty(giftInfos)) return new ArrayList<>(); + return giftInfos; + } + + private List getAllTabsAndGiftInfos() { + List tagsInfos = null; + return tagsInfos; + } + + private List getNormalGiftInfos() { + List giftInfos = loadGiftInfoList(); + List infos = new ArrayList<>(); + for (int i = 0; i < giftInfos.size(); i++) { + GiftInfo giftInfo = giftInfos.get(i); + if (!giftInfo.isNobleGift() || giftInfo.getLevel() == 0) { + infos.add(giftInfo); + } + } + return infos; + } + + private List getWeekStarGiftInfos() { + return GiftModel.get().getGiftInfosByType( + String.valueOf(AvRoomDataManager.get().getRoomUid()), + GiftType.GIFT_TYPE_WEEK_STAR); + } + + private List getLuckyGiftInfos() { + return GiftModel.get().getGiftInfosByType( + String.valueOf(AvRoomDataManager.get().getRoomUid()), + GiftType.GIFT_TYPE_LUCKY); + } + + private List getDrawGiftInfos() { + return GiftModel.get().getGiftInfosByType( + String.valueOf(AvRoomDataManager.get().getRoomUid()), + GiftType.GIFT_TYPE_DRAW_GIFT); + } + + private List getSingleRoomGiftInfos() { + return GiftModel.get().getGiftInfosByType( + String.valueOf(AvRoomDataManager.get().getRoomUid()), + GiftType.GIFT_TYPE_SINGLE_ROOM); + } + + private List getSuperLuckyGiftInfos() { + return GiftModel.get().getGiftInfosByType( + String.valueOf(AvRoomDataManager.get().getRoomUid()), + GiftType.GIFT_TYPE_SUPER_LUCKY); + } + + private List getCountryGiftInfos() { + return GiftModel.get().getGiftInfosByType( + String.valueOf(AvRoomDataManager.get().getRoomUid()), + GiftType.GIFT_TYPE_COUNTRY); + } + private List getCpGiftInfos() { + return GiftModel.get().getGiftInfosByType( + String.valueOf(AvRoomDataManager.get().getRoomUid()), + GiftType.GIFT_TYPE_CP); + } + + private List getCustomGiftInfos() { + return GiftModel.get().getGiftInfosByType( + String.valueOf(AvRoomDataManager.get().getRoomUid()), + GiftType.GIFT_TYPE_CUSTOM); + } + + private List getBravoGiftInfos() { + return GiftModel.get().getGiftInfosByType( + String.valueOf(AvRoomDataManager.get().getRoomUid()), + GiftType.GIFT_TYPE_BRAVO); + } + + private List getNobleGiftInfos() { + return GiftModel.get().getGiftInfoList(GiftType.GIFT_TYPE_VIP); + } + + private void initEasyPop(boolean isBag) { + + easyPopup = new EasyPopup(getContext()) + .setContentView(R.layout.dialog_gift_number_new) + .setFocusAndOutsideEnable(true) + .createPopup(); + + RecyclerView rvNumList = easyPopup.getView(R.id.rvNumList); + if (rvNumList == null) return; + if (mGiftDialogNumberAdapter == null) { + mGiftDialogNumberAdapter = new GiftDialogNumberAdapter(); + mGiftDialogNumberAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() { + @Override + public void onItemClick(BaseQuickAdapter baseQuickAdapter, View view, int i) { + OtherExtKt.isVerify(mGiftDialogNumberAdapter.getData(), i, integer -> { + updateNumber(integer); + return null; + }); + } + }); + } + rvNumList.setAdapter(mGiftDialogNumberAdapter); + mGiftDialogNumberAdapter.setNewData(RoomHelperManager.INSTANCE.getGiftNumbers(isBag)); + + easyPopup.setOnDismissListener(() -> giftNumberOptions.animate().rotationBy(180).start()); + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.tv_recharge: + + if (itemType == ITEM_TYPE_GOLD) { + //充值 + if (GIFT_DIALOG_FROM.equals(ResUtil.getString(R.string.room))) { + HashMap map = new HashMap<>(5); + map.put(IReportConstants.PAYPAGE_TYPE, IReportConstants.ONE); + if (goldWalletInfo != null) { + map.put(IReportConstants.ACCOUNT_BALANCE, goldWalletInfo.getDiamondNum()); + } + map.put(IReportConstants.MODULE, IReportConstants.MOLISTAR_PAY); + ReportManager.get().reportEvent(IReportConstants.PAYPAGE_SHOW, map); + } else if (GIFT_DIALOG_FROM.equals(ResUtil.getString(R.string.im_actions_giftaction_01))) { + HashMap map = new HashMap<>(5); + map.put(IReportConstants.PAYPAGE_TYPE, IReportConstants.NINE); + if (goldWalletInfo != null) { + map.put(IReportConstants.ACCOUNT_BALANCE, goldWalletInfo.getDiamondNum()); + } + map.put(IReportConstants.MODULE, IReportConstants.MOLISTAR_PAY); + ReportManager.get().reportEvent(IReportConstants.PAYPAGE_SHOW, map); + } +// if (AppMetaDataUtil.getChannelID().equals(Constants.GOOGLE)) { + ChargeActivity.start(context); +// } else { +// CommonWebViewActivity.start( +// context, UriProvider.getOfficialPay( +// 4, +// DeviceUtil.getDeviceId(context) +// ) +// ); +// } + } else if (itemType == ITEM_TYPE_RADISH) { + TaskCenterActivity.start(context, TaskCenterActivity.FromPage.GIFT); + } + + dismiss(); + break; + //送礼物 + case R.id.btn_send: + final GiftInfo finalCurrentGiftInfo = currentGiftInfo; + sendGiftButton.setEnabled(false); + sendGiftButton.setText(ResUtil.getString(R.string.ui_widget_giftdialog_024)); + Log.e(TAG, "onClick: indicator type: " + giftIndicator.getCurrrentType()); + if (!AuthModel.get().isImLogin()) { + SingleToastUtil.showToast(ResUtil.getString(R.string.ui_widget_giftdialog_025)); + sendGiftButton.setText(ResUtil.getString(R.string.ui_widget_giftdialog_026)); + sendGiftButton.setEnabled(true); + return; + } + if (finalCurrentGiftInfo == null || giftDialogBtnClickListener == null) { + sendGiftButton.setText(ResUtil.getString(R.string.ui_widget_giftdialog_027)); + sendGiftButton.setEnabled(true); + return; + } + String giftMessage = getGiftMessage(); + if (Objects.equals(giftMessage, "")) { + SingleToastUtil.showToast(ResUtil.getString(R.string.ui_widget_giftdialog_028)); + sendGiftButton.setText(ResUtil.getString(R.string.ui_widget_giftdialog_029)); + sendGiftButton.setEnabled(true); + } else { + if (!isInRoom) {//不在房间的情况 + ArrayList targetUids = new ArrayList<>(); + MicMemberInfo micMemberInfo = new MicMemberInfo(); + micMemberInfo.setAccount(String.valueOf(uid)); + targetUids.add(micMemberInfo); + Log.e(TAG, "onClick: indicator type: " + giftIndicator.getCurrrentType()); + giftDialogBtnClickListener.onSendGiftBtnClick( + finalCurrentGiftInfo, + targetUids, + giftNumber == -1 ? finalCurrentGiftInfo.getCount() : giftNumber, + giftMessage, + giftIndicator.getCurrrentType() == GiftIndicator.TYPE_KNAP, + false, + getDrawFixedArray(), + new SenGiftCallback() { + @Override + public void onSuccess() { + onSendGiftSuccess(finalCurrentGiftInfo); + } + + @Override + public void onFail() { + if (sendGiftButton == null) return; + sendGiftButton.setText(ResUtil.getString(R.string.ui_widget_giftdialog_030)); + sendGiftButton.setEnabled(true); + onSendGiftFile(); + } + }); + etSendMessage.setText(""); + return; + } + if (!userOnMic && uid > 0) { +// if (uid == AuthModel.get().getCurrentUid()) { +// SingleToastUtil.showToast(ResUtil.getString(R.string.send_gift_to_self_tips)); +// sendGiftButton.setText(ResUtil.getString(R.string.ui_widget_giftdialog_026)); +// sendGiftButton.setEnabled(true); +// return; +// } + ArrayList targetUids = new ArrayList<>(); + MicMemberInfo micMemberInfo = new MicMemberInfo(); + micMemberInfo.setAccount(String.valueOf(uid)); + targetUids.add(micMemberInfo); + Log.e(TAG, "onClick: indicator type: " + giftIndicator.getCurrrentType()); + giftDialogBtnClickListener.onSendGiftBtnClick( + finalCurrentGiftInfo, + targetUids, + giftNumber == -1 ? finalCurrentGiftInfo.getCount() : giftNumber, + giftMessage, + giftIndicator.getCurrrentType() == GiftIndicator.TYPE_KNAP, + false, + getDrawFixedArray(), + new SenGiftCallback() { + @Override + public void onSuccess() { + onSendGiftSuccess(finalCurrentGiftInfo); + } + + @Override + public void onFail() { + if (sendGiftButton == null) return; + sendGiftButton.setText(ResUtil.getString(R.string.ui_widget_giftdialog_031)); + sendGiftButton.setEnabled(true); + onSendGiftFile(); + } + }); + etSendMessage.setText(""); + } else if (avatarListAdapter != null && avatarListAdapter.getSelectedMember().size() > 0) { + ArrayList selectedMembers = (ArrayList) avatarListAdapter.getSelectedMember(); + + if (giftIndicator.getCurrrentType() == GiftIndicator.TYPE_KNAP + && giftNumber * selectedMembers.size() > finalCurrentGiftInfo.getCount()) { + SingleToastUtil.showToast(ResUtil.getString(R.string.ui_widget_giftdialog_032)); + sendGiftButton.setText(ResUtil.getString(R.string.ui_widget_giftdialog_033)); + sendGiftButton.setEnabled(true); + return; + } + giftDialogBtnClickListener.onSendGiftBtnClick( + finalCurrentGiftInfo, + selectedMembers, + giftNumber == -1 ? finalCurrentGiftInfo.getCount() : giftNumber, + giftMessage, + giftIndicator.getCurrrentType() == GiftIndicator.TYPE_KNAP, + avatarListAdapter.getSelectType() == GiftAvatarAdapter.SELECT_TYPE_WHOLE_MIC, + getDrawFixedArray(), + new SenGiftCallback() { + @Override + public void onSuccess() { + onSendGiftSuccess(finalCurrentGiftInfo); + } + + @Override + public void onFail() { + if (sendGiftButton == null) return; + sendGiftButton.setText(ResUtil.getString(R.string.ui_widget_giftdialog_034)); + sendGiftButton.setEnabled(true); + onSendGiftFile(); + } + }); + + etSendMessage.setText(""); + } else if (micMemberInfos.size() == 0) { + SingleToastUtil.showToast(ResUtil.getString(R.string.ui_widget_giftdialog_035)); + sendGiftButton.setText(ResUtil.getString(R.string.ui_widget_giftdialog_036)); + sendGiftButton.setEnabled(true); + dismiss(); + } else { + SingleToastUtil.showToast(ResUtil.getString(R.string.ui_widget_giftdialog_037)); + sendGiftButton.setText(ResUtil.getString(R.string.ui_widget_giftdialog_038)); + sendGiftButton.setEnabled(true); + } + } + + break; + case R.id.number_1: + updateNumber(1); + break; + case R.id.number_10: + updateNumber(10); + break; + case R.id.number_66: + updateNumber(66); + break; + case R.id.number_99: + updateNumber(99); + break; + case R.id.number_188: + updateNumber(188); + break; + case R.id.number_520: + updateNumber(520); + break; + case R.id.number_1314: + updateNumber(1314); + break; + case R.id.number_all: + updateNumber(-1); + break; + case R.id.number_manual: + GiftManualQuantityDialog giftManualQuantityDialog = new GiftManualQuantityDialog(context); + giftManualQuantityDialog.setOnConfirmClick(new GiftManualQuantityDialog.OnConfirmClick() { + @Override + public void onConfirm(int quantity) { + updateNumber(quantity); + giftManualQuantityDialog.dismiss(); + } + }); + giftManualQuantityDialog.show(); + easyPopup.dismiss(); + break; + case R.id.gift_number_layout: + showEasyPopup(); + break; + case R.id.iv_open_noble: + VipCenterActivity.start(context); + //进入贵族中心埋点 + HashMap map = new HashMap<>(5); + map.put(IReportConstants.PAYPAGE_TYPE, IReportConstants.THREE); + if (goldWalletInfo != null) { + map.put(IReportConstants.ACCOUNT_BALANCE, goldWalletInfo.getDiamondNum()); + } + map.put(IReportConstants.MODULE, IReportConstants.MOLISTAR_PAY); + ReportManager.get().reportEvent(IReportConstants.PAYPAGE_SHOW, map); + break; + case R.id.tv_reload: + reloadData(true); + break; + case R.id.iv_draw_gift_close: + clearDrawGift(); + isShowDrawGiftModel = false; + updateDrawGift(); + break; + case R.id.iv_draw_gift_remove_last: + if (drawGiftHelper != null) { + drawGiftHelper.removeLastStroke(); + updateDrawGiftTips(); + } + break; + case R.id.iv_draw_gift_remove_all: + clearDrawGift(); + break; + case R.id.tv_lucky_bag_intro: + if (currentGiftInfo == null) break; + if (currentGiftInfo.getGiftType() == GiftType.GIFT_TYPE_LUCKY) { + DialogWebViewActivity.start(context, UriProvider.getLuckyGiftRule(currentGiftInfo.getGiftId()), true); + } else { + DialogWebViewActivity.start(context, currentGiftInfo.getGiftExplainUrl(), true); + } + break; + default: + break; + } + } + + private void onSendGiftSuccess(GiftInfo giftInfo) { + if (sendGiftButton == null) return; + sendGiftButton.setText(ResUtil.getString(R.string.ui_widget_giftdialog_040)); + sendGiftButton.setEnabled(true); + if (giftInfo.getGiftType() == GiftType.GIFT_TYPE_DRAW_GIFT) { + SingleToastUtil.showToast(ResUtil.getString(R.string.ui_widget_giftdialog_041) + giftInfo.getGiftName() + ResUtil.getString(R.string.ui_widget_giftdialog_042)); + clearDrawGift(); + dismiss(); + }else if (giftInfo.getGiftType() == GiftType.GIFT_TYPE_NORMAL + || giftInfo.getGiftType() == GiftType.GIFT_TYPE_SUPER_LUCKY + || giftInfo.getGiftType() == GiftType.GIFT_TYPE_LUCKY_24 + || giftInfo.getGiftType() == GiftType.GIFT_TYPE_BRAVO + || giftInfo.getGiftType() == GiftType.GIFT_TYPE_LUCKY_25 + ) { + this.hide(); + int num = giftNumber == -1 ? giftInfo.getCount() : giftNumber; + if (isInRoom) { + GiftComboEvent giftComboEvent = new GiftComboEvent(GiftComboEvent.Action.ACT_GIFT_SEND_SUCCESS); + giftComboEvent.setGiftNumber(num); + EventBus.getDefault().post(giftComboEvent); + } + } + + + } + + protected void onSendGiftFile() { + EventBus.getDefault().post(new GiftComboEvent(GiftComboEvent.Action.ACT_GIFT_COMBO_CANCEL)); + } + + private void reloadData(final boolean needShowLoading) { + if (needShowLoading) showLoadingView(); + int currentType = giftIndicator.getCurrrentType(); + switch (currentType) { + case TYPE_NORMAL: + case GiftIndicator.TYPE_LUCKY: + case TYPE_NOBLE: + case TYPE_WEEK: + String roomUid = null; + if (isInRoom) { + if (AvRoomDataManager.get().getRoomUid() > 0) { + // 如果在房间内,就用房间的 UID + roomUid = String.valueOf(AvRoomDataManager.get().getRoomUid()); + } else { + // 如果是在公聊大厅,那就用公聊大厅的 UID + roomUid = InitialModel.get().getPublicChatHallUid(); + } + } + compositeDisposable.add(GiftModel.get().refreshGiftList(roomUid) + .subscribe((giftListInfoServiceResult, throwable) -> { + if (throwable == null) { + // 返回结果时,当前选中选项与请求时的选项一样时才显示 + if (currentType == giftIndicator.getCurrrentType()) { + updateGiftView(giftIndicator.getCurrrentType(), currentGiftInfo); + } + } else { + if (needShowLoading) showLoadFailedView(); + } + }) + ); + break; + + case GiftIndicator.TYPE_KNAP: + compositeDisposable.add(GiftModel.get() + .requestKnapGiftInfos() + .subscribe((listServiceResult, throwable) -> { + if (throwable == null) { + if (currentType == giftIndicator.getCurrrentType()) { + updateGiftView(giftIndicator.getCurrrentType()); + } + } else { + if (needShowLoading) showLoadFailedView(); + } + }) + ); + break; + } + } + + private String getGiftMessage() { + if (currentGiftInfo != null && currentGiftInfo.isSendMsg()) { + if (etSendMessage.getText().toString().length() == 0) { + return getContext().getString(R.string.tips_input_gift_message); + } else { + if (Objects.equals(etSendMessage.getText().toString().trim(), "")) { + return ""; + } else { + return etSendMessage.getText().toString().trim(); + } + } + } else { + return null; + } + } + + private void updateNumber(int number) { + giftNumber = number; + giftNumberText.setText(giftNumber == -1 ? "all" : giftNumber + ""); + easyPopup.dismiss(); + } + + private void showEasyPopup() { + giftNumberOptions.animate().rotationBy(180).start(); + easyPopup.showAtAnchorView(giftNumLayout, VerticalGravity.ABOVE, HorizontalGravity.ALIGN_LEFT, + 0, -UIUtil.dip2px(context, 11)); + } + + @Nullable + private List> getDrawFixedArray() { + return drawGiftHelper == null ? null : drawGiftHelper.getDrawFixedArray(); + } + + private void clearDrawGift() { + if (drawGiftHelper != null) { + drawGiftHelper.clearDrawGift(); + updateDrawGiftTips(); + } + } + + @Override + public void onDetachedFromWindow() { + super.onDetachedFromWindow(); + EventBus.getDefault().unregister(this); + if (mSubscribe != null) { + mSubscribe.dispose(); + mSubscribe = null; + } + if (compositeDisposable != null) { + compositeDisposable.dispose(); + compositeDisposable = null; + } + if (luckyMsgDisposable != null) { + luckyMsgDisposable.dispose(); + luckyMsgDisposable = null; + } + if (mBravoBannerDisposable != null) { + mBravoBannerDisposable.dispose(); + mBravoBannerDisposable = null; + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onWalletInfoUpdate(UpdateWalletInfoEvent event) { + goldWalletInfo = PayModel.get().getCurrentWalletInfo(); + setGoldOrRadishText(lastSelectedItem); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onRecieveGiftKnapMsg(UpdateKnapEvent event) { + //刷新背包礼物 + compositeDisposable.add(GiftModel.get().requestKnapGiftInfos() + .compose(RxHelper.handleSchedulers()) + .subscribe()); + if (giftIndicator.getCurrrentType() != GiftIndicator.TYPE_KNAP) { + return; + } + int giftId = event.getGiftId(); + int sendNum = event.getSendNumber(); + if (ListUtils.isListEmpty(pagerList)) { + return; + } + for (GiftInfoVm item : pagerList) { + if (item.data.getGiftId() == giftId) { + int count = item.data.getCount() - sendNum; + item.data.setCount(Math.max(count, 0)); + item.updateCount(); + break; + } + } + updateTotalPrice(); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onReceiveFreeGift(UpdateKnapFreeGiftEvent event) { + if (giftIndicator.getCurrrentType() == GiftIndicator.TYPE_KNAP) { + int giftId = event.getGiftId(); + long progress = event.getProgress(); + if (ListUtils.isListEmpty(pagerList)) { + return; + } + + for (GiftInfoVm item: pagerList) { + if (item.data.getGiftId() == giftId) { + item.data.setFreeGiftProgress(progress); + item.updateFreeGiftCount(); + break; + } + } + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onReceiveFreeGiftNum(UpdateKnapFreeGiftNumEvent event) { + //刷新背包礼物 + compositeDisposable.add(GiftModel.get().requestKnapGiftInfos() + .compose(RxHelper.handleSchedulers()) + .subscribe()); + if (giftIndicator.getCurrrentType() == GiftIndicator.TYPE_KNAP) { + int giftId = event.getGiftId(); + if (ListUtils.isListEmpty(pagerList)) { + return; + } + for (GiftInfoVm item : pagerList) { + if (item.data.getGiftId() == giftId) { + int count; + if (event.isReset()) { + count = 0; + } else { + count = item.data.getCount() + 1; + } + item.data.setCount(Math.max(count, 0)); + item.updateCount(); + break; + } + } + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onReceiveFreeGiftData(UpdateKnapFreeGiftDataEvent event) { + //刷新背包礼物 + compositeDisposable.add(GiftModel.get().requestKnapGiftInfos() + .compose(RxHelper.handleSchedulers()) + .subscribe()); + if (giftIndicator.getCurrrentType() == GiftIndicator.TYPE_KNAP) { + RoomFreeGiftMsgBean roomFreeGiftMsgBean = event.getRoomFreeGiftMsgBean(); + if (ListUtils.isListEmpty(pagerList)) { + return; + } + for (GiftInfoVm item : pagerList) { + if (item.data.getGiftId() == roomFreeGiftMsgBean.getGiftId()) { + item.data.setGiftId(roomFreeGiftMsgBean.getGiftId()); + item.data.setGiftName(roomFreeGiftMsgBean.getGiftName()); + item.data.setGiftUrl(roomFreeGiftMsgBean.getGiftUrl()); + break; + } + } + } + } + + private void onGiftOutOfDate(String message) { + ((BaseActivity) getContext()).toast(message); + } + + @Override + public void onItemSelected(int position) { + avatarList.smoothScrollToPosition(position); + updateDrawGiftTips(); + } + + @Override + public void dismiss() { + super.dismiss(); + if (drawGiftHelper != null) { + drawGiftHelper.resetDrawGiftView(); + } + } + + public interface OnGiftDialogBtnClickListener { + + /** + * 新版全麦发礼物事件接口,带喊话功能 + * + * @param giftInfo + * @param micMemberInfos + * @param number + * @param msg + * @param isKnap + * @param isWholeMic + * @param callback + */ + default void onSendGiftBtnClick(GiftInfo giftInfo, + ArrayList micMemberInfos, + int number, + String msg, + boolean isKnap, + boolean isWholeMic, + @Nullable List> drawFixedArray, + SenGiftCallback callback){}; + + } + + public interface SenGiftCallback { + void onSuccess(); + + void onFail(); + } + + public void sendGift(){ + sendGiftButton.performClick(); + } + + //礼物连击相关 消息 + @Subscribe(threadMode = ThreadMode.MAIN) + public void onGiftComboEvent(GiftComboEvent event) { + switch (event.getAction()) { + case GiftComboEvent.Action.ACT_GIFT_COMBO_START: + sendGift(); + break; + case GiftComboEvent.Action.ACT_GIFT_DIALOG_SHOW: + show(); + break; + case GiftComboEvent.Action.ACT_GIFT_DIALOG_DISMISS: + dismiss(); + break; + } + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/GiftRecyclerView.java b/app/src/main/java/com/chwl/app/ui/widget/GiftRecyclerView.java new file mode 100644 index 0000000..8daaac1 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/GiftRecyclerView.java @@ -0,0 +1,77 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.ViewConfiguration; + +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.netease.nim.uikit.common.util.log.LogUtil; + +/** + * @author xiaoyu + * @date 2017/12/12 + */ + +public class GiftRecyclerView extends RecyclerView { + private static final String TAG = "gift"; + + public GiftRecyclerView(Context context) { + super(context); + } + + public GiftRecyclerView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + public GiftRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + private float mLastY; + private float mStartY; + private boolean allowIntercept = true; + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + int pos = ((GridLayoutManager) getLayoutManager()).findFirstVisibleItemPosition(); + switch (ev.getActionMasked()) { + case MotionEvent.ACTION_DOWN: + // down事件首先阻断父控件的拦截 + getParent().requestDisallowInterceptTouchEvent(true); + // 但是允许父控件后续的拦截 + allowIntercept = true; + mLastY = ev.getY(); + mStartY = ev.getY(); + break; + case MotionEvent.ACTION_MOVE: + LogUtil.e(TAG, "ACTION_MOVE"); + float dy = ev.getY() - mLastY; + float totalY = ev.getY() - mStartY; + if (pos == 0 && getChildAt(0).getTop() == 0) { + if (getChildAt(0).getTop() + dy < 0) { + // 只要内部滑动一次,则往后都不允许父控件拦截 + getParent().requestDisallowInterceptTouchEvent(true); + allowIntercept = false; + } + if (allowIntercept && ViewConfiguration.get(getContext()).getScaledTouchSlop() < totalY) { + getParent().requestDisallowInterceptTouchEvent(false); + } + } else { + // 如果当前第一个完整显示的位置不是0,则允许内部滑动 + allowIntercept = false; + getParent().requestDisallowInterceptTouchEvent(true); + } + mLastY = ev.getY(); + break; + case MotionEvent.ACTION_UP: + LogUtil.e(TAG, "ACTION_UP"); + break; + default: + } + return super.dispatchTouchEvent(ev); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/GridViewWithoutScroll.java b/app/src/main/java/com/chwl/app/ui/widget/GridViewWithoutScroll.java new file mode 100644 index 0000000..d5f7c08 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/GridViewWithoutScroll.java @@ -0,0 +1,40 @@ +package com.chwl.app.ui.widget; + +import android.annotation.TargetApi; +import android.content.Context; +import android.os.Build; +import android.util.AttributeSet; +import android.widget.GridView; + +/** + * @author jack + * @Description + * @Date 2018/4/16 + */ + +public class GridViewWithoutScroll extends GridView { + + public GridViewWithoutScroll(Context context) { + super(context); + } + + public GridViewWithoutScroll(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public GridViewWithoutScroll(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @TargetApi(Build.VERSION_CODES.O) + public GridViewWithoutScroll(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int expandHeightSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, + MeasureSpec.AT_MOST); + super.onMeasure(widthMeasureSpec, expandHeightSpec); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/InterceptTouchLayout.java b/app/src/main/java/com/chwl/app/ui/widget/InterceptTouchLayout.java new file mode 100644 index 0000000..8b4381d --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/InterceptTouchLayout.java @@ -0,0 +1,41 @@ +package com.chwl.app.ui.widget; + +import android.annotation.TargetApi; +import android.content.Context; +import android.os.Build; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +/** + * @author jack + * @Description + * @Date 2019/2/28 + */ +public class InterceptTouchLayout extends FrameLayout { + public InterceptTouchLayout(@NonNull Context context) { + super(context); + } + + public InterceptTouchLayout(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + public InterceptTouchLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + public InterceptTouchLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + return true; + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/LeftNotiDialog.java b/app/src/main/java/com/chwl/app/ui/widget/LeftNotiDialog.java new file mode 100644 index 0000000..529de58 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/LeftNotiDialog.java @@ -0,0 +1,94 @@ +package com.chwl.app.ui.widget; + +import android.app.Dialog; +import android.content.Context; +import android.os.Bundle; +import android.view.Gravity; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.TextView; + +import com.chwl.app.R; + +/** + * Created by zhouxiangfeng on 2017/5/13. + */ + +public class LeftNotiDialog extends Dialog implements View.OnClickListener { + + /** + * 上下文 + */ + private Context context; + private WindowManager windowManager; + private int width; + private TextView tvTitle; + private TextView tvOne; + private TextView tvTwo; + private TextView tvCancel; + private TextView tvNoti; + + public LeftNotiDialog(Context context, boolean cancelable, + OnCancelListener cancelListener) { + super(context, cancelable, cancelListener); + // TODO Auto-generated constructor stub + this.context = context; + } + + + public LeftNotiDialog(Context context) { + super(context, R.style.BottomSelectDialog); + // TODO Auto-generated constructor stub + this.context = context; + + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + // TODO Auto-generated method stub + super.onCreate(savedInstanceState); + requestWindowFeature(Window.FEATURE_NO_TITLE); + setContentView(R.layout.layout_left_noti_dialog); + findViewById(R.id.ll_content).setOnClickListener(this); + tvNoti = (TextView) findViewById(R.id.tv_noti); + setDialogShowAttributes(context, this);// 设置Dialog显示参数,出入动画 + } + + public static void setDialogShowAttributes(Context context, Dialog dialog) { + + WindowManager winManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);//获取窗口管理�? + int mScreenWidth = winManager.getDefaultDisplay().getWidth();//获取屏幕宽度,将此宽度设为要显示的Dialog窗口的宽�? + int mScreenHeight = winManager.getDefaultDisplay().getHeight();//获取屏幕宽度,将此宽度设为要显示的Dialog窗口的宽�? + Window mWindow = dialog.getWindow();//获取Dialog窗口 + mWindow.getDecorView().setPadding(0, 0, 0, 0); + WindowManager.LayoutParams Params = mWindow.getAttributes(); + Params.windowAnimations = R.style.left_dialog_anim_style;//设置窗口出入动画 +// Params.width = mScreenWidth/3; + Params.height = WindowManager.LayoutParams.MATCH_PARENT; +// Params.height = mScreenHeight; + mWindow.setAttributes(Params); + mWindow.setBackgroundDrawableResource(R.color.transparent_black); + mWindow.setGravity(Gravity.LEFT); + } + + public void setNoti(String noti) { + tvNoti.setText(noti); + } + + + @Override + public void onClick(View v) { + // TODO Auto-generated method stub + switch (v.getId()) { + case R.id.ll_content: + dismiss(); + break; + + default: + break; + } + } + + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/LevelHeadView.java b/app/src/main/java/com/chwl/app/ui/widget/LevelHeadView.java new file mode 100644 index 0000000..d66fc69 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/LevelHeadView.java @@ -0,0 +1,90 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.netease.nim.uikit.support.glide.GlideApp; +import com.chwl.app.R; +import com.chwl.app.common.widget.CircleImageView; +import com.chwl.core.user.bean.UserInfo; + +/** + * Created by zhouxiangfeng on 2017/6/3. + */ + +public class LevelHeadView extends RelativeLayout { + + private final Context context; + private View mView; + private CircleImageView civ_head; + private UserInfo userInfo; + private ImageView iv_trophy_level; + private TextView tv_pay_count; + + public LevelHeadView(Context context) { + super(context); + this.context = context; + init(); + } + + public LevelHeadView(Context context, AttributeSet attrs) { + super(context, attrs); + this.context = context; + init(); + } + + public LevelHeadView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + this.context = context; + init(); + } + + public LevelHeadView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + this.context = context; + init(); + } + + private void init() { + mView = LayoutInflater.from(context).inflate(R.layout.layout_level_head, this, true); + civ_head = (CircleImageView) mView.findViewById(R.id.civ_head); + iv_trophy_level = (ImageView) mView.findViewById(R.id.iv_trophy_level); + tv_pay_count = (TextView) mView.findViewById(R.id.tv_pay_count); + } + + public void setCivAvatar(String url) { + GlideApp.with(context).load(url).error(R.drawable.icon_plus_big).into(civ_head); + } + + public void setTrophyLevel(int level) { + switch (level) { + case 1: + GlideApp.with(context).load(R.drawable.icon_first).error(R.drawable.icon_plus_big).into(iv_trophy_level); + break; + + case 2: + GlideApp.with(context).load(R.drawable.icon_second).error(R.drawable.icon_plus_big).into(iv_trophy_level); + break; + + case 3: + GlideApp.with(context).load(R.drawable.icon_third).error(R.drawable.icon_plus_big).into(iv_trophy_level); + break; + } + } + + public void setPayCount(int payCount) { + tv_pay_count.setText(String.valueOf(payCount)); + } + + public void initiate(String avatar, int level, int payCount) { + setCivAvatar(avatar); + setTrophyLevel(level); + setPayCount(payCount); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/LevelUpDialog.java b/app/src/main/java/com/chwl/app/ui/widget/LevelUpDialog.java new file mode 100644 index 0000000..ae43d8b --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/LevelUpDialog.java @@ -0,0 +1,41 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.view.Window; +import android.view.WindowManager; + +import com.chwl.app.R; +import com.chwl.app.base.BaseBindingActivity; +import com.chwl.app.databinding.DialogLevelUpBinding; +import com.chwl.library.annatation.ActLayoutRes; + +/** + * Created by huangmeng1 on 2018/6/21. + */ +@ActLayoutRes(R.layout.dialog_level_up) +public class LevelUpDialog extends BaseBindingActivity { + public static void start(Context context, String name, boolean b) { + Intent intent = new Intent(context, LevelUpDialog.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.putExtra("name", name); + intent.putExtra("isExper", b); + context.startActivity(intent); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + requestWindowFeature(Window.FEATURE_NO_TITLE); + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); + super.onCreate(savedInstanceState); + } + + @Override + protected void init() { + mBinding.tvIKnow.setOnClickListener(v -> finish()); + boolean isExper = getIntent().getBooleanExtra("isExper", true); + mBinding.setIsExper(isExper); + mBinding.tvLevel.setText(getIntent().getStringExtra("name")); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/LinearLayoutManagerWrapper.java b/app/src/main/java/com/chwl/app/ui/widget/LinearLayoutManagerWrapper.java new file mode 100644 index 0000000..563e921 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/LinearLayoutManagerWrapper.java @@ -0,0 +1,34 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.util.AttributeSet; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +/** + * Created by huangmeng1 on 2018/4/2. + */ + +public class LinearLayoutManagerWrapper extends LinearLayoutManager { + public LinearLayoutManagerWrapper(Context context) { + super(context); + } + + public LinearLayoutManagerWrapper(Context context, int orientation, boolean reverseLayout) { + super(context, orientation, reverseLayout); + } + + public LinearLayoutManagerWrapper(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + @Override + public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { + try { + super.onLayoutChildren(recycler, state); + } catch (IndexOutOfBoundsException e) { + e.printStackTrace(); + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/ListViewWithoutScroll.java b/app/src/main/java/com/chwl/app/ui/widget/ListViewWithoutScroll.java new file mode 100644 index 0000000..2f5ba14 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/ListViewWithoutScroll.java @@ -0,0 +1,40 @@ +package com.chwl.app.ui.widget; + +import android.annotation.TargetApi; +import android.content.Context; +import android.os.Build; +import android.util.AttributeSet; +import android.widget.ListView; + +/** + * @author jack + * @Description + * @Date 2018/4/16 + */ + +public class ListViewWithoutScroll extends ListView { + public ListViewWithoutScroll(Context context) { + super(context); + } + + public ListViewWithoutScroll(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public ListViewWithoutScroll(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @TargetApi(Build.VERSION_CODES.O) + public ListViewWithoutScroll(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int expandHeightSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, + MeasureSpec.AT_MOST); + super.onMeasure(widthMeasureSpec, expandHeightSpec); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/LivingIconView.java b/app/src/main/java/com/chwl/app/ui/widget/LivingIconView.java new file mode 100644 index 0000000..252c1e5 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/LivingIconView.java @@ -0,0 +1,97 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Color; +import android.graphics.drawable.AnimationDrawable; +import android.util.AttributeSet; +import android.view.ViewGroup; + +import androidx.annotation.Nullable; +import androidx.appcompat.widget.AppCompatImageView; + +import com.chwl.app.R; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; + +/** + * @author jack + * @Description + * @Date 2018/4/19 + */ + +public class LivingIconView extends AppCompatImageView { + private int color = Color.RED; + + private volatile boolean isPlaying = false; + private volatile boolean isAttched = false; + + private AnimationDrawable drawable; + private int drawableId; + private int dpWidth = 0; + private int dpHeight = 0; + + public LivingIconView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + int dp_9 = UIUtil.dip2px(context, 9); + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LivingIconView); + drawableId = a.getResourceId(R.styleable.LivingIconView_cus_drawable, R.drawable.living_icon_animation); + dpWidth = (int) a.getDimension(R.styleable.LivingIconView_cus_dp_width, dp_9); + dpHeight = (int) a.getDimension(R.styleable.LivingIconView_cus_dp_height, dp_9); + a.recycle(); + init(context); + } + + private void init(Context context) { + drawable = (AnimationDrawable) context.getResources().getDrawable(drawableId); + drawable.setOneShot(false); + //setScaleType(ScaleType.FIT_CENTER); + setImageDrawable(drawable); + setLayoutParams(new ViewGroup.LayoutParams(dpWidth, dpHeight)); + } + + public void setColor(int color) { + this.color = color; + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + isAttched = true; + if (!isPlaying && drawable != null) {//开启子线程 + isPlaying = true; + drawable.start(); + } + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + isAttched = false; + if (drawable != null) { + drawable.stop(); + } + isPlaying = false; + } + + /** + * 开始播放 + */ + public void start() { + if (!isPlaying) { + if (isAttched && drawable != null) { + isPlaying = true; + drawable.start(); + } + } + } + + /** + * 停止子线程,并刷新画布 + */ + public void stop() { + isPlaying = false; + if (drawable != null) { + drawable.stop(); + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/LoadingAdapter.java b/app/src/main/java/com/chwl/app/ui/widget/LoadingAdapter.java new file mode 100644 index 0000000..97cb1da --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/LoadingAdapter.java @@ -0,0 +1,134 @@ +package com.chwl.app.ui.widget; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.IntDef; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.StaggeredGridLayoutManager; + +import com.chwl.app.R; + +import java.util.List; + +/** + *

具有加载更多的adapter

+ * Created by Administrator on 2017/11/13. + */ +public abstract class LoadingAdapter extends RecyclerView.Adapter { + + private static final int FOOTER = 10000; + private static final int NORMAL = 10001; + + public static final int STATUS_LOADING = 10; + public static final int STATUS_LOADED = 11; +// public static final int STATUS_LOADED = 11; + + @IntDef({STATUS_LOADING, STATUS_LOADED}) + public @interface Status { + } + + private int mStatus = STATUS_LOADED; + + private List mDataList; + + + public void setDataList(List dataList) { + mDataList = dataList; + notifyDataSetChanged(); + } + + public void setStatus(@Status int status) { + mStatus = status; + notifyDataSetChanged(); + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + if (viewType == FOOTER) { + return new LoadingViewHolder(LayoutInflater.from( + parent.getContext()).inflate(R.layout.loading_more_layout, parent, false)); + } else + return onCreateHolder(parent, viewType); + } + + protected abstract RecyclerView.ViewHolder onCreateHolder(ViewGroup parent, int viewType); + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + if (holder instanceof LoadingViewHolder) return; + onBindHolder(holder, position); + } + + protected abstract void onBindHolder(RecyclerView.ViewHolder holder, int position); + + @Override + public int getItemViewType(int position) { + if (position == getItemCount() - 2 && mStatus == STATUS_LOADING) { + return FOOTER; + } + return NORMAL; + } + + @Override + public int getItemCount() { + return mDataList == null ? 0 : mDataList.size() + (mStatus == STATUS_LOADING ? 1 : 0); + } + + //解决GridLayoutManager 占用问题 + @Override + public void onAttachedToRecyclerView(RecyclerView recyclerView) { + super.onAttachedToRecyclerView(recyclerView); + RecyclerView.LayoutManager manager = recyclerView.getLayoutManager(); + if (manager instanceof GridLayoutManager) { + final GridLayoutManager gridManager = ((GridLayoutManager) manager); + gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { + @Override + public int getSpanSize(int position) { + return isFooter(position) ? gridManager.getSpanCount() : 1; + } + }); + } + } + + private boolean isFooter(int position) { + return mStatus == STATUS_LOADING && position == getItemCount(); + } + + //处理StaggeredGridLayoutManager 占用问题 + @Override + public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { + super.onViewAttachedToWindow(holder); + if (isStaggeredGridLayout(holder)) { + handleLayoutIfStaggeredGridLayout(holder, holder.getLayoutPosition()); + } + } + + private boolean isStaggeredGridLayout(RecyclerView.ViewHolder holder) { + ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams(); + return layoutParams != null && layoutParams instanceof StaggeredGridLayoutManager.LayoutParams; + } + + private void handleLayoutIfStaggeredGridLayout(RecyclerView.ViewHolder holder, int position) { + if (/*isHeader(position) ||*/ isFooter(position)) { + StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) holder.itemView.getLayoutParams(); + p.setFullSpan(true); + } + } + + public static class LoadingViewHolder extends RecyclerView.ViewHolder { + + public LoadingViewHolder(View itemView) { + super(itemView); + } + } + + public static class NormalViewHolder extends RecyclerView.ViewHolder { + + public NormalViewHolder(View itemView) { + super(itemView); + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/LoadingDialog.java b/app/src/main/java/com/chwl/app/ui/widget/LoadingDialog.java new file mode 100644 index 0000000..762f9b2 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/LoadingDialog.java @@ -0,0 +1,30 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.graphics.drawable.AnimationDrawable; +import android.os.Bundle; +import android.widget.ImageView; + +import androidx.appcompat.app.AppCompatDialog; + +import com.chwl.app.R; + +/** + * @author xiaoyu + * @date 2017/12/13 + */ + +public class LoadingDialog extends AppCompatDialog { + + public LoadingDialog(Context context) { + super(context, R.style.ErbanUserInfoDialog); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.dialog_loading); + setCancelable(false); + setCanceledOnTouchOutside(false); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/MagicAdapter.java b/app/src/main/java/com/chwl/app/ui/widget/MagicAdapter.java new file mode 100644 index 0000000..8169033 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/MagicAdapter.java @@ -0,0 +1,155 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.recyclerview.widget.RecyclerView; + +import com.netease.nim.uikit.support.glide.GlideApp; +import com.chwl.app.R; +import com.chwl.core.magic.bean.MagicInfo; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; + +import java.util.List; +import java.util.Locale; + +/** + * @author xiaoyu + */ + +public class MagicAdapter extends RecyclerView.Adapter { + + private List magicInfos; + private Context context; + private int index; + + public MagicInfo getCurrentMagicInfo() { + if (ListUtils.isListEmpty(magicInfos) || + index >= magicInfos.size()) + return null; + else + return magicInfos.get(index); + } + + public List getData() { + return magicInfos; + } + + public void setIndex(int index) { + this.index = index; + } + + public MagicAdapter(Context context, List magicInfos) { + this.magicInfos = magicInfos; + this.context = context; + } + + @Override + public int getItemViewType(int position) { + return magicInfos.get(position).getMagicType(); + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + int layoutResId; + switch (viewType) { + case MagicInfo.MONSTER_MAGIC: + layoutResId = R.layout.list_item_monster_magic; + break; + + default: + case MagicInfo.ROOM_MAGIC: + layoutResId = R.layout.list_item_magic; + break; + } + View root = LayoutInflater.from(context).inflate(layoutResId, parent, false); + return new MagicViewHolder(root, viewType); + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) { + if (viewHolder instanceof MagicViewHolder) { + ((MagicViewHolder) viewHolder).bind(position); + } + } + + @Override + public long getItemId(int position) { + return 0; + } + + @Override + public int getItemCount() { + return magicInfos == null ? 0 : magicInfos.size(); + } + + class MagicViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { + private ImageView ivMagicIcon; + private TextView tvMagicName; + private TextView tvMagicGold; + private MagicInfo mMagicInfo; + private TextView damageValue; + private View viewSelect; + + MagicViewHolder(View itemView, int viewType) { + super(itemView); + ivMagicIcon = itemView.findViewById(R.id.iv_magic_icon); + tvMagicName = itemView.findViewById(R.id.tv_magic_name); + tvMagicGold = itemView.findViewById(R.id.tv_magic_gold); + if (viewType == MagicInfo.MONSTER_MAGIC) { + damageValue = itemView.findViewById(R.id.tv_magic_damage); + } + itemView.setOnClickListener(this); + viewSelect = itemView.findViewById(R.id.view_room_gift_select); + } + + @Override + public void onClick(View v) { + if (mOnItemClickListener != null) { + mOnItemClickListener.onItemClick(v, position); + } + index = position; + notifyDataSetChanged(); + } + + int position; + + public void bind(int position) { + this.position = position; + mMagicInfo = magicInfos.get(position); + // 魔法icon + GlideApp.with(ivMagicIcon.getContext().getApplicationContext()) + .load(mMagicInfo.getIcon()) + .into(ivMagicIcon); + // 魔法名字 + tvMagicName.setText(mMagicInfo.getName()); + // 魔法钻石 + String gold = mMagicInfo.getPrice() + ResUtil.getString(R.string.avroom_widget_messageview_027); + if (mMagicInfo.getMagicType() == MagicInfo.MONSTER_MAGIC) { + gold = String.format(Locale.getDefault(), + context.getString(R.string.format_monster_hunting_magic_value), + String.valueOf(mMagicInfo.getPrice())); + damageValue.setText(String.format(Locale.getDefault(), + context.getString(R.string.format_monster_hunting_impact), + mMagicInfo.getImpactValue())); + } + tvMagicGold.setText(gold); + viewSelect.setSelected(position == index); + } + } + + private OnItemClickListener mOnItemClickListener; + + public void setOnItemClickListener(OnItemClickListener listener) { + mOnItemClickListener = listener; + } + + public interface OnItemClickListener { + void onItemClick(View view, int position); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/MagicRecyclerView.java b/app/src/main/java/com/chwl/app/ui/widget/MagicRecyclerView.java new file mode 100644 index 0000000..b4c862e --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/MagicRecyclerView.java @@ -0,0 +1,73 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; + +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.RecyclerView; + +/** + * @author xiaoyu + * @date 2017/12/12 + */ + +public class MagicRecyclerView extends RecyclerView { + private static final String TAG = "gift"; + + public MagicRecyclerView(Context context) { + super(context); + } + + public MagicRecyclerView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + public MagicRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + private float mLastY; + private float mStartY; + private boolean allowIntercept = true; + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { +// int pos = ((GridLayoutManager) getLayoutManager()).findFirstVisibleItemPosition(); +// switch (ev.getActionMasked()) { +// case MotionEvent.ACTION_DOWN: +// // down事件首先阻断父控件的拦截 +// getParent().requestDisallowInterceptTouchEvent(true); +// // 但是允许父控件后续的拦截 +// allowIntercept = true; +// mLastY = ev.getY(); +// mStartY = ev.getY(); +// break; +// case MotionEvent.ACTION_MOVE: +// LogUtil.e(TAG, "ACTION_MOVE"); +// float dy = ev.getY() - mLastY; +// float totalY = ev.getY() - mStartY; +// if (pos == 0 && getChildAt(0).getTop() == 0) { +// if (getChildAt(0).getTop() + dy < 0) { +// // 只要内部滑动一次,则往后都不允许父控件拦截 +// getParent().requestDisallowInterceptTouchEvent(true); +// allowIntercept = false; +// } +// if (allowIntercept && ViewConfiguration.get(getContext()).getScaledTouchSlop() < totalY) { +// getParent().requestDisallowInterceptTouchEvent(false); +// } +// } else { +// // 如果当前第一个完整显示的位置不是0,则允许内部滑动 +// allowIntercept = false; +// getParent().requestDisallowInterceptTouchEvent(true); +// } +// mLastY = ev.getY(); +// break; +// case MotionEvent.ACTION_UP: +// LogUtil.e(TAG, "ACTION_UP"); +// break; +// default: +// } + return super.dispatchTouchEvent(ev); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/MainRedPointTab.java b/app/src/main/java/com/chwl/app/ui/widget/MainRedPointTab.java new file mode 100644 index 0000000..7e0fc6a --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/MainRedPointTab.java @@ -0,0 +1,160 @@ +package com.chwl.app.ui.widget; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.util.AttributeSet; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.bumptech.glide.load.resource.bitmap.CenterCrop; +import com.netease.nim.uikit.common.ui.draggablebubbles.BubbleView; +import com.netease.nim.uikit.support.glide.GlideApp; +import com.opensource.svgaplayer.SVGADrawable; +import com.opensource.svgaplayer.SVGAImageView; +import com.opensource.svgaplayer.SVGAParser; +import com.opensource.svgaplayer.SVGAVideoEntity; +import com.chwl.app.R; +import com.chwl.app.common.svga.SimpleSvgaCallback; +import com.chwl.core.home.bean.MainTabInfo; +import com.chwl.core.home.bean.MainTabType; +import com.chwl.core.utils.CheckUtils; +import com.chwl.core.utils.CoreTextUtils; + +import java.net.MalformedURLException; +import java.net.URL; + +/** + *

main tab 有消息个数 控件 + *

+ * Created by Administrator on 2017/11/14. + */ +public class MainRedPointTab extends RelativeLayout { + private final SVGAImageView ivTabIcon; + private final TextView tvTabName; + private final TextView mTvNum; + private MainTabInfo tabInfo; + private boolean isSelected = false; + + public MainRedPointTab(@NonNull Context context) { + this(context, null); + } + + public MainRedPointTab(@NonNull Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public MainRedPointTab(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + inflate(context, R.layout.maint_tab_red_poin_layout, this); + ivTabIcon = findViewById(R.id.iv_tab_icon); + tvTabName = findViewById(R.id.tv_tab_name); + mTvNum = findViewById(R.id.msg_number); + ivTabIcon.setCallback(new SimpleSvgaCallback() { + @Override + public void onFinished() { + updateIcon(); + } + }); + } + + public void setMainTabInfo(@NonNull MainTabInfo tabInfo) { + this.tabInfo = tabInfo; + tvTabName.setText(tabInfo.getTabName()); + select(isSelected); + } + + public MainTabInfo getTabInfo() { + return tabInfo; + } + + public void select(boolean select) { + if (tabInfo == null) return; + tvTabName.setSelected(select); + isSelected = select; + if (!CoreTextUtils.isEmptyText(tabInfo.getTabSelectedAnimation()) && select) { + URL url = null; + try { + url = new URL(tabInfo.getTabSelectedAnimation()); + } catch (MalformedURLException e) { + updateIcon(); + } + if (url == null) { + updateIcon(); + } else { + SVGAParser.Companion.shareParser() + .decodeFromURL( + url, + new SVGAParser.ParseCompletion() { + @Override + public void onComplete(@NonNull SVGAVideoEntity svgaVideoEntity) { + SVGADrawable drawable = new SVGADrawable(svgaVideoEntity); + ivTabIcon.setLoops(1); + ivTabIcon.setImageDrawable(drawable); + ivTabIcon.startAnimation(); + } + + @Override + public void onError() { + updateIcon(); + } + }, list -> { + + }); + } + } else { + updateIcon(); + } + + } + + private void updateIcon() { + if (tabInfo == null) return; + ivTabIcon.stopAnimation(); + int defaultRes = getDefaultRes(tabInfo.getTabType(), isSelected); + GlideApp.with(ivTabIcon).load(isSelected ? tabInfo.getTabSelectedIcon() : tabInfo.getTabIcon()) + .dontAnimate() + .placeholder(defaultRes) + .error(defaultRes) + .transform(new CenterCrop()) + .into(ivTabIcon); + } + + @SuppressLint("SetTextI18n") + public void setNumber(int number) { + if (mTvNum instanceof BubbleView) { + ((BubbleView) mTvNum).setNumText(number); + } else { + if (number > 99) { + mTvNum.setText("99+"); + } else + mTvNum.setText(String.valueOf(number)); + } + + mTvNum.setVisibility((CheckUtils.isCheckUser() || number <= 0) ? GONE : VISIBLE); + } + + private int getDefaultRes(int tabType, boolean select) { + int resId = select ? R.drawable.ic_main_tab_home_pressed : R.drawable.ic_main_tab_home; + switch (tabType) { + case MainTabType.TAB_TYPE_SQUARE: + resId = select ? R.drawable.ic_main_tab_square_pressed : R.drawable.ic_main_tab_square; + break; + case MainTabType.TAB_TYPE_GAME: + resId = select ? R.drawable.ic_main_tab_game_pressed : R.drawable.ic_main_tab_game; + break; + case MainTabType.TAB_TYPE_MSG: + resId = select ? R.drawable.ic_main_tab_msg_pressed : R.drawable.ic_main_tab_msg; + break; + case MainTabType.TAB_TYPE_ME: + resId = select ? R.drawable.ic_main_tab_me_pressed : R.drawable.ic_main_tab_me; + break; + default: + break; + } + return resId; + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/MainTab.java b/app/src/main/java/com/chwl/app/ui/widget/MainTab.java new file mode 100644 index 0000000..e717e41 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/MainTab.java @@ -0,0 +1,97 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.view.Gravity; + +import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; + +import com.netease.nim.uikit.common.util.sys.ScreenUtil; +import com.chwl.app.R; + +/** + *

main tab 控件

+ * Created by Administrator on 2017/11/14. + */ +public class MainTab extends androidx.appcompat.widget.AppCompatTextView { + private static final int DEFAULT_COLOR = Color.parseColor("#333333"); + private int mTabIcon, mTabIconSelect; + private int mTabtextColor, mTabTextSelectColor; + private String mTabText; + private Context mContext; + + public MainTab(Context context) { + this(context, null); + } + + public MainTab(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public MainTab(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context, attrs, defStyleAttr); + } + + private void init(Context context, AttributeSet attrs, int defStyleAttr) { + mContext = context; + setGravity(Gravity.CENTER); + setCompoundDrawablePadding(ScreenUtil.dip2px(0)); + + TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MainTab); + mTabIcon = typedArray.getResourceId(R.styleable.MainTab_tab_icon, R.drawable.ic_main_tab_home); + mTabIconSelect = typedArray.getResourceId(R.styleable.MainTab_tab_icon_select, R.drawable.ic_main_tab_home_pressed); + + mTabtextColor = typedArray.getColor(R.styleable.MainTab_tab_text_color, DEFAULT_COLOR); + mTabTextSelectColor = typedArray.getColor(R.styleable.MainTab_tab_text_color_select, DEFAULT_COLOR); + mTabText = typedArray.getString(R.styleable.MainTab_tab_text); + typedArray.recycle(); + + select(false); + setText(mTabText); + } + + public void setIcon(int iconResId) { + Drawable mainTabHome = ContextCompat.getDrawable(mContext, iconResId); + + //必须加上这句,否则不显示 + mainTabHome.setBounds(0, 0, mainTabHome.getMinimumWidth(), mainTabHome.getIntrinsicHeight()); + setCompoundDrawables(null, mainTabHome, null, null); + } + + public void setmTabIcon(int tabIcon) { + mTabIcon = tabIcon; + } + + public void setmTabIconSelect(int tabIconSelect) { + mTabIconSelect = tabIconSelect; + } + + public void select(boolean select) { + setTextColor(select ? mTabTextSelectColor : mTabtextColor); + stopAnim(); + if (!select) { + setIcon(mTabIcon); + } else { + setIcon(mTabIconSelect); + } + } + + public void setAnimIcon(int anmiResId) { +// setCompoundDrawablesWithIntrinsicBounds(0, anmiResId, 0, 0); +// setCompoundDrawablesWithIntrinsicBounds(null, animationDrawable, null, null); +// if (animationDrawable != null) { +// animationDrawable.start(); +// } + } + + public void stopAnim() { +// if (animationDrawable != null) { +// animationDrawable.stop(); +// } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/MainTabLayout.java b/app/src/main/java/com/chwl/app/ui/widget/MainTabLayout.java new file mode 100644 index 0000000..b6ca23c --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/MainTabLayout.java @@ -0,0 +1,175 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.widget.LinearLayout; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.Size; + +import com.chwl.app.R; +import com.chwl.core.home.bean.MainTabInfo; +import com.chwl.core.home.bean.MainTabType; +import com.chwl.library.utils.ListUtils; + +import java.util.ArrayList; +import java.util.List; + +/** + *

底部tab导航

+ * Created by Administrator on 2017/11/14. + */ +public class MainTabLayout extends LinearLayout implements View.OnClickListener { + + private final List tabViewList = new ArrayList<>(4); + private MainRedPointTab homeTab; + private MainRedPointTab squareTab; + private MainRedPointTab gameTab; + private MainRedPointTab msgTab; + private MainRedPointTab meTab; + private int mLastPosition = -1; + private OnTabClickListener mOnTabClickListener; + @Nullable + private List mainTabInfoList; + private int defaultTabType; + + private int msgNumber; + private int meNumber; + private int squareNumber; + + public MainTabLayout(Context context) { + this(context, null); + } + + public MainTabLayout(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public MainTabLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context); + } + + private void init(Context context) { + setOrientation(HORIZONTAL); + inflate(context, R.layout.main_tab_layout, this); + + msgTab = findViewById(R.id.main_msg_tab); + squareTab = findViewById(R.id.main_square_tab); + gameTab = findViewById(R.id.main_game_tab); + homeTab = findViewById(R.id.main_home_tab); + meTab = findViewById(R.id.main_me_tab); + + homeTab.setOnClickListener(this); + meTab.setOnClickListener(this); + squareTab.setOnClickListener(this); + gameTab.setOnClickListener(this); + msgTab.setOnClickListener(this); + + tabViewList.add(homeTab); + tabViewList.add(gameTab); + tabViewList.add(squareTab); + tabViewList.add(msgTab); + tabViewList.add(meTab); + + } + + public void setMainTabInfoList(@NonNull @Size(4) List mainTabInfoList) { + this.mainTabInfoList = mainTabInfoList; + for (int i = 0; i < mainTabInfoList.size(); i++) { + MainTabInfo mainTabInfo = mainTabInfoList.get(i); + MainRedPointTab redPointTab = tabViewList.get(i); + redPointTab.setMainTabInfo(mainTabInfo); + switch (mainTabInfo.getTabType()) { + case MainTabType.TAB_TYPE_MSG: + redPointTab.setNumber(msgNumber); + break; + case MainTabType.TAB_TYPE_ME: + redPointTab.setNumber(meNumber); + break; + } + } + if (mLastPosition == -1) { + select(defaultTabType); + } + } + + public void setDefaultTabType(int defaultTabType) { + this.defaultTabType = defaultTabType; + } + + @Override + public void onClick(View v) { + if (ListUtils.isListEmpty(mainTabInfoList)) return; + switch (v.getId()) { + case R.id.main_home_tab: + select(MainTabType.TAB_TYPE_HOME); + break; + case R.id.main_square_tab: + select(MainTabType.TAB_TYPE_SQUARE); + break; + case R.id.main_game_tab: + select(MainTabType.TAB_TYPE_GAME); + break; + case R.id.main_msg_tab: + select(MainTabType.TAB_TYPE_MSG); + break; + case R.id.main_me_tab: + select(MainTabType.TAB_TYPE_ME); + break; + } + } + + private void select(int tabType) { + if (tabType == 0) tabType = MainTabType.TAB_TYPE_HOME; + if (mLastPosition == tabType) return; + msgTab.select(tabType == MainTabType.TAB_TYPE_MSG); + squareTab.select(tabType == MainTabType.TAB_TYPE_SQUARE); + gameTab.select(tabType == MainTabType.TAB_TYPE_GAME); + homeTab.select(tabType == MainTabType.TAB_TYPE_HOME); + meTab.select(tabType == MainTabType.TAB_TYPE_ME); + if (mOnTabClickListener != null) { + mOnTabClickListener.onTabClick(tabType); + } + mLastPosition = tabType; + } + + public void setMsgNum(int number) { + msgNumber = number; + MainRedPointTab pointTab = findTabInfoByType(MainTabType.TAB_TYPE_MSG); + if (pointTab != null) { + pointTab.setNumber(number); + } + } + + public void setUnreadVisitorCount(int count) { + meNumber = count; + MainRedPointTab pointTab = findTabInfoByType(MainTabType.TAB_TYPE_ME); + if (pointTab != null) { + //pointTab.setNumber(count); + } + } + + @Nullable + private MainRedPointTab findTabInfoByType(int tabType) { + if (mainTabInfoList == null) return null; + for (MainRedPointTab tabViewList : tabViewList) { + if (tabViewList.getTabInfo() != null && tabViewList.getTabInfo().getTabType() == tabType) { + return tabViewList; + } + } + return null; + } + + public void setOnTabClickListener(OnTabClickListener onTabClickListener) { + mOnTabClickListener = onTabClickListener; + } + + + public interface OnTabClickListener { + void onTabClick(int tabType); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/MarqueeLayout.java b/app/src/main/java/com/chwl/app/ui/widget/MarqueeLayout.java new file mode 100644 index 0000000..b8078d0 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/MarqueeLayout.java @@ -0,0 +1,119 @@ +package com.chwl.app.ui.widget; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.content.Context; +import android.text.TextPaint; +import android.util.AttributeSet; +import android.view.animation.LinearInterpolator; +import android.widget.HorizontalScrollView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.chwl.app.R; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.ScreenUtils; +import com.chwl.library.utils.log.MLog; + +/** + * @author xxf-kaede + * @date 2015/1/7 + */ +public class MarqueeLayout extends HorizontalScrollView { + + private TextView mGlobalNoticeContent; + private AnimatorSet animatorSet; + + private int mScreenWidth; + private Context mContext; + + public MarqueeLayout(@NonNull Context context) { + this(context, null); + } + + public MarqueeLayout(@NonNull Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public MarqueeLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + mContext = context; + inflate(context, R.layout.global_broadcast_notice_layout, this); + setHorizontalScrollBarEnabled(false); + mGlobalNoticeContent = findViewById(R.id.tv_global_notice_content); + + mScreenWidth = ScreenUtils.getScreenWidth(context); + } + + + public void setText(CharSequence content) { + mGlobalNoticeContent.setText(content); + } + + /** + * 使用MarqueeLayout后,一定要在界面销毁的时候调用reserverAnimation() + * 不然可能导致内存泄露 + */ + public void startMarquee() { + MLog.debug(this, "[liao] startMarquee"); + reserverAnimation(); + + if (mGlobalNoticeContent != null) { + TextPaint paint = mGlobalNoticeContent.getPaint(); + float len = paint.measureText(mGlobalNoticeContent.getText().toString()); + + + MLog.debug(this, ResUtil.getString(R.string.ui_widget_marqueelayout_01) + len); + + animatorSet = new AnimatorSet(); + ObjectAnimator inAnimator = ObjectAnimator.ofFloat(mGlobalNoticeContent, + "translationX", mScreenWidth, -mScreenWidth - len); + inAnimator.setDuration((long) (len * 0.1) * 100); + inAnimator.setInterpolator(new LinearInterpolator()); + + + animatorSet.playSequentially(inAnimator); + + animatorSet.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + if (mOnAnimatorListener != null) + mOnAnimatorListener.onAnimationEnd(animation); + } + }); + animatorSet.start(); + } + } + + //清除属性动画 + public void reserverAnimation() { + MLog.debug(this, "[liao] reserverAnimation"); + if (animatorSet != null) { + if (animatorSet.isRunning()) { + animatorSet.cancel(); + } + animatorSet = null; + } + } + + @Override + protected void onDetachedFromWindow() { + reserverAnimation(); + super.onDetachedFromWindow(); + } + + private OnAnimatorListener mOnAnimatorListener; + + public void setOnAnimatorListener(OnAnimatorListener onAnimatorListener) { + mOnAnimatorListener = onAnimatorListener; + } + + public interface OnAnimatorListener { + void onAnimationEnd(Animator animation); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/MarqueeTextView.kt b/app/src/main/java/com/chwl/app/ui/widget/MarqueeTextView.kt new file mode 100644 index 0000000..a226d3c --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/MarqueeTextView.kt @@ -0,0 +1,414 @@ +package com.chwl.app.ui.widget + +import android.content.Context +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.os.Handler +import android.os.Looper +import android.os.Message +import android.text.TextPaint +import android.util.AttributeSet +import android.view.View +import androidx.annotation.ColorInt +import androidx.annotation.FloatRange +import androidx.annotation.Px +import com.chwl.app.R +import java.lang.ref.WeakReference +import kotlin.math.abs +import kotlin.math.ceil + +/** + * 文本横向滚动,跑马灯效果 + * - 设置的内容不要太长,建议不要超过 [String] 最大长度的 1/5 + * @author JianXin + * @date 2021-07-22 11:59 + */ +open class MarqueeTextView @JvmOverloads constructor( + context: Context?, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : View(context, attrs, defStyleAttr) { + + companion object { + const val TAG = "MarqueeTextView" + const val BLANK = " " + const val REPEAT_SINGLE = 1 //一次结束 + const val REPEAT_SINGLE_LOOP = 0 //单个循序 + const val REPEAT_FILL_LOOP = -1 // 填充后循环 + } + + /*** + * 滚动速度 + */ + var speed = 1f + set(value) { + if (value <= 0) { + field = 0f + stop() + } else { + field = value + } + } + + /** + * 文本内容 + */ + var text = "" + set(value) { + if (field.isEmpty() && value.isEmpty()) { + return + } + field = value + var targetContent = value + if (isResetLocation) { //控制重新设置文本内容的时候,是否初始化xLocation。 + xLocation = width * startLocationDistance + } + val itemEndBlank = getItemEndBlank() + if (!targetContent.endsWith(itemEndBlank)) { + targetContent += itemEndBlank //避免没有后缀, 补充空格位 + } + //计算宽度,根据模式来 + if (repeat == REPEAT_FILL_LOOP) { + mFinalDrawText = "" + //计算文本的宽度 + mSingleContentWidth = getTextWidth(targetContent) + if (mSingleContentWidth > 0) { + // 最大可见内容项数 + val maxVisibleCount = ceil(width / mSingleContentWidth.toDouble()).toInt() + 1 + repeat(maxVisibleCount) { + mFinalDrawText += targetContent + } + } + contentWidth = getTextWidth(mFinalDrawText) + } else { + if (xLocation < 0 && repeat == REPEAT_SINGLE) { + if (abs(xLocation) > contentWidth) { + xLocation = width * startLocationDistance + } + } + mFinalDrawText = targetContent + contentWidth = getTextWidth(mFinalDrawText) + mSingleContentWidth = contentWidth + } + textHeight = getTextHeight() + invalidate() + } + + /** + * 最终绘制显示的文本 + */ + private var mFinalDrawText: String = "" + + /** + * 文字颜色 + */ + @ColorInt + var textColor = Color.BLACK + set(value) { + if (value != field) { + field = value + textPaint.color = textColor + invalidate() + } + } + + /** + * 字体大小 + */ + @Px + var textSize = 12f + set(value) { + if (value > 0 && value != field) { + field = value + textPaint.textSize = value + if (text.isNotEmpty()) { + text = text + } + } + } + + /**item间距,*/ + @Px + var textItemDistance = 50f + set(value) { + if (field == value) { + return + } + field = if (value < 0f) 0f else value + if (text.isNotEmpty()) { + text = text + } + } + + /** + * 滚动模式 + */ + var repeat = REPEAT_SINGLE_LOOP + set(value) { + if (value != field) { + field = value + resetInit = true + text = text + } + } + + /** + * 开始的位置距离左边,0~1,0:最左边,1:最右边,0.5:中间。 + */ + @FloatRange(from = 0.0, to = 1.0) + var startLocationDistance = 0.0f + set(value) { + if (value == field) { + return + } + field = when { + value < 0f -> 0f + value > 1f -> 1f + else -> value + } + } + + /** + * 是否重置文本绘制的位置,默认为true + */ + var isResetLocation = true + private var xLocation = 0f //文本的x坐标 + + /** + * 单个显示内容的宽度 + */ + private var mSingleContentWidth: Float = 0f + + /**内容的宽度*/ + private var contentWidth = 0f + + /**是否继续滚动*/ + var isRolling = false + private set + + /**画笔*/ + protected val textPaint: TextPaint = TextPaint(Paint.ANTI_ALIAS_FLAG) + + private var textHeight = 0f + private var resetInit = true + + private val mHandler by lazy { MyHandler(this) } + + /** + * 是否用户主动调用,默认 true + */ + protected var isRollByUser = true + + init { + initAttrs(attrs) + initPaint() + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + if (resetInit && text.isNotEmpty()) { + textItemDistance = textItemDistance + xLocation = width * startLocationDistance + resetInit = false + } + val absLocation = abs(xLocation) + when (repeat) { + REPEAT_SINGLE -> if (contentWidth < absLocation) { + stop() + } + REPEAT_SINGLE_LOOP -> if (contentWidth <= absLocation) { + //一轮结束 + xLocation = width.toFloat() + } + REPEAT_FILL_LOOP -> if (xLocation < 0 && mSingleContentWidth <= absLocation) { + xLocation = mSingleContentWidth - absLocation + } + else -> + if (contentWidth < absLocation) { + //也就是说文字已经到头了 + stop() + } + } + //绘制文本 + if (mFinalDrawText.isNotBlank()) { + canvas.drawText( + mFinalDrawText, + if (mSingleContentWidth > width) xLocation else 0f, + height / 2 + textHeight / 2, + textPaint + ) + } + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + if (!isRollByUser) { + startInternal(true) + } + } + + override fun onDetachedFromWindow() { + if (isRolling) { + stopInternal(false) + } + super.onDetachedFromWindow() + } + + override fun setVisibility(visibility: Int) { + super.setVisibility(visibility) + if (visibility != VISIBLE) { + stopInternal(false) + } else { + if (!isRollByUser) { + startInternal(false) + } + } + } + + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + text = text + } + + private fun initAttrs(attrs: AttributeSet?) { + val a = context.obtainStyledAttributes(attrs, R.styleable.MarqueeTextView) + textColor = a.getColor(R.styleable.MarqueeTextView_android_textColor, textColor) + isResetLocation = a.getBoolean(R.styleable.MarqueeTextView_marqueeResetLocation, true) + speed = a.getFloat(R.styleable.MarqueeTextView_marqueeSpeed, 1f) + textSize = a.getDimension(R.styleable.MarqueeTextView_android_textSize, 12f) + textItemDistance = a.getDimension(R.styleable.MarqueeTextView_marqueeItemDistance, 50f) + startLocationDistance = a.getFloat( + R.styleable.MarqueeTextView_marqueeStartLocationDistance, + 0f + ) + repeat = a.getInt(R.styleable.MarqueeTextView_marqueeRepeat, REPEAT_SINGLE_LOOP) + text = a.getText(R.styleable.MarqueeTextView_android_text)?.toString() ?: "" + a.recycle() + } + + /** + * 刻字机修改 + */ + private fun initPaint() { + textPaint.apply { + style = Paint.Style.FILL + color = textColor + textSize = textSize + isAntiAlias = true + density = 1 / resources.displayMetrics.density + } + } + + /** + * 切换开始暂停 + */ + fun toggle() { + if (isRolling) { + stop() + } else { + start() + } + } + + /** + * 继续滚动 + */ + fun start() { + startInternal(true) + } + + /** + * [isRollByUser] 是否用户主动调用 + */ + protected fun startInternal(isRollByUser: Boolean) { + this.isRollByUser = isRollByUser + stop() + if (text.isNotBlank()) { + mHandler.sendEmptyMessage(MyHandler.WHAT_RUN) + isRolling = true + } + } + + /** + * 停止滚动 + */ + fun stop() { + stopInternal(true) + } + + /** + * [isRollByUser] 是否用户主动调用 + */ + protected fun stopInternal(isRollByUser: Boolean) { + this.isRollByUser = isRollByUser + isRolling = false + mHandler.removeMessages(MyHandler.WHAT_RUN) + } + + /** + * 计算出一个空格的宽度 + * @return + */ + private fun getBlankWidth(): Float { + return getTextWidth(BLANK) + } + + private fun getTextWidth(text: String?): Float { + if (text.isNullOrEmpty()) { + return 0f + } + return textPaint.measureText(text) + } + + /** + * 文本高度 + */ + private fun getTextHeight(): Float { + val fontMetrics = textPaint.fontMetrics + return abs(fontMetrics.bottom - fontMetrics.top) / 2 + } + + private fun getItemEndBlank(): String { + val oneBlankWidth = getBlankWidth() //空格的宽度 + var count = 1 + if (textItemDistance > 0 && oneBlankWidth != 0f) { + count = (ceil(textItemDistance / oneBlankWidth).toInt()) //粗略计算空格数量 + } + val builder = StringBuilder(count) + for (i in 0..count) { + builder.append(BLANK)//间隔字符串 + } + return builder.toString() + } + + /** + * handler + * + * @author JianXin + * @date 2021-07-22 11:43 + */ + private class MyHandler(view: MarqueeTextView) : Handler(Looper.getMainLooper()) { + + companion object { + internal const val WHAT_RUN = 1001 + } + + private val mRef = WeakReference(view) + + override fun handleMessage(msg: Message) { + super.handleMessage(msg) + if (msg.what == WHAT_RUN) { + mRef.get()?.apply { + if (speed > 0) { + xLocation -= speed + invalidate() + // 16 毫秒绘制一次 + sendEmptyMessageDelayed(WHAT_RUN, 16) + } + } + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/widget/MicSelectDialog.kt b/app/src/main/java/com/chwl/app/ui/widget/MicSelectDialog.kt new file mode 100644 index 0000000..5a30a18 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/MicSelectDialog.kt @@ -0,0 +1,157 @@ +package com.chwl.app.ui.widget + +import android.view.Gravity +import android.view.WindowManager +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.chwl.app.R +import com.chwl.app.avroom.adapter.UpMicAdapter +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.databinding.DialogMicSelectBinding +import com.chwl.core.auth.AuthModel +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.manager.IMNetEaseManager +import com.chwl.core.room.bean.RoomInfo +import com.chwl.core.room.giftvalue.helper.GiftValueMrg +import com.chwl.core.room.model.HomePartyModel +import com.chwl.core.user.bean.BaseInfo +import com.chwl.core.user.bean.UserInfo +import com.chwl.library.common.util.ClickUtils.click +import com.chwl.library.common.util.doLog +import com.chwl.library.common.util.doToast +import com.chwl.library.net.rxnet.callback.CallBack +import com.chwl.library.utils.SingleToastUtil +import com.example.lib_utils.ktx.getString +import io.reactivex.functions.Consumer + +class MicSelectDialog : BaseDialogFragment() { + + + override var width = WindowManager.LayoutParams.MATCH_PARENT + override var height = WindowManager.LayoutParams.WRAP_CONTENT + override var dimAmount = 0f + override var gravity = Gravity.BOTTOM + + + private lateinit var mAdapter: UpMicAdapter + private val myUid = AuthModel.get().currentUid + private var isMySelf = false + + var targetUser = UserInfo() + var homePartyModel: HomePartyModel? = null + + var mPosition : Int? = null + + override fun init() { + + if (AvRoomDataManager.get().getChatRoomMember(targetUser.uid.toString()) == null) { + SingleToastUtil.showToast(R.string.tips_member_not_in_room.getString()) + dismiss() + } + isMySelf = targetUser.uid == myUid + + mAdapter = UpMicAdapter(context, targetUser.uid, + Consumer { position: Int -> + //xxx 上麦逻辑- 资料卡上麦 自己和别人 上麦 走这里 ! + val roomInfo = AvRoomDataManager.get().mCurrentRoomInfo ?: return@Consumer + mPosition = position + "上麦 micPosition = $position".doLog() + // 19麦房间的 boss ViewItemPos是7 , 云信上麦位是6 , 展示时是8号麦 + if (AvRoomDataManager.get().is19Room && AvRoomDataManager.get().is19RoomBoosItemPos(position) && !isMySelf) { + + "上麦 micPosition = $position 开始请求上麦接口".doLog() + homePartyModel?.getRoomBossMicUp(AvRoomDataManager.get().roomUid, targetUser.uid,true) + ?.compose(bindToLifecycle()) + ?.doOnSuccess { + "上麦 micPosition = $position 开始请求上麦接口结果: 成功".doLog() + upMicOther(roomInfo) + } + ?.doOnError { + "上麦 micPosition = $position 开始请求上麦接口结果: 失败".doLog() + it?.message?.doToast() + } + ?.subscribe() + } else { + if (isMySelf) { + uoMicMySelf(roomInfo) + } else { + upMicOther(roomInfo) + } + } + + }) + + val span = if (AvRoomDataManager.get().isHomeParty) 4 else 5 + val gridLayoutManager = GridLayoutManager(context, span, RecyclerView.VERTICAL, false) + binding.rvList.layoutManager = gridLayoutManager + binding.rvList.adapter = mAdapter + //xxx gridLayoutManager.spanSizeLookup 要在recycleView设置完Adapter 后设置, 才保险 + gridLayoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() { + override fun getSpanSize(position: Int): Int { + if (AvRoomDataManager.get().isHomeParty && position == 0) return gridLayoutManager.spanCount + return 1 + } + } + + binding.confirm.click { + + dismiss() + } + } + + //别人上麦 + private fun upMicOther(roomInfo: RoomInfo) : Boolean{ + mPosition?.let { + if (AvRoomDataManager.get().isLeaveMode && targetUser.uid == AvRoomDataManager.get().roomUid) { + SingleToastUtil.showToast(R.string.tips_close_leave_mode_first.getString()) + dismiss() + return false + } + + if (targetUser.defUser == UserInfo.USER_TYPE_ROBOT) { + SingleToastUtil.showToast(R.string.unable_to_up_mic_by_level.getString()) + return false + } + + val baseInfo = BaseInfo(targetUser.uid, targetUser.nick) + IMNetEaseManager.get().inviteMicroPhoneBySdk(baseInfo, it - 1).subscribe() + dismiss() + } + return true + } + + //自己上麦 + private fun uoMicMySelf(roomInfo: RoomInfo) :Boolean{ + mPosition?.let { + if (isMySelf) { + //自己抱自己上麦 + AvRoomDataManager.get().haveStartDragon = false + homePartyModel?.upMicroPhone( + it - 1, + targetUser.uid.toString(), + roomInfo.roomId.toString(), + true, + object : CallBack { + override fun onSuccess(data: String?) { + GiftValueMrg.get().requestUpMic(it - 1, targetUser.uid.toString()) + mActionCallBack?.onAction(0,null) //随便通知下外头 + } + + override fun onFail(code: Int, error: String?) { + + } + } + ) + dismiss() + return true + } + } + return true + } + + override fun onDestroy() { + homePartyModel = null + super.onDestroy() + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/MultipleGraduallyTextView.kt b/app/src/main/java/com/chwl/app/ui/widget/MultipleGraduallyTextView.kt new file mode 100644 index 0000000..2430644 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/MultipleGraduallyTextView.kt @@ -0,0 +1,61 @@ +package com.chwl.app.ui.widget + +import android.content.Context +import android.graphics.* +import android.util.AttributeSet +import androidx.appcompat.widget.AppCompatTextView +import com.chwl.app.R + +class MultipleGraduallyTextView(context: Context, attr: AttributeSet?, def: Int) : + AppCompatTextView(context, attr, def) { + private var paint: Paint = Paint(Paint.ANTI_ALIAS_FLAG) + private var beforeStartColor = 0 + private var startColor = 0 + private var afterStartColor = 0 + private var beforeEndColor = 0 + private var endColor = 0 + private var afterEndColor = 0 + + constructor(context: Context) : this(context, null) + constructor(context: Context, attr: AttributeSet?) : this(context, attr, 0) + + init { + val arr = context.obtainStyledAttributes(attr, R.styleable.MultipleGraduallyTextView) + beforeStartColor = + arr.getColor(R.styleable.MultipleGraduallyTextView_beforeStartColor, Color.TRANSPARENT) + startColor = + arr.getColor(R.styleable.MultipleGraduallyTextView_startColor, Color.TRANSPARENT) + afterStartColor = + arr.getColor(R.styleable.MultipleGraduallyTextView_afterStartColor, Color.TRANSPARENT) + beforeEndColor = + arr.getColor(R.styleable.MultipleGraduallyTextView_beforeEndColor, Color.TRANSPARENT) + endColor = + arr.getColor(R.styleable.MultipleGraduallyTextView_endColor, Color.TRANSPARENT) + afterEndColor = + arr.getColor(R.styleable.MultipleGraduallyTextView_afterEndColor, Color.TRANSPARENT) + paint.style = Paint.Style.FILL + val gradient = LinearGradient( + 0f, + 0f, + width.toFloat(), + height.toFloat(), + intArrayOf( + beforeStartColor, + startColor, + afterStartColor, + beforeEndColor, + endColor, + afterEndColor + ), + floatArrayOf(0f,0.2f,0.4f,0.6f,0.8f,1.0f), + Shader.TileMode.CLAMP + ) + paint.shader = gradient + arr.recycle() + } + + override fun onDraw(canvas: Canvas) { + canvas.drawRect(0f, 0f, width.toFloat(), height.toFloat(), paint) + super.onDraw(canvas) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/widget/MyItemAnimator.java b/app/src/main/java/com/chwl/app/ui/widget/MyItemAnimator.java new file mode 100644 index 0000000..1503104 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/MyItemAnimator.java @@ -0,0 +1,684 @@ +package com.chwl.app.ui.widget; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.TimeInterpolator; +import android.animation.ValueAnimator; +import android.view.View; +import android.view.ViewPropertyAnimator; + +import androidx.annotation.NonNull; +import androidx.core.view.ViewCompat; +import androidx.recyclerview.widget.RecyclerView.ViewHolder; +import androidx.recyclerview.widget.SimpleItemAnimator; + +import java.util.ArrayList; +import java.util.List; + +/** + * 重写DefualtItemAnimator, 防止 recyclerview 列表闪烁 + */ +public class MyItemAnimator extends SimpleItemAnimator { + private static final boolean DEBUG = false; + + private static TimeInterpolator sDefaultInterpolator; + + private ArrayList mPendingRemovals = new ArrayList<>(); + private ArrayList mPendingAdditions = new ArrayList<>(); + private ArrayList mPendingMoves = new ArrayList<>(); + private ArrayList mPendingChanges = new ArrayList<>(); + + ArrayList> mAdditionsList = new ArrayList<>(); + ArrayList> mMovesList = new ArrayList<>(); + ArrayList> mChangesList = new ArrayList<>(); + + ArrayList mAddAnimations = new ArrayList<>(); + ArrayList mMoveAnimations = new ArrayList<>(); + ArrayList mRemoveAnimations = new ArrayList<>(); + ArrayList mChangeAnimations = new ArrayList<>(); + + private static class MoveInfo { + public ViewHolder holder; + public int fromX, fromY, toX, toY; + + MoveInfo(ViewHolder holder, int fromX, int fromY, int toX, int toY) { + this.holder = holder; + this.fromX = fromX; + this.fromY = fromY; + this.toX = toX; + this.toY = toY; + } + } + + private static class ChangeInfo { + public ViewHolder oldHolder, newHolder; + public int fromX, fromY, toX, toY; + private ChangeInfo(ViewHolder oldHolder, ViewHolder newHolder) { + this.oldHolder = oldHolder; + this.newHolder = newHolder; + } + + ChangeInfo(ViewHolder oldHolder, ViewHolder newHolder, + int fromX, int fromY, int toX, int toY) { + this(oldHolder, newHolder); + this.fromX = fromX; + this.fromY = fromY; + this.toX = toX; + this.toY = toY; + } + + @Override + public String toString() { + return "ChangeInfo{" + + "oldHolder=" + oldHolder + + ", newHolder=" + newHolder + + ", fromX=" + fromX + + ", fromY=" + fromY + + ", toX=" + toX + + ", toY=" + toY + + '}'; + } + } + + @Override + public void runPendingAnimations() { + boolean removalsPending = !mPendingRemovals.isEmpty(); + boolean movesPending = !mPendingMoves.isEmpty(); + boolean changesPending = !mPendingChanges.isEmpty(); + boolean additionsPending = !mPendingAdditions.isEmpty(); + if (!removalsPending && !movesPending && !additionsPending && !changesPending) { + // nothing to animate + return; + } + // First, remove stuff + for (ViewHolder holder : mPendingRemovals) { + animateRemoveImpl(holder); + } + mPendingRemovals.clear(); + // Next, move stuff + if (movesPending) { + final ArrayList moves = new ArrayList<>(); + moves.addAll(mPendingMoves); + mMovesList.add(moves); + mPendingMoves.clear(); + Runnable mover = new Runnable() { + @Override + public void run() { + for (MoveInfo moveInfo : moves) { + animateMoveImpl(moveInfo.holder, moveInfo.fromX, moveInfo.fromY, + moveInfo.toX, moveInfo.toY); + } + moves.clear(); + mMovesList.remove(moves); + } + }; + if (removalsPending) { + View view = moves.get(0).holder.itemView; + ViewCompat.postOnAnimationDelayed(view, mover, getRemoveDuration()); + } else { + mover.run(); + } + } + // Next, change stuff, to run in parallel with move animations + if (changesPending) { + final ArrayList changes = new ArrayList<>(); + changes.addAll(mPendingChanges); + mChangesList.add(changes); + mPendingChanges.clear(); + Runnable changer = new Runnable() { + @Override + public void run() { + for (ChangeInfo change : changes) { + animateChangeImpl(change); + } + changes.clear(); + mChangesList.remove(changes); + } + }; + if (removalsPending) { + ViewHolder holder = changes.get(0).oldHolder; + ViewCompat.postOnAnimationDelayed(holder.itemView, changer, getRemoveDuration()); + } else { + changer.run(); + } + } + // Next, add stuff + if (additionsPending) { + final ArrayList additions = new ArrayList<>(); + additions.addAll(mPendingAdditions); + mAdditionsList.add(additions); + mPendingAdditions.clear(); + Runnable adder = new Runnable() { + @Override + public void run() { + for (ViewHolder holder : additions) { + animateAddImpl(holder); + } + additions.clear(); + mAdditionsList.remove(additions); + } + }; + if (removalsPending || movesPending || changesPending) { + long removeDuration = removalsPending ? getRemoveDuration() : 0; + long moveDuration = movesPending ? getMoveDuration() : 0; + long changeDuration = changesPending ? getChangeDuration() : 0; + long totalDelay = removeDuration + Math.max(moveDuration, changeDuration); + View view = additions.get(0).itemView; + ViewCompat.postOnAnimationDelayed(view, adder, totalDelay); + } else { + adder.run(); + } + } + } + + @Override + public boolean animateRemove(final ViewHolder holder) { + resetAnimation(holder); + mPendingRemovals.add(holder); + return true; + } + + private void animateRemoveImpl(final ViewHolder holder) { + final View view = holder.itemView; + final ViewPropertyAnimator animation = view.animate(); + mRemoveAnimations.add(holder); + animation.setDuration(getRemoveDuration()).alpha(0).setListener( + new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animator) { + dispatchRemoveStarting(holder); + } + + @Override + public void onAnimationEnd(Animator animator) { + animation.setListener(null); + view.setAlpha(1); + dispatchRemoveFinished(holder); + mRemoveAnimations.remove(holder); + dispatchFinishedWhenDone(); + } + }).start(); + } + + @Override + public boolean animateAdd(final ViewHolder holder) { + resetAnimation(holder); + holder.itemView.setAlpha(0); + mPendingAdditions.add(holder); + return true; + } + + void animateAddImpl(final ViewHolder holder) { + final View view = holder.itemView; + final ViewPropertyAnimator animation = view.animate(); + mAddAnimations.add(holder); + animation.alpha(1).setDuration(getAddDuration()) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animator) { + dispatchAddStarting(holder); + } + + @Override + public void onAnimationCancel(Animator animator) { + view.setAlpha(1); + } + + @Override + public void onAnimationEnd(Animator animator) { + animation.setListener(null); + dispatchAddFinished(holder); + mAddAnimations.remove(holder); + dispatchFinishedWhenDone(); + } + }).start(); + } + + @Override + public boolean animateMove(final ViewHolder holder, int fromX, int fromY, + int toX, int toY) { + final View view = holder.itemView; + fromX += (int) holder.itemView.getTranslationX(); + fromY += (int) holder.itemView.getTranslationY(); + resetAnimation(holder); + int deltaX = toX - fromX; + int deltaY = toY - fromY; + if (deltaX == 0 && deltaY == 0) { + dispatchMoveFinished(holder); + return false; + } + if (deltaX != 0) { + view.setTranslationX(-deltaX); + } + if (deltaY != 0) { + view.setTranslationY(-deltaY); + } + mPendingMoves.add(new MoveInfo(holder, fromX, fromY, toX, toY)); + return true; + } + + void animateMoveImpl(final ViewHolder holder, int fromX, int fromY, int toX, int toY) { + final View view = holder.itemView; + final int deltaX = toX - fromX; + final int deltaY = toY - fromY; + if (deltaX != 0) { + view.animate().translationX(0); + } + if (deltaY != 0) { + view.animate().translationY(0); + } + // TODO: make EndActions end listeners instead, since end actions aren't called when + // vpas are canceled (and can't end them. why?) + // need listener functionality in VPACompat for this. Ick. + final ViewPropertyAnimator animation = view.animate(); + mMoveAnimations.add(holder); + animation.setDuration(getMoveDuration()).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animator) { + dispatchMoveStarting(holder); + } + + @Override + public void onAnimationCancel(Animator animator) { + if (deltaX != 0) { + view.setTranslationX(0); + } + if (deltaY != 0) { + view.setTranslationY(0); + } + } + + @Override + public void onAnimationEnd(Animator animator) { + animation.setListener(null); + dispatchMoveFinished(holder); + mMoveAnimations.remove(holder); + dispatchFinishedWhenDone(); + } + }).start(); + } + + @Override + public boolean animateChange(ViewHolder oldHolder, ViewHolder newHolder, + int fromX, int fromY, int toX, int toY) { + if (oldHolder == newHolder) { + // Don't know how to run change animations when the same view holder is re-used. + // run a move animation to handle position changes. + return animateMove(oldHolder, fromX, fromY, toX, toY); + } + final float prevTranslationX = oldHolder.itemView.getTranslationX(); + final float prevTranslationY = oldHolder.itemView.getTranslationY(); + final float prevAlpha = oldHolder.itemView.getAlpha(); + resetAnimation(oldHolder); + int deltaX = (int) (toX - fromX - prevTranslationX); + int deltaY = (int) (toY - fromY - prevTranslationY); + // recover prev translation state after ending animation + oldHolder.itemView.setTranslationX(prevTranslationX); + oldHolder.itemView.setTranslationY(prevTranslationY); + oldHolder.itemView.setAlpha(prevAlpha); + if (newHolder != null) { + // carry over translation values + resetAnimation(newHolder); + newHolder.itemView.setTranslationX(-deltaX); + newHolder.itemView.setTranslationY(-deltaY); + newHolder.itemView.setAlpha(0); + } + mPendingChanges.add(new ChangeInfo(oldHolder, newHolder, fromX, fromY, toX, toY)); + return true; + } + + void animateChangeImpl(final ChangeInfo changeInfo) { + final ViewHolder holder = changeInfo.oldHolder; + final View view = holder == null ? null : holder.itemView; + final ViewHolder newHolder = changeInfo.newHolder; + final View newView = newHolder != null ? newHolder.itemView : null; + if (view != null) { + final ViewPropertyAnimator oldViewAnim = view.animate().setDuration( + getChangeDuration()); + mChangeAnimations.add(changeInfo.oldHolder); + oldViewAnim.translationX(changeInfo.toX - changeInfo.fromX); + oldViewAnim.translationY(changeInfo.toY - changeInfo.fromY); +// oldViewAnim.alpha(0).setListener(new AnimatorListenerAdapter() { +// @Override +// public void onAnimationStart(Animator animator) { +// dispatchChangeStarting(changeInfo.oldHolder, true); +// } +// +// @Override +// public void onAnimationEnd(Animator animator) { +// oldViewAnim.setListener(null); +// view.setAlpha(1); +// view.setTranslationX(0); +// view.setTranslationY(0); +// dispatchChangeFinished(changeInfo.oldHolder, true); +// mChangeAnimations.remove(changeInfo.oldHolder); +// dispatchFinishedWhenDone(); +// } +// }).start(); + oldViewAnim.setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animator) { + dispatchChangeStarting(changeInfo.oldHolder, true); + } + + @Override + public void onAnimationEnd(Animator animator) { + oldViewAnim.setListener(null); + view.setAlpha(1); + view.setTranslationX(0); + view.setTranslationY(0); + dispatchChangeFinished(changeInfo.oldHolder, true); + mChangeAnimations.remove(changeInfo.oldHolder); + dispatchFinishedWhenDone(); + } + }).start(); + } + if (newView != null) { + final ViewPropertyAnimator newViewAnimation = newView.animate(); + mChangeAnimations.add(changeInfo.newHolder); +// newViewAnimation.translationX(0).translationY(0).setDuration(getChangeDuration()) +// .alpha(1).setListener(new AnimatorListenerAdapter() { +// @Override +// public void onAnimationStart(Animator animator) { +// dispatchChangeStarting(changeInfo.newHolder, false); +// } +// @Override +// public void onAnimationEnd(Animator animator) { +// newViewAnimation.setListener(null); +// newView.setAlpha(1); +// newView.setTranslationX(0); +// newView.setTranslationY(0); +// dispatchChangeFinished(changeInfo.newHolder, false); +// mChangeAnimations.remove(changeInfo.newHolder); +// dispatchFinishedWhenDone(); +// } +// }).start(); + newViewAnimation.translationX(0).translationY(0).setDuration(getChangeDuration()) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animator) { + dispatchChangeStarting(changeInfo.newHolder, false); + } + @Override + public void onAnimationEnd(Animator animator) { + newViewAnimation.setListener(null); + newView.setAlpha(1); + newView.setTranslationX(0); + newView.setTranslationY(0); + dispatchChangeFinished(changeInfo.newHolder, false); + mChangeAnimations.remove(changeInfo.newHolder); + dispatchFinishedWhenDone(); + } + }).start(); + } + } + + private void endChangeAnimation(List infoList, ViewHolder item) { + for (int i = infoList.size() - 1; i >= 0; i--) { + ChangeInfo changeInfo = infoList.get(i); + if (endChangeAnimationIfNecessary(changeInfo, item)) { + if (changeInfo.oldHolder == null && changeInfo.newHolder == null) { + infoList.remove(changeInfo); + } + } + } + } + + private void endChangeAnimationIfNecessary(ChangeInfo changeInfo) { + if (changeInfo.oldHolder != null) { + endChangeAnimationIfNecessary(changeInfo, changeInfo.oldHolder); + } + if (changeInfo.newHolder != null) { + endChangeAnimationIfNecessary(changeInfo, changeInfo.newHolder); + } + } + private boolean endChangeAnimationIfNecessary(ChangeInfo changeInfo, ViewHolder item) { + boolean oldItem = false; + if (changeInfo.newHolder == item) { + changeInfo.newHolder = null; + } else if (changeInfo.oldHolder == item) { + changeInfo.oldHolder = null; + oldItem = true; + } else { + return false; + } + item.itemView.setAlpha(1); + item.itemView.setTranslationX(0); + item.itemView.setTranslationY(0); + dispatchChangeFinished(item, oldItem); + return true; + } + + @Override + public void endAnimation(ViewHolder item) { + final View view = item.itemView; + // this will trigger end callback which should set properties to their target values. + view.animate().cancel(); + // TODO if some other animations are chained to end, how do we cancel them as well? + for (int i = mPendingMoves.size() - 1; i >= 0; i--) { + MoveInfo moveInfo = mPendingMoves.get(i); + if (moveInfo.holder == item) { + view.setTranslationY(0); + view.setTranslationX(0); + dispatchMoveFinished(item); + mPendingMoves.remove(i); + } + } + endChangeAnimation(mPendingChanges, item); + if (mPendingRemovals.remove(item)) { + view.setAlpha(1); + dispatchRemoveFinished(item); + } + if (mPendingAdditions.remove(item)) { + view.setAlpha(1); + dispatchAddFinished(item); + } + + for (int i = mChangesList.size() - 1; i >= 0; i--) { + ArrayList changes = mChangesList.get(i); + endChangeAnimation(changes, item); + if (changes.isEmpty()) { + mChangesList.remove(i); + } + } + for (int i = mMovesList.size() - 1; i >= 0; i--) { + ArrayList moves = mMovesList.get(i); + for (int j = moves.size() - 1; j >= 0; j--) { + MoveInfo moveInfo = moves.get(j); + if (moveInfo.holder == item) { + view.setTranslationY(0); + view.setTranslationX(0); + dispatchMoveFinished(item); + moves.remove(j); + if (moves.isEmpty()) { + mMovesList.remove(i); + } + break; + } + } + } + for (int i = mAdditionsList.size() - 1; i >= 0; i--) { + ArrayList additions = mAdditionsList.get(i); + if (additions.remove(item)) { + view.setAlpha(1); + dispatchAddFinished(item); + if (additions.isEmpty()) { + mAdditionsList.remove(i); + } + } + } + + // animations should be ended by the cancel above. + //noinspection PointlessBooleanExpression,ConstantConditions + if (mRemoveAnimations.remove(item) && DEBUG) { + throw new IllegalStateException("after animation is cancelled, item should not be in " + + "mRemoveAnimations list"); + } + + //noinspection PointlessBooleanExpression,ConstantConditions + if (mAddAnimations.remove(item) && DEBUG) { + throw new IllegalStateException("after animation is cancelled, item should not be in " + + "mAddAnimations list"); + } + + //noinspection PointlessBooleanExpression,ConstantConditions + if (mChangeAnimations.remove(item) && DEBUG) { + throw new IllegalStateException("after animation is cancelled, item should not be in " + + "mChangeAnimations list"); + } + + //noinspection PointlessBooleanExpression,ConstantConditions + if (mMoveAnimations.remove(item) && DEBUG) { + throw new IllegalStateException("after animation is cancelled, item should not be in " + + "mMoveAnimations list"); + } + dispatchFinishedWhenDone(); + } + + private void resetAnimation(ViewHolder holder) { + if (sDefaultInterpolator == null) { + sDefaultInterpolator = new ValueAnimator().getInterpolator(); + } + holder.itemView.animate().setInterpolator(sDefaultInterpolator); + endAnimation(holder); + } + + @Override + public boolean isRunning() { + return (!mPendingAdditions.isEmpty() + || !mPendingChanges.isEmpty() + || !mPendingMoves.isEmpty() + || !mPendingRemovals.isEmpty() + || !mMoveAnimations.isEmpty() + || !mRemoveAnimations.isEmpty() + || !mAddAnimations.isEmpty() + || !mChangeAnimations.isEmpty() + || !mMovesList.isEmpty() + || !mAdditionsList.isEmpty() + || !mChangesList.isEmpty()); + } + + /** + * Check the state of currently pending and running animations. If there are none + * pending/running, call {@link #dispatchAnimationsFinished()} to notify any + * listeners. + */ + void dispatchFinishedWhenDone() { + if (!isRunning()) { + dispatchAnimationsFinished(); + } + } + + @Override + public void endAnimations() { + int count = mPendingMoves.size(); + for (int i = count - 1; i >= 0; i--) { + MoveInfo item = mPendingMoves.get(i); + View view = item.holder.itemView; + view.setTranslationY(0); + view.setTranslationX(0); + dispatchMoveFinished(item.holder); + mPendingMoves.remove(i); + } + count = mPendingRemovals.size(); + for (int i = count - 1; i >= 0; i--) { + ViewHolder item = mPendingRemovals.get(i); + dispatchRemoveFinished(item); + mPendingRemovals.remove(i); + } + count = mPendingAdditions.size(); + for (int i = count - 1; i >= 0; i--) { + ViewHolder item = mPendingAdditions.get(i); + item.itemView.setAlpha(1); + dispatchAddFinished(item); + mPendingAdditions.remove(i); + } + count = mPendingChanges.size(); + for (int i = count - 1; i >= 0; i--) { + endChangeAnimationIfNecessary(mPendingChanges.get(i)); + } + mPendingChanges.clear(); + if (!isRunning()) { + return; + } + + int listCount = mMovesList.size(); + for (int i = listCount - 1; i >= 0; i--) { + ArrayList moves = mMovesList.get(i); + count = moves.size(); + for (int j = count - 1; j >= 0; j--) { + MoveInfo moveInfo = moves.get(j); + ViewHolder item = moveInfo.holder; + View view = item.itemView; + view.setTranslationY(0); + view.setTranslationX(0); + dispatchMoveFinished(moveInfo.holder); + moves.remove(j); + if (moves.isEmpty()) { + mMovesList.remove(moves); + } + } + } + listCount = mAdditionsList.size(); + for (int i = listCount - 1; i >= 0; i--) { + ArrayList additions = mAdditionsList.get(i); + count = additions.size(); + for (int j = count - 1; j >= 0; j--) { + ViewHolder item = additions.get(j); + View view = item.itemView; + view.setAlpha(1); + dispatchAddFinished(item); + additions.remove(j); + if (additions.isEmpty()) { + mAdditionsList.remove(additions); + } + } + } + listCount = mChangesList.size(); + for (int i = listCount - 1; i >= 0; i--) { + ArrayList changes = mChangesList.get(i); + count = changes.size(); + for (int j = count - 1; j >= 0; j--) { + endChangeAnimationIfNecessary(changes.get(j)); + if (changes.isEmpty()) { + mChangesList.remove(changes); + } + } + } + + cancelAll(mRemoveAnimations); + cancelAll(mMoveAnimations); + cancelAll(mAddAnimations); + cancelAll(mChangeAnimations); + + dispatchAnimationsFinished(); + } + + void cancelAll(List viewHolders) { + for (int i = viewHolders.size() - 1; i >= 0; i--) { + viewHolders.get(i).itemView.animate().cancel(); + } + } + + /** + * {@inheritDoc} + *

+ * If the payload list is not empty, DefaultItemAnimator returns true. + * When this is the case: + *

    + *
  • If you override {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)}, both + * ViewHolder arguments will be the same instance. + *
  • + *
  • + * If you are not overriding {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)}, + * then DefaultItemAnimator will call {@link #animateMove(ViewHolder, int, int, int, int)} and + * run a move animation instead. + *
  • + *
+ */ + @Override + public boolean canReuseUpdatedViewHolder(@NonNull ViewHolder viewHolder, + @NonNull List payloads) { + return !payloads.isEmpty() || super.canReuseUpdatedViewHolder(viewHolder, payloads); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/NobleAvatarView.java b/app/src/main/java/com/chwl/app/ui/widget/NobleAvatarView.java new file mode 100644 index 0000000..2b1208e --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/NobleAvatarView.java @@ -0,0 +1,118 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.widget.ImageView; +import android.widget.RelativeLayout; + +import androidx.annotation.Nullable; + +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMember; +import com.chwl.app.R; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.noble.bean.NobleInfo; +import com.chwl.core.noble.NobleResourceType; +import com.chwl.core.noble.NobleUtil; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.library.utils.SizeUtils; + +/** + *

贵族头像

+ * + * @author jiahui + * @date 2018/1/16 + */ +public class NobleAvatarView extends RelativeLayout { + + private ImageView mIvAvatar; + private ImageView mIvAvatarHeadWear; + private ImageView mIvUserLevel; + private Context mContext; + + public NobleAvatarView(Context context) { + this(context, null); + } + + public NobleAvatarView(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public NobleAvatarView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + mContext = context; + inflate(context, R.layout.noble_avatar_layout, this); + mIvAvatar = findViewById(R.id.iv_avatar); + mIvAvatarHeadWear = findViewById(R.id.iv_avatar_head_wear); + mIvUserLevel = findViewById(R.id.iv_user_noble_level); + } + + /** + * 设置自定义大小,单位dp + * + * @param avatarSize 头像大小 + * @param avatarHeadWearSize 头饰大小 + * @param userLevelSize 贵族级别图标大小 + */ + public void setSize(float avatarSize, float avatarHeadWearSize, float userLevelSize) { + int avatarSizeDp = SizeUtils.dp2px(mContext, avatarSize); + LayoutParams avatarParams = (LayoutParams) mIvAvatar.getLayoutParams(); + avatarParams.width = avatarSizeDp; + avatarParams.height = avatarSizeDp; + avatarParams.leftMargin = SizeUtils.dp2px(mContext, (avatarHeadWearSize - avatarSize) / 2); + avatarParams.topMargin = SizeUtils.dp2px(mContext, (avatarHeadWearSize - avatarSize) / 2); + + int avatarHeadWearSizeDp = SizeUtils.dp2px(mContext, avatarHeadWearSize); + LayoutParams avatarHeadWearParam = (LayoutParams) mIvAvatarHeadWear.getLayoutParams(); + avatarHeadWearParam.width = avatarHeadWearSizeDp; + avatarHeadWearParam.height = avatarHeadWearSizeDp; + + int userLevelSizeDp = SizeUtils.dp2px(mContext, userLevelSize); + LayoutParams userLevelParam = (LayoutParams) mIvUserLevel.getLayoutParams(); + userLevelParam.width = userLevelSizeDp; + userLevelParam.height = userLevelSizeDp; + } + + public void setData(UserInfo userInfo) { + if (userInfo == null) return; + ImageLoadUtils.loadAvatar(mContext, userInfo.getAvatar(), mIvAvatar); + setNobleData(userInfo.getNobleInfo()); + } + + public void setData(String avatar, NobleInfo nobleInfo) { + ImageLoadUtils.loadAvatar(mContext, avatar, mIvAvatar); + setNobleData(nobleInfo); + } + + public void setData(ChatRoomMember chatRoomMember) { + if (chatRoomMember == null) return; + ImageLoadUtils.loadAvatar(mContext, chatRoomMember.getAvatar(), mIvAvatar); + NobleInfo nobleInfo = new NobleInfo(); + String resourceHeadWear = (String) NobleUtil.getResource(NobleResourceType.KEY_HEAD_WEAR, chatRoomMember); + nobleInfo.setHeadWear(resourceHeadWear); + setNobleData(nobleInfo); + } + + private void setNobleData(NobleInfo nobleInfo) { + if (nobleInfo != null) { + mIvAvatarHeadWear.setVisibility(VISIBLE); + mIvUserLevel.setVisibility(VISIBLE); + String headWear = nobleInfo.getHeadWear(); + if (TextUtils.isEmpty(headWear)) { + mIvAvatarHeadWear.setVisibility(INVISIBLE); + mIvUserLevel.setVisibility(nobleInfo.getLevel() > 0 ? VISIBLE : GONE); + NobleUtil.loadResource(NobleUtil.getBadgeByLevel(nobleInfo.getLevel()), mIvUserLevel); + } else { + mIvUserLevel.setVisibility(INVISIBLE); + NobleUtil.loadResource(headWear, mIvAvatarHeadWear); + } + } else { + mIvAvatarHeadWear.setVisibility(INVISIBLE); + mIvUserLevel.setVisibility(INVISIBLE); + } + } + + public ImageView getIvAvatar() { + return mIvAvatar; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/NobleOpenNoticeView.java b/app/src/main/java/com/chwl/app/ui/widget/NobleOpenNoticeView.java new file mode 100644 index 0000000..03019c2 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/NobleOpenNoticeView.java @@ -0,0 +1,173 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.graphics.Color; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.TextUtils; +import android.text.style.ForegroundColorSpan; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import androidx.core.content.ContextCompat; + +import com.opensource.svgaplayer.SVGACallback; +import com.opensource.svgaplayer.SVGADrawable; +import com.opensource.svgaplayer.SVGAImageView; +import com.opensource.svgaplayer.SVGAParser; +import com.opensource.svgaplayer.SVGAVideoEntity; +import com.chwl.app.R; +import com.chwl.core.noble.bean.NobleInfo; +import com.chwl.core.noble.NobleUtil; + +import java.net.MalformedURLException; +import java.net.URL; + +/** + *

房间里面开通贵族展示横幅

+ * + * @author jiahui + * @date 2018/1/19 + */ +public class NobleOpenNoticeView extends RelativeLayout implements View.OnClickListener { + private Context mContext; + + private TextView mNobleOpenContent; + private SVGAImageView mSVGAImageView; + private SVGAParser mSVGAParser; + + public NobleOpenNoticeView(Context context) { + this(context, null); + } + + public NobleOpenNoticeView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public NobleOpenNoticeView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + mContext = context; + inflate(context, R.layout.noble_open_notice_layout, this); + LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT); + setLayoutParams(params); + setBackgroundColor(ContextCompat.getColor(context, R.color.color_99000000)); + + mNobleOpenContent = findViewById(R.id.tv_noble_open_content); + mSVGAImageView = findViewById(R.id.noble_savg_view); + findViewById(R.id.iv_noble_open_close).setOnClickListener(this); + mSVGAParser = new SVGAParser(context); + } + + /** + * 设置数据 + * + * @param nobleInfo 贵族信息 + * @param nick 昵称 + * @param type 1:开通,2:续费 + */ + public void setData(NobleInfo nobleInfo, String nick, int type) { + if (nobleInfo == null || TextUtils.isEmpty(nick)) { + setVisibility(GONE); + return; + } + + String source = NobleUtil.getOpenEffectByLevel(nobleInfo.getLevel()); + if (TextUtils.isEmpty(source)) return; + if (source.toLowerCase().endsWith(".svga")) { + try { + mSVGAParser.parse(new URL(source), new SVGAParser.ParseCompletion() { + @Override + public void onComplete(SVGAVideoEntity svgaVideoEntity) { + setVisibility(VISIBLE); + SVGADrawable drawable = new SVGADrawable(svgaVideoEntity); + mSVGAImageView.setLoops(1); + mSVGAImageView.setImageDrawable(drawable); + mSVGAImageView.startAnimation(); + mSVGAImageView.setClearsAfterStop(true); + mSVGAImageView.setCallback(new SVGACallback() { + @Override + public void onPause() { + + } + + @Override + public void onFinished() { + NobleOpenNoticeView.this.setVisibility(GONE); + } + + @Override + public void onRepeat() { + + } + + @Override + public void onStep(int i, double v) { + + } + }); + } + + @Override + public void onError() { + setVisibility(GONE); + } + }); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + } + setVisibility(VISIBLE); + + String content = null; + if (type == 1) { + //恭喜 xxxx 开通“国王”贵族,速来膜拜 + content = mContext.getString(R.string.noble_open_notice, nick, nobleInfo.getName()); + } else if (type == 2) { + //恭喜 xxxx 续费“国王”贵族 + content = mContext.getString(R.string.noble_reopen_notice, nick, nobleInfo.getName()); + } + if (!TextUtils.isEmpty(content)) { + Spannable spannable = new SpannableString(content); + int start = content.lastIndexOf(nick); + int end = start + nick.length() + 1; + spannable.setSpan(new ForegroundColorSpan(Color.parseColor("#f3cf77")), + start - 1, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + start = content.lastIndexOf(nobleInfo.getName()); + end = start + nobleInfo.getName().length() + 1; + spannable.setSpan(new ForegroundColorSpan(Color.parseColor("#f3cf77")), + start - 1, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + mNobleOpenContent.setText(spannable); + } + } + + @Override + public void setVisibility(int visibility) { + super.setVisibility(visibility); + if (visibility == GONE || visibility == INVISIBLE) { + if (mSVGAImageView.isAnimating()) { + mSVGAImageView.clearAnimation(); + mSVGAImageView.setVisibility(GONE); + } + } + } + + @Override + public void onClick(View v) { + setVisibility(GONE); + if (mSVGAImageView.isAnimating()) { + mSVGAImageView.clearAnimation(); + } + } + + @Override + protected void onDetachedFromWindow() { + if (mSVGAImageView.isAnimating()) { + mSVGAImageView.clearAnimation(); + } + super.onDetachedFromWindow(); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/NumView.java b/app/src/main/java/com/chwl/app/ui/widget/NumView.java new file mode 100644 index 0000000..e8a3c3c --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/NumView.java @@ -0,0 +1,36 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.ImageView; +import android.widget.LinearLayout; + +import androidx.annotation.Nullable; + +import com.chwl.app.R; +import com.chwl.library.utils.JavaUtil; + +public class NumView extends LinearLayout { + + private int[] nums = {R.drawable.ic_num0, R.drawable.ic_num1, R.drawable.ic_num2 + , R.drawable.ic_num3, R.drawable.ic_num4, R.drawable.ic_num5 + , R.drawable.ic_num6, R.drawable.ic_num7, R.drawable.ic_num8 + , R.drawable.ic_num9}; + + public NumView(Context context) { + this(context, null); + } + + public NumView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + public void setNum(int num) { + char[] bytes = String.valueOf(num).toCharArray(); + for (char aByte : bytes) { + ImageView imageView = new ImageView(getContext()); + imageView.setImageResource(nums[JavaUtil.str2int(aByte + "")]); + addView(imageView); + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/ObservableScrollView.java b/app/src/main/java/com/chwl/app/ui/widget/ObservableScrollView.java new file mode 100644 index 0000000..0e31cba --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/ObservableScrollView.java @@ -0,0 +1,48 @@ +package com.chwl.app.ui.widget; + +/** + * Created by chenran on 2017/10/17. + */ + +import android.content.Context; +import android.util.AttributeSet; + +import androidx.core.widget.NestedScrollView; + +import com.netease.nim.uikit.common.util.log.LogUtil; + +public class ObservableScrollView extends NestedScrollView { + + private ScrollViewListener scrollViewListener = null; + + public ObservableScrollView(Context context) { + super(context); + } + + public ObservableScrollView(Context context, AttributeSet attrs, + int defStyle) { + super(context, attrs, defStyle); + } + + public ObservableScrollView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public void setScrollViewListener(ScrollViewListener scrollViewListener) { + this.scrollViewListener = scrollViewListener; + } + + @Override + protected void onScrollChanged(int x, int y, int oldx, int oldy) { + super.onScrollChanged(x, y, oldx, oldy); + LogUtil.i("ObservableScrollView", "x->"+x + " y->" + y + " oldx->" + oldx + " oldy" + oldy); + if (scrollViewListener != null) { + scrollViewListener.onScrollChanged(this, x, y, oldx, oldy); + } + } + + public interface ScrollViewListener { + void onScrollChanged(NestedScrollView view, int x, int y, int oldx, int oldy); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/OnPageSelectedListener.java b/app/src/main/java/com/chwl/app/ui/widget/OnPageSelectedListener.java new file mode 100644 index 0000000..35e7bdd --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/OnPageSelectedListener.java @@ -0,0 +1,21 @@ +package com.chwl.app.ui.widget; + +import androidx.viewpager.widget.ViewPager; + +/** + * + * Created by lvzebiao on 2018/11/8. + */ + +public abstract class OnPageSelectedListener implements ViewPager.OnPageChangeListener{ + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + + } + + @Override + public void onPageScrollStateChanged(int state) { + + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/ParentClickHorizontalScrollView.java b/app/src/main/java/com/chwl/app/ui/widget/ParentClickHorizontalScrollView.java new file mode 100644 index 0000000..7383723 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/ParentClickHorizontalScrollView.java @@ -0,0 +1,66 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.widget.HorizontalScrollView; + +/** + * 兼容父容器点击事件的HorizontalScrollView + * + * created by yc on 2018-12-27 + */ +public class ParentClickHorizontalScrollView extends HorizontalScrollView { + + private View parentView; + + public ParentClickHorizontalScrollView(Context context) { + super(context); + } + + public ParentClickHorizontalScrollView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public ParentClickHorizontalScrollView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public View getParentView() { + return parentView; + } + + public void setParentView(View parentView) { + this.parentView = parentView; + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + //注意 getParent() 是 ViewParent 但不一定是 View + if (parentView == null + && getParent() != null + && getParent() instanceof View) { + parentView = (View) getParent(); + } + + if (parentView != null) { + switch (ev.getAction()) { + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + parentView.onTouchEvent(ev); //使父容器也能响应本次按下事件 + break; + + case MotionEvent.ACTION_MOVE: //当触发滑动时,将父容器的按下响应失效 + //修改动作为ACTION_CANCEL + ev.setAction(MotionEvent.ACTION_CANCEL); + parentView.onTouchEvent(ev); + //父容器响应后恢复事件原动作 + ev.setAction(MotionEvent.ACTION_MOVE); + break; + } + } + return super.onTouchEvent(ev); //无论如何 本身都响应事件 + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/PinEntryEditText.java b/app/src/main/java/com/chwl/app/ui/widget/PinEntryEditText.java new file mode 100644 index 0000000..7d9e493 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/PinEntryEditText.java @@ -0,0 +1,630 @@ +/** + * Copyright 2016 Ali Muzaffar + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.chwl.app.ui.widget; + +import android.animation.Animator; +import android.animation.AnimatorSet; +import android.animation.ValueAnimator; +import android.content.Context; +import android.content.res.ColorStateList; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Typeface; +import android.graphics.drawable.Drawable; +import android.text.InputFilter; +import android.text.InputType; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.ActionMode; +import android.view.View; +import android.view.animation.OvershootInterpolator; +import android.view.inputmethod.InputMethodManager; + +import androidx.annotation.Nullable; +import androidx.appcompat.widget.AppCompatEditText; +import androidx.core.content.ContextCompat; +import androidx.core.view.ViewCompat; + +import com.chwl.app.R; + + +public class PinEntryEditText extends AppCompatEditText { + private static final String XML_NAMESPACE_ANDROID = "http://schemas.android.com/apk/res/android"; + + public static final String DEFAULT_MASK = "\u25CF"; + + protected String mMask = null; + protected StringBuilder mMaskChars = null; + protected String mSingleCharHint = null; + protected int mAnimatedType = 0; + protected float mSpace = 24; //24 dp by default, space between the lines + protected float mCharSize; + protected float mNumChars = 4; + protected float mTextBottomPadding = 8; //8dp by default, height of the text from our lines + protected int mMaxLength = 4; + protected RectF[] mLineCoords; + protected float[] mCharBottom; + protected Paint mCharPaint; + protected Paint mLastCharPaint; + protected Paint mSingleCharPaint; + protected Drawable mPinBackground; + protected Rect mTextHeight = new Rect(); + protected boolean mIsDigitSquare = false; + + protected OnClickListener mClickListener; + protected OnPinEnteredListener mOnPinEnteredListener = null; + + protected float mLineStroke = 1; //1dp by default + protected float mLineStrokeSelected = 2; //2dp by default + protected Paint mLinesPaint; + protected boolean mAnimate = false; + protected boolean mHasError = false; + protected ColorStateList mOriginalTextColors; + protected int[][] mStates = new int[][]{ + new int[]{android.R.attr.state_selected}, // selected + new int[]{android.R.attr.state_active}, // error + new int[]{android.R.attr.state_focused}, // focused + new int[]{-android.R.attr.state_focused}, // unfocused + }; + + protected int[] mColors = new int[]{ + Color.GREEN, + Color.RED, + Color.BLACK, + Color.GRAY + }; + + protected ColorStateList mColorStates = new ColorStateList(mStates, mColors); + + public PinEntryEditText(Context context) { + super(context); + } + + public PinEntryEditText(Context context, AttributeSet attrs) { + super(context, attrs); + init(context, attrs); + } + + public PinEntryEditText(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context, attrs); + } + + public void setMaxLength(final int maxLength) { + mMaxLength = maxLength; + mNumChars = maxLength; + + setFilters(new InputFilter[]{new InputFilter.LengthFilter(maxLength)}); + + setText(null); + invalidate(); + } + + public void setMask(String mask) { + mMask = mask; + mMaskChars = null; + invalidate(); + } + + public void setSingleCharHint(String hint) { + mSingleCharHint = hint; + invalidate(); + } + + private void init(Context context, AttributeSet attrs) { + float multi = context.getResources().getDisplayMetrics().density; + mLineStroke = multi * mLineStroke; + mLineStrokeSelected = multi * mLineStrokeSelected; + mSpace = multi * mSpace; //convert to pixels for our density + mTextBottomPadding = multi * mTextBottomPadding; //convert to pixels for our density + + TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.PinEntryEditText, 0, 0); + try { + TypedValue outValue = new TypedValue(); + ta.getValue(R.styleable.PinEntryEditText_pinAnimationType, outValue); + mAnimatedType = outValue.data; + mMask = ta.getString(R.styleable.PinEntryEditText_pinCharacterMask); + mSingleCharHint = ta.getString(R.styleable.PinEntryEditText_pinRepeatedHint); + mLineStroke = ta.getDimension(R.styleable.PinEntryEditText_pinLineStroke, mLineStroke); + mLineStrokeSelected = ta.getDimension(R.styleable.PinEntryEditText_pinLineStrokeSelected, mLineStrokeSelected); + mSpace = ta.getDimension(R.styleable.PinEntryEditText_pinCharacterSpacing, mSpace); + mTextBottomPadding = ta.getDimension(R.styleable.PinEntryEditText_pinTextBottomPadding, mTextBottomPadding); + mIsDigitSquare = ta.getBoolean(R.styleable.PinEntryEditText_pinBackgroundIsSquare, mIsDigitSquare); + mPinBackground = ta.getDrawable(R.styleable.PinEntryEditText_pinBackgroundDrawable); + ColorStateList colors = ta.getColorStateList(R.styleable.PinEntryEditText_pinLineColors); + if (colors != null) { + mColorStates = colors; + } + } finally { + ta.recycle(); + } + + mCharPaint = new Paint(getPaint()); + mLastCharPaint = new Paint(getPaint()); + mSingleCharPaint = new Paint(getPaint()); + mLinesPaint = new Paint(getPaint()); + mLinesPaint.setStrokeWidth(mLineStroke); + + TypedValue outValue = new TypedValue(); + context.getTheme().resolveAttribute(R.attr.colorControlActivated, + outValue, true); + int colorSelected = outValue.data; + mColors[0] = colorSelected; + + int colorFocused = isInEditMode() ? Color.GRAY : ContextCompat.getColor(context, R.color.color_999999); + mColors[1] = colorFocused; + + int colorUnfocused = isInEditMode() ? Color.GRAY : ContextCompat.getColor(context, R.color.color_999999); + mColors[2] = colorUnfocused; + + setBackgroundResource(0); + + mMaxLength = attrs.getAttributeIntValue(XML_NAMESPACE_ANDROID, "maxLength", 4); + mNumChars = mMaxLength; + + //Disable copy paste +// super.setCustomSelectionActionModeCallback(new ActionMode.Callback() { +// public boolean onPrepareActionMode(ActionMode mode, Menu menu) { +// return false; +// } +// +// public void onDestroyActionMode(ActionMode mode) { +// } +// +// public boolean onCreateActionMode(ActionMode mode, Menu menu) { +// return false; +// } +// +// public boolean onActionItemClicked(ActionMode mode, MenuItem item) { +// return false; +// } +// }); + // When tapped, move cursor to end of text. + super.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + setSelection(getText().length()); + if (mClickListener != null) { + mClickListener.onClick(v); + } + } + }); + +// super.setOnLongClickListener(new OnLongClickListener() { +// @Override +// public boolean onLongClick(View v) { +// setSelection(getText().length()); +// return true; +// } +// }); + + //If input type is password and no mask is set, use a default mask + if ((getInputType() & InputType.TYPE_TEXT_VARIATION_PASSWORD) == InputType.TYPE_TEXT_VARIATION_PASSWORD && TextUtils.isEmpty(mMask)) { + mMask = DEFAULT_MASK; + } else if ((getInputType() & InputType.TYPE_NUMBER_VARIATION_PASSWORD) == InputType.TYPE_NUMBER_VARIATION_PASSWORD && TextUtils.isEmpty(mMask)) { + mMask = DEFAULT_MASK; + } + + if (!TextUtils.isEmpty(mMask)) { + mMaskChars = getMaskChars(); + } + + //Height of the characters, used if there is a background drawable + getPaint().getTextBounds("|", 0, 1, mTextHeight); + + mAnimate = mAnimatedType > -1; + } + + @Override + public void setInputType(int type) { + super.setInputType(type); + + if ((type & InputType.TYPE_TEXT_VARIATION_PASSWORD) == InputType.TYPE_TEXT_VARIATION_PASSWORD + || (type & InputType.TYPE_NUMBER_VARIATION_PASSWORD) == InputType.TYPE_NUMBER_VARIATION_PASSWORD) { + // If input type is password and no mask is set, use a default mask + if (TextUtils.isEmpty(mMask)) { + setMask(DEFAULT_MASK); + } + } else { + // If input type is not password, remove mask + setMask(null); + } + + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + mOriginalTextColors = getTextColors(); + if (mOriginalTextColors != null) { + mLastCharPaint.setColor(mOriginalTextColors.getDefaultColor()); + mCharPaint.setColor(mOriginalTextColors.getDefaultColor()); + mSingleCharPaint.setColor(getCurrentHintTextColor()); + } + int availableWidth = getWidth() - ViewCompat.getPaddingEnd(this) - ViewCompat.getPaddingStart(this); + if (mSpace < 0) { + mCharSize = (availableWidth / (mNumChars * 2 - 1)); + } else { + mCharSize = (availableWidth - (mSpace * (mNumChars - 1))) / mNumChars; + } + mLineCoords = new RectF[(int) mNumChars]; + mCharBottom = new float[(int) mNumChars]; + int startX; + int bottom = getHeight() - getPaddingBottom(); + int rtlFlag; + final boolean isLayoutRtl = ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL; + if (isLayoutRtl) { + rtlFlag = -1; + startX = (int) (getWidth() - ViewCompat.getPaddingStart(this) - mCharSize); + } else { + rtlFlag = 1; + startX = ViewCompat.getPaddingStart(this); + } + for (int i = 0; i < mNumChars; i++) { + mLineCoords[i] = new RectF(startX, bottom, startX + mCharSize, bottom); + if (mPinBackground != null) { + if (mIsDigitSquare) { + mLineCoords[i].top = getPaddingTop(); + mLineCoords[i].right = startX + mLineCoords[i].width(); + } else { + mLineCoords[i].top -= mTextHeight.height() + mTextBottomPadding * 2; + } + } + + if (mSpace < 0) { + startX += rtlFlag * mCharSize * 2; + } else { + startX += rtlFlag * (mCharSize + mSpace); + } + mCharBottom[i] = mLineCoords[i].bottom - mTextBottomPadding; + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (mIsDigitSquare) { + int widthMode = MeasureSpec.getMode(widthMeasureSpec); + int heightMode = MeasureSpec.getMode(heightMeasureSpec); + int measuredWidth = 0; + int measuredHeight = 0; + // If we want a square or circle pin box, we might be able + // to figure out the dimensions outselves + // if width and height are set to wrap_content or match_parent + if (widthMode == MeasureSpec.EXACTLY) { + measuredWidth = MeasureSpec.getSize(widthMeasureSpec); + measuredHeight = (int) ((measuredWidth - (mNumChars - 1 * mSpace)) / mNumChars); + } else if (heightMode == MeasureSpec.EXACTLY) { + measuredHeight = MeasureSpec.getSize(heightMeasureSpec); + measuredWidth = (int) ((measuredHeight * mNumChars) + (mSpace * mNumChars - 1)); + } else if (widthMode == MeasureSpec.AT_MOST) { + measuredWidth = MeasureSpec.getSize(widthMeasureSpec); + measuredHeight = (int) ((measuredWidth - (mNumChars - 1 * mSpace)) / mNumChars); + } else if (heightMode == MeasureSpec.AT_MOST) { + measuredHeight = MeasureSpec.getSize(heightMeasureSpec); + measuredWidth = (int) ((measuredHeight * mNumChars) + (mSpace * mNumChars - 1)); + } else { + // Both unspecific + // Try for a width based on our minimum + measuredWidth = getPaddingLeft() + getPaddingRight() + getSuggestedMinimumWidth(); + + // Whatever the width ends up being, ask for a height that would let the pie + // get as big as it can + measuredHeight = (int) ((measuredWidth - (mNumChars - 1 * mSpace)) / mNumChars); + } + + setMeasuredDimension( + resolveSizeAndState(measuredWidth, widthMeasureSpec, 1), resolveSizeAndState(measuredHeight, heightMeasureSpec, 0)); + } else { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + } + + @Override + public void setOnClickListener(OnClickListener l) { + mClickListener = l; + } + + @Override + public void setCustomSelectionActionModeCallback(ActionMode.Callback actionModeCallback) { + throw new RuntimeException("setCustomSelectionActionModeCallback() not supported."); + } + + @Override + protected void onDraw(Canvas canvas) { + //super.onDraw(canvas); + CharSequence text = getFullText(); + int textLength = text.length(); + float[] textWidths = new float[textLength]; + getPaint().getTextWidths(text, 0, textLength, textWidths); + + float hintWidth = 0; + if (mSingleCharHint != null) { + float[] hintWidths = new float[mSingleCharHint.length()]; + getPaint().getTextWidths(mSingleCharHint, hintWidths); + for (float i : hintWidths) { + hintWidth += i; + } + } + for (int i = 0; i < mNumChars; i++) { + //If a background for the pin characters is specified, it should be behind the characters. + if (mPinBackground != null) { + updateDrawableState(i < textLength, i == textLength); + mPinBackground.setBounds((int) mLineCoords[i].left, (int) mLineCoords[i].top, (int) mLineCoords[i].right, (int) mLineCoords[i].bottom); + mPinBackground.draw(canvas); + } + float middle = mLineCoords[i].left + mCharSize / 2; + if (textLength > i) { + if (!mAnimate || i != textLength - 1) { + canvas.drawText(text, i, i + 1, middle - textWidths[i] / 2, mCharBottom[i], mCharPaint); + } else { + canvas.drawText(text, i, i + 1, middle - textWidths[i] / 2, mCharBottom[i], mLastCharPaint); + } + } else if (mSingleCharHint != null) { + canvas.drawText(mSingleCharHint, middle - hintWidth / 2, mCharBottom[i], mSingleCharPaint); + } + //The lines should be in front of the text (because that's how I want it). + if (mPinBackground == null) { + updateColorForLines(i <= textLength); + canvas.drawLine(mLineCoords[i].left, mLineCoords[i].top, mLineCoords[i].right, mLineCoords[i].bottom, mLinesPaint); + } + } + } + + private CharSequence getFullText() { + if (TextUtils.isEmpty(mMask)) { + return getText(); + } else { + return getMaskChars(); + } + } + + private StringBuilder getMaskChars() { + if (mMaskChars == null) { + mMaskChars = new StringBuilder(); + } + int textLength = getText().length(); + while (mMaskChars.length() != textLength) { + if (mMaskChars.length() < textLength) { + mMaskChars.append(mMask); + } else { + mMaskChars.deleteCharAt(mMaskChars.length() - 1); + } + } + return mMaskChars; + } + + + private int getColorForState(int... states) { + return mColorStates.getColorForState(states, Color.GRAY); + } + + /** + * @param hasTextOrIsNext Is the color for a character that has been typed or is + * the next character to be typed? + */ + protected void updateColorForLines(boolean hasTextOrIsNext) { + if (mHasError) { + mLinesPaint.setColor(getColorForState(android.R.attr.state_active)); + } else if (isFocused()) { + mLinesPaint.setStrokeWidth(mLineStrokeSelected); + mLinesPaint.setColor(getColorForState(android.R.attr.state_focused)); + if (hasTextOrIsNext) { + mLinesPaint.setColor(getColorForState(android.R.attr.state_selected)); + } + } else { + mLinesPaint.setStrokeWidth(mLineStroke); + mLinesPaint.setColor(getColorForState(-android.R.attr.state_focused)); + } + } + + protected void updateDrawableState(boolean hasText, boolean isNext) { + if (mHasError) { + mPinBackground.setState(new int[]{android.R.attr.state_active}); + } else if (isFocused()) { + mPinBackground.setState(new int[]{android.R.attr.state_focused}); + if (isNext) { + mPinBackground.setState(new int[]{android.R.attr.state_focused, android.R.attr.state_selected}); + } else if (hasText) { + mPinBackground.setState(new int[]{android.R.attr.state_focused, android.R.attr.state_checked}); + } + } else { + if (hasText) { + mPinBackground.setState(new int[]{-android.R.attr.state_focused, android.R.attr.state_checked}); + } else { + mPinBackground.setState(new int[]{-android.R.attr.state_focused}); + } + } + } + + public void setError(boolean hasError) { + mHasError = hasError; + invalidate(); + } + + public boolean isError() { + return mHasError; + } + + /** + * Request focus on this PinEntryEditText + */ + public void focus() { + requestFocus(); + + // Show keyboard + InputMethodManager inputMethodManager = (InputMethodManager) getContext() + .getSystemService(Context.INPUT_METHOD_SERVICE); + inputMethodManager.showSoftInput(this, 0); + } + + @Override + public void setTypeface(@Nullable Typeface tf) { + super.setTypeface(tf); + setCustomTypeface(tf); + } + + @Override + public void setTypeface(@Nullable Typeface tf, int style) { + super.setTypeface(tf, style); + setCustomTypeface(tf); + } + + private void setCustomTypeface(@Nullable Typeface tf) { + if (mCharPaint != null) { + mCharPaint.setTypeface(tf); + mLastCharPaint.setTypeface(tf); + mSingleCharPaint.setTypeface(tf); + mLinesPaint.setTypeface(tf); + } + } + + public void setPinLineColors(ColorStateList colors) { + mColorStates = colors; + invalidate(); + } + + public void setPinBackground(Drawable pinBackground) { + mPinBackground = pinBackground; + invalidate(); + } + + @Override + protected void onTextChanged(CharSequence text, final int start, int lengthBefore, final int lengthAfter) { + setError(false); + if (mLineCoords == null || !mAnimate) { + if (mOnPinEnteredListener != null && text.length() == mMaxLength) { + mOnPinEnteredListener.onPinEntered(text); + } + return; + } + + if (mAnimatedType == -1) { + invalidate(); + return; + } + + if (lengthAfter > lengthBefore) { + if (mAnimatedType == 0) { + animatePopIn(); + } else { + animateBottomUp(text, start); + } + } + } + + private void animatePopIn() { + ValueAnimator va = ValueAnimator.ofFloat(1, getPaint().getTextSize()); + va.setDuration(200); + va.setInterpolator(new OvershootInterpolator()); + va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + mLastCharPaint.setTextSize((Float) animation.getAnimatedValue()); + PinEntryEditText.this.invalidate(); + } + }); + if (getText().length() == mMaxLength && mOnPinEnteredListener != null) { + va.addListener(new Animator.AnimatorListener() { + @Override + public void onAnimationStart(Animator animation) { + } + + @Override + public void onAnimationEnd(Animator animation) { + mOnPinEnteredListener.onPinEntered(getText()); + } + + @Override + public void onAnimationCancel(Animator animation) { + } + + @Override + public void onAnimationRepeat(Animator animation) { + } + }); + } + va.start(); + } + + private void animateBottomUp(CharSequence text, final int start) { + mCharBottom[start] = mLineCoords[start].bottom - mTextBottomPadding; + ValueAnimator animUp = ValueAnimator.ofFloat(mCharBottom[start] + getPaint().getTextSize(), mCharBottom[start]); + animUp.setDuration(300); + animUp.setInterpolator(new OvershootInterpolator()); + animUp.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + Float value = (Float) animation.getAnimatedValue(); + mCharBottom[start] = value; + PinEntryEditText.this.invalidate(); + } + }); + + mLastCharPaint.setAlpha(255); + ValueAnimator animAlpha = ValueAnimator.ofInt(0, 255); + animAlpha.setDuration(300); + animAlpha.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + Integer value = (Integer) animation.getAnimatedValue(); + mLastCharPaint.setAlpha(value); + } + }); + + AnimatorSet set = new AnimatorSet(); + if (text.length() == mMaxLength && mOnPinEnteredListener != null) { + set.addListener(new Animator.AnimatorListener() { + + @Override + public void onAnimationStart(Animator animation) { + } + + @Override + public void onAnimationEnd(Animator animation) { + mOnPinEnteredListener.onPinEntered(getText()); + } + + @Override + public void onAnimationCancel(Animator animation) { + } + + @Override + public void onAnimationRepeat(Animator animation) { + + } + }); + } + set.playTogether(animUp, animAlpha); + set.start(); + } + + public void setAnimateText(boolean animate) { + mAnimate = animate; + } + + public void setOnPinEnteredListener(OnPinEnteredListener l) { + mOnPinEnteredListener = l; + } + + public interface OnPinEnteredListener { + void onPinEntered(CharSequence str); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/widget/RecallDialog.java b/app/src/main/java/com/chwl/app/ui/widget/RecallDialog.java new file mode 100644 index 0000000..870bb80 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/RecallDialog.java @@ -0,0 +1,118 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.EditText; +import android.widget.TextView; + +import com.netease.nim.uikit.common.util.string.StringUtil; +import com.chwl.app.R; +import com.chwl.app.base.BaseActivity; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.recall.RecallModel; +import com.chwl.core.recall.bean.GoBackInfo; +import com.chwl.core.recall.event.GoBackEvent; +import com.chwl.core.user.UserModel; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.core.utils.SharedPreferenceUtils; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import io.reactivex.functions.Consumer; + +public class RecallDialog extends BaseActivity implements View.OnClickListener { + /** 一个设备只能领取一次老用户回归礼物 */ + public static final String GO_BACK_ONCE = "go_back_once"; + + private EditText etRecallInput; + + public static void start(Context context) { + Intent intent = new Intent(context, RecallDialog.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + requestWindowFeature(Window.FEATURE_NO_TITLE); + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); + setContentView(R.layout.recall_dialog); + initView(); + + EventBus.getDefault().register(this); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + EventBus.getDefault().unregister(this); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onGobackEvent(GoBackEvent event){ + if (event.isFailed()) { + SingleToastUtil.showToast(event.getError()); + } else { + GoBackInfo goBackInfo = (GoBackInfo) event.getData(); + + SingleToastUtil.showToast(goBackInfo.getMessage()); + SharedPreferenceUtils.put(GO_BACK_ONCE, "true"); + finish(); + } + } + + private void initView() { + etRecallInput = findViewById(R.id.et_recall_input); + + TextView tvRecallName = findViewById(R.id.tv_recall_name); + UserModel.get().getCurrentUserInfo().subscribe(new Consumer() { + @Override + public void accept(UserInfo info) throws Exception { + tvRecallName.setText(ResUtil.getString(R.string.ui_widget_recalldialog_01) + info.getNick() + ":"); + } + }); + findViewById(R.id.tv_get_recall_gift).setOnClickListener(this); + findViewById(R.id.iv_recall_close).setOnClickListener(this); + } + + private void goBack(String uid, String inviteCode) { + RecallModel.get().goBack(uid, StringUtil.isEmpty(inviteCode) ? "" : inviteCode); + } + + /** + * 只有框内按钮可以关闭弹框 + */ + @Override + public void onBackPressed() { +// super.onBackPressed(); + } + + @Override + public void onClick(View v) { + + switch (v.getId()) { + + case R.id.tv_get_recall_gift: // 收下回归礼 + goBack(String.valueOf(AuthModel.get().getCurrentUid()), etRecallInput.getText().toString().trim()); + break; + + case R.id.iv_recall_close: + finish(); + break; + + default: + break; + } + + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/RectLayout.java b/app/src/main/java/com/chwl/app/ui/widget/RectLayout.java new file mode 100644 index 0000000..4bdeb86 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/RectLayout.java @@ -0,0 +1,45 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.widget.RelativeLayout; + +import com.chwl.app.R; + +/** + * Created by jack + */ +public class RectLayout extends RelativeLayout { + + private float hwRatio = -1.0f; + public RectLayout(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RectLayout, defStyle, 0); + hwRatio = a.getFloat(R.styleable.RectLayout_hw_ratio, -1.0f); + + a.recycle(); + } + + public RectLayout(Context context, AttributeSet attrs) { + this(context, attrs,0); + } + + public RectLayout(Context context) { + super(context); + } + + + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + + setMeasuredDimension(getDefaultSize(0, widthMeasureSpec), getDefaultSize(0, heightMeasureSpec)); + + if (hwRatio > 0){ + int childWidthSize = getMeasuredWidth(); + heightMeasureSpec = MeasureSpec.makeMeasureSpec((int) (childWidthSize * hwRatio), MeasureSpec.EXACTLY); + } + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/RecyclerRefreshLayout.java b/app/src/main/java/com/chwl/app/ui/widget/RecyclerRefreshLayout.java new file mode 100644 index 0000000..80fb9c4 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/RecyclerRefreshLayout.java @@ -0,0 +1,228 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; + +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.StaggeredGridLayoutManager; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import com.chwl.app.R; + + +/** + * 下拉刷新上拉加载控件,目前适用于RecyclerView + * Created by huanghaibin on 16-5-3. + */ +public class RecyclerRefreshLayout extends SwipeRefreshLayout implements SwipeRefreshLayout.OnRefreshListener { + private RecyclerView mRecycleView; + + private int mTouchSlop; + + private SuperRefreshLayoutListener listener; + + private boolean mIsOnLoading = false; + + private boolean mCanLoadMore = true; + + private boolean mHasMore = true; + + private int mYDown; + + private int mLastY; + + public RecyclerRefreshLayout(Context context) { + this(context, null); + } + + public RecyclerRefreshLayout(Context context, AttributeSet attrs) { + super(context, attrs); + mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); + setOnRefreshListener(this); + } + + + @Override + public void onRefresh() { + if (listener != null && !mIsOnLoading) { + listener.onRefreshing(); + } else + setRefreshing(false); + } + + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + // 初始化ListView对象 + if (mRecycleView == null) { + getRecycleView(); + } + } + + /** + * 获取RecyclerView,后续支持AbsListView + */ + private void getRecycleView() { + if (getChildCount() > 0) { + View childView = getChildAt(0); + if (!(childView instanceof RecyclerView)) { + childView = findViewById(R.id.recyclerView); + } + if (childView != null && childView instanceof RecyclerView) { + mRecycleView = (RecyclerView) childView; + mRecycleView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrollStateChanged(RecyclerView recyclerView, int newState) { + + } + + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + if (canLoad() && mCanLoadMore) { + loadData(); + } + } + }); + } + } + } + + @Override + public boolean dispatchTouchEvent(MotionEvent event) { + final int action = event.getAction(); + switch (action) { + case MotionEvent.ACTION_DOWN: + mYDown = (int) event.getRawY(); + break; + case MotionEvent.ACTION_MOVE: + mLastY = (int) event.getRawY(); + break; + default: + break; + } + return super.dispatchTouchEvent(event); + } + + /** + * 是否可以加载更多, 条件是到了最底部 + * + * @return isCanLoad + */ + private boolean canLoad() { + return isScrollBottom() && !mIsOnLoading && isPullUp() && mHasMore; + } + + /** + * 如果到了最底部,而且是上拉操作.那么执行onLoad方法 + */ + private void loadData() { + if (listener != null) { + setOnLoading(true); + listener.onLoadMore(); + } + } + + /** + * 是否是上拉操作 + * + * @return isPullUp + */ + private boolean isPullUp() { + return (mYDown - mLastY) >= mTouchSlop; + } + + /** + * 设置正在加载 + * + * @param loading 设置正在加载 + */ + public void setOnLoading(boolean loading) { + mIsOnLoading = loading; + if (!mIsOnLoading) { + mYDown = 0; + mLastY = 0; + } + } + + /** + * 判断是否到了最底部 + */ + private boolean isScrollBottom() { + return (mRecycleView != null && mRecycleView.getAdapter() != null) + && getLastVisiblePosition() == (mRecycleView.getAdapter().getItemCount() - 1); + } + + /** + * 加载结束记得调用 + */ + public void onComplete() { + setOnLoading(false); + setRefreshing(false); + mHasMore = true; + } + + /** + * 是否可加载更多 + * + * @param mCanLoadMore 是否可加载更多 + */ + public void setCanLoadMore(boolean mCanLoadMore) { + this.mCanLoadMore = mCanLoadMore; + } + + /** + * 获取RecyclerView可见的最后一项 + * + * @return 可见的最后一项position + */ + public int getLastVisiblePosition() { + int position; + if (mRecycleView.getLayoutManager() instanceof LinearLayoutManager) { + position = ((LinearLayoutManager) mRecycleView.getLayoutManager()).findLastVisibleItemPosition(); + } else if (mRecycleView.getLayoutManager() instanceof GridLayoutManager) { + position = ((GridLayoutManager) mRecycleView.getLayoutManager()).findLastVisibleItemPosition(); + } else if (mRecycleView.getLayoutManager() instanceof StaggeredGridLayoutManager) { + StaggeredGridLayoutManager layoutManager = (StaggeredGridLayoutManager) mRecycleView.getLayoutManager(); + int[] lastPositions = layoutManager.findLastVisibleItemPositions(new int[layoutManager.getSpanCount()]); + position = getMaxPosition(lastPositions); + } else { + position = mRecycleView.getLayoutManager().getItemCount() - 1; + } + return position; + } + + /** + * 获得最大的位置 + * + * @param positions 获得最大的位置 + * @return 获得最大的位置 + */ + private int getMaxPosition(int[] positions) { + int maxPosition = Integer.MIN_VALUE; + for (int position : positions) { + maxPosition = Math.max(maxPosition, position); + } + return maxPosition; + } + + /** + * 添加加载和刷新 + * + * @param listener add the listener for SuperRefreshLayout + */ + public void setSuperRefreshLayoutListener(SuperRefreshLayoutListener listener) { + this.listener = listener; + } + + public interface SuperRefreshLayoutListener { + void onRefreshing(); + + void onLoadMore(); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/RecyclerViewNoBugLinearLayoutManager.java b/app/src/main/java/com/chwl/app/ui/widget/RecyclerViewNoBugLinearLayoutManager.java new file mode 100644 index 0000000..38aa682 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/RecyclerViewNoBugLinearLayoutManager.java @@ -0,0 +1,46 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.util.AttributeSet; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +/** + * Created by ${Seven} on 2017/10/18. + */ + +public class RecyclerViewNoBugLinearLayoutManager extends LinearLayoutManager { + public RecyclerViewNoBugLinearLayoutManager(Context context) { + super( context ); + } + + public RecyclerViewNoBugLinearLayoutManager(Context context, int orientation, boolean reverseLayout) { + super( context, orientation, reverseLayout ); + } + + public RecyclerViewNoBugLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super( context, attrs, defStyleAttr, defStyleRes ); + } + + @Override + public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { + try { + //try catch一下 + super.onLayoutChildren( recycler, state ); + } catch (Exception e) { + e.printStackTrace(); + } + + } + + @Override + public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) { + try { + return super.scrollVerticallyBy(dy, recycler, state); + } catch (Exception e) { + e.printStackTrace(); + } + return 0; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/RecyclerViewNoViewpagerScroll.java b/app/src/main/java/com/chwl/app/ui/widget/RecyclerViewNoViewpagerScroll.java new file mode 100644 index 0000000..4f7cbb7 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/RecyclerViewNoViewpagerScroll.java @@ -0,0 +1,31 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; + +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.RecyclerView; + +/** + * 横向RecyclerView与Viewpager结合使用, RecyclerView区域禁止Viewpager滑动 + */ +public class RecyclerViewNoViewpagerScroll extends RecyclerView { + public RecyclerViewNoViewpagerScroll(Context context) { + super(context); + } + + public RecyclerViewNoViewpagerScroll(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + public RecyclerViewNoViewpagerScroll(Context context, @Nullable AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + getParent().requestDisallowInterceptTouchEvent(true); + return super.dispatchTouchEvent(ev); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/RedPointView.java b/app/src/main/java/com/chwl/app/ui/widget/RedPointView.java new file mode 100644 index 0000000..116b69f --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/RedPointView.java @@ -0,0 +1,84 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.text.TextPaint; +import android.text.TextUtils; +import android.util.AttributeSet; + +import androidx.annotation.Nullable; +import androidx.appcompat.widget.AppCompatTextView; + +import com.chwl.app.R; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; + +/** + * 本来是继承View,但是发现new出来的paint和textview不一样,(暂时没找到原因) + * 所以继承textview ,获取textview的paint + * create by lvzebiao @2019/5/7 + */ +public class RedPointView extends AppCompatTextView { + + private String text; + + private TextPaint textPaint; + + private float textYOffset; + + private Rect rect; + + private int padding; + + public RedPointView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + TypedArray a = context.obtainStyledAttributes(attrs, + R.styleable.RedPointView, 0, 0); + padding = a.getDimensionPixelOffset(R.styleable.RedPointView_rpv_padding, UIUtil.dip2px(context, 5)); + a.recycle(); + + rect = new Rect(); + textPaint = getPaint(); + //textPaint.setColor(textColor); + textPaint.setTextAlign(Paint.Align.CENTER); + //textPaint.setTextSize(textSize); + Paint.FontMetrics textFontMetrics = textPaint.getFontMetrics(); + /* + * drawText从baseline开始,baseline的值为0,baseline的上面为负值,baseline的下面为正值, + * 即这里ascent为负值,descent为正值。 + * 比如ascent为-20,descent为5,那需要移动的距离就是20 - (20 + 5)/ 2 + */ + textYOffset = -textFontMetrics.ascent - (-textFontMetrics.ascent + textFontMetrics.descent) / 2; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int height = MeasureSpec.getSize(heightMeasureSpec); + int textWidth = 0; + if (!TextUtils.isEmpty(text) && text.length() >= 2) { + //测量文本的长度 + rect.setEmpty(); + textPaint.getTextBounds(text, 0, text.length(), rect); + textWidth = rect.width(); + } + int width = Math.max(textWidth + padding * 2, height); + //noinspection SuspiciousNameCombination + setMeasuredDimension(width, height); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (!TextUtils.isEmpty(text)) { + canvas.drawText(text, (float) getWidth() / 2, (float) getHeight() / 2 + textYOffset, + textPaint); + } + } + + public void setNumber(String text) { + this.text = text; + invalidate(); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/ScollLinearLayoutManager.java b/app/src/main/java/com/chwl/app/ui/widget/ScollLinearLayoutManager.java new file mode 100644 index 0000000..25bc90f --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/ScollLinearLayoutManager.java @@ -0,0 +1,53 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.graphics.PointF; +import android.util.DisplayMetrics; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.LinearSmoothScroller; +import androidx.recyclerview.widget.RecyclerView; + +public class ScollLinearLayoutManager extends LinearLayoutManager { + private float MILLISECONDS_PER_INCH = 1f; //修改可以改变数据,越大速度越慢 + private Context contxt; + + public ScollLinearLayoutManager(Context context, @RecyclerView.Orientation int orientation, + boolean reverseLayout) { + super(context, orientation, reverseLayout); + this.contxt = context; + } + + @Override + public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) { + LinearSmoothScroller linearSmoothScroller = + new LinearSmoothScroller(recyclerView.getContext()) { + @Override + public PointF computeScrollVectorForPosition(int targetPosition) { + return ScollLinearLayoutManager.this + .computeScrollVectorForPosition(targetPosition); + } + + //This returns the milliseconds it takes to + //scroll one pixel. + @Override + protected float calculateSpeedPerPixel + (DisplayMetrics displayMetrics) { + return MILLISECONDS_PER_INCH / displayMetrics.density; + //返回滑动一个pixel需要多少毫秒 + } + + }; + linearSmoothScroller.setTargetPosition(position); + startSmoothScroll(linearSmoothScroller); + } + + //可以用来设置速度 + public void setSpeedSlow(float x) { + //自己在这里用density去乘,希望不同分辨率设备上滑动速度相同 + //0.3f是自己估摸的一个值,可以根据不同需求自己修改 + MILLISECONDS_PER_INCH = contxt.getResources().getDisplayMetrics().density * 0.3f + (x); + } + +} + diff --git a/app/src/main/java/com/chwl/app/ui/widget/ShareRedBagDialog.java b/app/src/main/java/com/chwl/app/ui/widget/ShareRedBagDialog.java new file mode 100644 index 0000000..04f121c --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/ShareRedBagDialog.java @@ -0,0 +1,29 @@ +package com.chwl.app.ui.widget; + +import android.app.Dialog; +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.StyleRes; + +/** + * Created by Seven on 2017/9/24. + */ + +public class ShareRedBagDialog extends Dialog { + public ShareRedBagDialog(@NonNull Context context) { + super(context); + } + + public ShareRedBagDialog(@NonNull Context context, @StyleRes int themeResId) { + super(context, themeResId); + } + + protected ShareRedBagDialog(@NonNull Context context, boolean cancelable, @Nullable + OnCancelListener cancelListener) { + super(context, cancelable, cancelListener); + } + + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/SideBarView.kt b/app/src/main/java/com/chwl/app/ui/widget/SideBarView.kt new file mode 100644 index 0000000..ee53550 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/SideBarView.kt @@ -0,0 +1,146 @@ +package com.chwl.app.ui.widget + +import android.content.Context +import android.graphics.Canvas +import android.graphics.Paint +import android.graphics.Typeface +import android.util.AttributeSet +import android.view.MotionEvent +import android.view.View +import android.view.ViewParent + + +/** + * Created by Max on 2023/12/8 10:43 + * Desc:字母索引 + **/ +class SideBarView : View { + private var selectIndex = 0 + private var textSize = 0f + private var textColor = 0 + private var textSizeFocus = 0f + private var textColorFocus = 0 + + //标记 避免重复调用 + private var isDown = false + + //这里也可以传入数组方式 + private var list = listOf( + "A", "B", "C", "D", "E", "F", "G", "H", "I", + "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", + "W", "X", "Y", "Z", "#" + ) + private var paint = Paint() + + private var listener: Listener? = null + + constructor(context: Context?) : super(context) + constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) + constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) + + constructor( + context: Context?, + attrs: AttributeSet?, + defStyleAttr: Int, + defStyleRes: Int + ) : super(context, attrs, defStyleAttr, defStyleRes) + + fun setTextColor(textColor: Int, focusTextColor: Int = textColor) { + this.textColor = textColor + this.textColorFocus = focusTextColor + } + + fun setTextSize(textSize: Float, focusTextSize: Float = textSize) { + this.textSize = textSize + this.textSizeFocus = focusTextSize + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + paintText(canvas) + } + + private fun paintText(canvas: Canvas?) { + //计算每一个字母的高度,总告诉除以字母集合的高度就可以 + val height: Int = height / list.size + for (i in list.indices) { + if (i == selectIndex) { + paint.color = textColorFocus + paint.textSize = textSizeFocus + } else { + paint.color = textColor + paint.textSize = textSize + } + paint.isAntiAlias = true //设置抗锯齿 + paint.typeface = Typeface.DEFAULT_BOLD + //计算每一个字母x轴 + val paintX = width / 2f - paint.measureText(list[i]) / 2 + //计算每一个字母Y轴 + val paintY = height * i + height + //绘画出来这个TextView + canvas?.drawText(list[i], paintX, paintY.toFloat(), paint) + //画完一个以后重置画笔 + paint.reset() + } + } + + override fun onTouchEvent(event: MotionEvent): Boolean { + val parent: ViewParent? + when (event.action) { + MotionEvent.ACTION_DOWN, MotionEvent.ACTION_MOVE -> { + val index = (event.y / height * list.size).toInt() + if (index >= 0 && index < list.size && selectIndex != index) { + listener?.onSideBarScroll(list[index]) + selectIndex = index + invalidate() + //改变标记状态 + isDown = true + } + parent = getParent() + parent?.requestDisallowInterceptTouchEvent(true) + } + + MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { + listener?.onSideBarScrollEnd() + //改变标记状态 + isDown = false + parent = getParent() + parent?.requestDisallowInterceptTouchEvent(false) + } + } + return true + } + + interface Listener { + //滚动位置 + fun onSideBarScroll(word: String) + + //隐藏提示文本 + fun onSideBarScrollEnd() + } + + fun setListener(listener: Listener?) { + this.listener = listener + } + + /** + * Item滚动 更新侧边栏字母 + * + * @param word 字母 + */ + fun onUpdateSideBarText(word: String?) { + //手指没触摸才调用 + if (!isDown) { + for (i in list.indices) { + if (list[i] == word && selectIndex != i) { + selectIndex = i + invalidate() + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/widget/SimpleAnimListener.java b/app/src/main/java/com/chwl/app/ui/widget/SimpleAnimListener.java new file mode 100644 index 0000000..b7c080a --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/SimpleAnimListener.java @@ -0,0 +1,39 @@ +package com.chwl.app.ui.widget; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.tencent.qgame.animplayer.AnimConfig; +import com.tencent.qgame.animplayer.inter.IAnimListener; + +public class SimpleAnimListener implements IAnimListener { + @Override + public void onFailed(int i, @Nullable String s) { + + } + + @Override + public void onVideoComplete() { + + } + + @Override + public boolean onVideoConfigReady(@NonNull AnimConfig animConfig) { + return true; + } + + @Override + public void onVideoDestroy() { + + } + + @Override + public void onVideoRender(int i, @Nullable AnimConfig animConfig) { + + } + + @Override + public void onVideoStart() { + + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/SquareImageView.java b/app/src/main/java/com/chwl/app/ui/widget/SquareImageView.java new file mode 100644 index 0000000..6af482d --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/SquareImageView.java @@ -0,0 +1,36 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.util.AttributeSet; + +/** + * Created by chenran on 2017/7/24. + */ +public class SquareImageView extends androidx.appcompat.widget.AppCompatImageView { + + + public SquareImageView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + public SquareImageView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public SquareImageView(Context context) { + super(context); + } + + + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + + setMeasuredDimension(getDefaultSize(0, widthMeasureSpec), getDefaultSize(0, heightMeasureSpec)); + + int childWidthSize = getMeasuredWidth(); +// int childHeightSize = getMeasuredHeight(); + + heightMeasureSpec = widthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidthSize, MeasureSpec.EXACTLY); + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/SquareLayout.java b/app/src/main/java/com/chwl/app/ui/widget/SquareLayout.java new file mode 100644 index 0000000..948521f --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/SquareLayout.java @@ -0,0 +1,37 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.RelativeLayout; + +/** + * Created by chenran on 2017/7/24. + */ +public class SquareLayout extends RelativeLayout { + + + public SquareLayout(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + public SquareLayout(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public SquareLayout(Context context) { + super(context); + } + + + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + + setMeasuredDimension(getDefaultSize(0, widthMeasureSpec), getDefaultSize(0, heightMeasureSpec)); + + int childWidthSize = getMeasuredWidth(); + int childHeightSize = getMeasuredHeight(); + + heightMeasureSpec = widthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidthSize, MeasureSpec.EXACTLY); + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/SuperEditText.java b/app/src/main/java/com/chwl/app/ui/widget/SuperEditText.java new file mode 100644 index 0000000..a9abffe --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/SuperEditText.java @@ -0,0 +1,126 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Color; +import android.text.InputType; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.widget.EditText; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.chwl.app.R; + +/** + * Created by huangmeng1 on 2018/6/27. + */ + +public class SuperEditText extends FrameLayout { + private String hint = ""; + private String titleHint = ""; + private TextView tvTitle; + private EditText editText; + private ImageView imageView; + private boolean close; + private boolean isPay; + + private int hintColor; + private int textColor; + + public void setPay(boolean pay) { + isPay = pay; + } + + public SuperEditText(@NonNull Context context) { + this(context, null); + } + + public SuperEditText(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + TypedArray a = context.obtainStyledAttributes(attrs, + R.styleable.SuperEditText, 0, 0); + hint = a.getString(R.styleable.SuperEditText_hint); + titleHint = a.getString(R.styleable.SuperEditText_title_hint); + hintColor = a.getColor(R.styleable.SuperEditText_hint_color, Color.GRAY); + textColor = a.getColor(R.styleable.SuperEditText_text_color, Color.BLACK); + a.recycle(); + init(); + } + + public void setIntegerType() { + editText.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD); + } + + public EditText getEditText() { + return editText; + } + + private void init() { + inflate(getContext(), R.layout.layout_edit_eyes, this); + + tvTitle = findViewById(R.id.tv_title_hint); + tvTitle.setText(titleHint); + + editText = findViewById(R.id.edit); + editText.setHintTextColor(hintColor); + editText.setTextColor(textColor); + + editText.setCursorVisible(false); + editText.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + if (MotionEvent.ACTION_DOWN == event.getAction()) { + editText.setCursorVisible(true);// 再次点击显示光标 + } + return false; + } + }); + imageView = findViewById(R.id.iv_eyes); + editText.setHint(hint); + findViewById(R.id.fl_eyes).setOnClickListener(v -> { + if (isPay) { + if (!close) { + editText.setInputType(InputType.TYPE_CLASS_NUMBER); + imageView.setImageResource(R.drawable.ic_eyes_open); + } else { + setIntegerType(); + imageView.setImageResource(R.drawable.ic_eyes_close); + } + close = !close; + } else { + if (editText.getInputType() == InputType.TYPE_TEXT_VARIATION_PASSWORD) { + editText.setInputType(InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD); + imageView.setImageResource(R.drawable.ic_eyes_open); + } else { + editText.setInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD); + imageView.setImageResource(R.drawable.ic_eyes_close); + } + } + + editText.setSelection(editText.getText().length()); + }); + } + + public String getText() { + return editText.getText() == null ? "" : editText.getText().toString(); + } + + public void setTitleHint(String title) { + titleHint = title; + tvTitle.setText(titleHint); + } + + public void setEditHint(String hint) { + this.hint = hint; + editText.setHint(this.hint); + } + + + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/TextSpannableBuilder.java b/app/src/main/java/com/chwl/app/ui/widget/TextSpannableBuilder.java new file mode 100644 index 0000000..bda7cdb --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/TextSpannableBuilder.java @@ -0,0 +1,196 @@ +package com.chwl.app.ui.widget; + +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.TextUtils; +import android.widget.TextView; + +import com.chwl.app.common.widget.CustomAutoWidthImageSpan; +import com.chwl.app.common.widget.CustomImageSpan; + +public class TextSpannableBuilder { + public SpannableStringBuilder builder; + private TextView textView; + + public TextSpannableBuilder(TextView textView) { + builder = new SpannableStringBuilder(); + this.textView = textView; + } + + /** + * @param text 文字 + * @return -返回一個spannableStringBuilder + */ + public TextSpannableBuilder append(CharSequence text) { + if (TextUtils.isEmpty(text)) return this; + builder.append(text); + return this; + } + + /** + * @param drawable -icon url + * @return -返回一個spannableStringBuilder + */ + public TextSpannableBuilder appendImg(String drawable) { + if (TextUtils.isEmpty(drawable)) return this; + int start = builder.length(); + builder.append("-"); + CustomImageSpan imageSpan = new CustomImageSpan(new ColorDrawable(Color.TRANSPARENT), textView, drawable); + builder.setSpan(imageSpan, start, builder.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + return this; + } + /** + * @param drawable -icon url + * @return -返回一個spannableStringBuilder + */ + public TextSpannableBuilder appendImg(String drawable, Object what) { + if (TextUtils.isEmpty(drawable)) return this; + int start = builder.length(); + builder.append("-"); + CustomImageSpan imageSpan = new CustomImageSpan(new ColorDrawable(Color.TRANSPARENT), textView, drawable); + builder.setSpan(imageSpan, start, builder.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + builder.setSpan(what, start, builder.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + return this; + } + + /** + * @param drawable -icon url + * @param width 寬 + * @param height 高 + * @return -返回一個spannableStringBuilder + */ + public TextSpannableBuilder append(String drawable, int width, int height) { + if (TextUtils.isEmpty(drawable)) return this; + int start = builder.length(); + builder.append("-"); + CustomImageSpan imageSpan = new CustomImageSpan(new ColorDrawable(Color.TRANSPARENT), textView, drawable, width, height); + builder.setSpan(imageSpan, start, builder.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + return this; + } + + public TextSpannableBuilder append(String drawable, int width, int height, Object what) { + if (TextUtils.isEmpty(drawable)) return this; + int start = builder.length(); + builder.append("-"); + CustomImageSpan imageSpan = new CustomImageSpan(new ColorDrawable(Color.TRANSPARENT), textView, drawable, width, height); + builder.setSpan(imageSpan, start, builder.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + builder.setSpan(what, start, builder.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + return this; + } + + /** + * 文本和背景分離的情況 + */ + public TextSpannableBuilder appendBgAndContent(String drawable, String content) { + if (TextUtils.isEmpty(drawable)) return this; + int start = builder.length(); + builder.append("-"); + CustomImageSpan imageSpan = new CustomImageSpan(new ColorDrawable(Color.TRANSPARENT), textView, drawable, content); + builder.setSpan(imageSpan, start, builder.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + return this; + } + + /** + * @param drawable -icon + * @param width 寬 + * @param height 高 + * @return -返回一個spannableStringBuilder + */ + public TextSpannableBuilder append(Drawable drawable, int width, int height) { + if (drawable == null) return this; + drawable.setBounds(0, 0, width, height); + int start = builder.length(); + builder.append("-"); + builder.setSpan(new CustomImageSpan(drawable), start, builder.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + return this; + } + + /** + * @param imgUrl -icon url + * @param height 高 + * @return -返回一個spannableStringBuilder,自適應寬度 + */ + public TextSpannableBuilder append(String imgUrl, int height) { + if (TextUtils.isEmpty(imgUrl)) return this; + int start = builder.length(); + builder.append("-"); + builder.setSpan(new CustomAutoWidthImageSpan(new ColorDrawable(Color.TRANSPARENT), textView, imgUrl, height) + , start, builder.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + return this; + } + + public TextSpannableBuilder append(String imgUrl, int height, Object what) { + if (TextUtils.isEmpty(imgUrl)) return this; + int start = builder.length(); + builder.append("-"); + builder.setSpan(new CustomAutoWidthImageSpan(new ColorDrawable(Color.TRANSPARENT), textView, imgUrl, height) + , start, builder.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + builder.setSpan(what, start, builder.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + return this; + } + + /** + * @param drawable -icon + * @param width 寬 + * @param height 高 + * @return -返回一個spannableStringBuilder + */ + public TextSpannableBuilder append(Drawable drawable, int width, int height, Object... whats) { + if (drawable == null) return this; + try { + drawable.setBounds(0, 0, width, height); + int start = builder.length(); + builder.append("-"); + builder.setSpan(new CustomImageSpan(drawable), start, builder.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + if (whats != null) { + for (int i = 0; i < whats.length; i++) { + builder.setSpan(whats[0], start, builder.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + } + } + } catch (Exception ex) { + + } + return this; + } + + /** + * @param text -文字 + * @param what -span類型 + * @return -返回一個spannableStringBuilder + */ + public TextSpannableBuilder append(CharSequence text, Object what) { + if (TextUtils.isEmpty(text)) return this; + int start = builder.length(); + builder.append(text); + builder.setSpan(what, start, builder.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + return this; + } + + /** + * 支持多個spannable 對同一段文字修改 + * + * @param text + * @param what + * @return + */ + public TextSpannableBuilder append(CharSequence text, Object... what) { + if (TextUtils.isEmpty(text)) return this; + int start = builder.length(); + builder.append(text); + for (int i = 0; i < what.length; i++) { + Object o = what[i]; + if (o == null) { + continue; + } + builder.setSpan(what[i], start, builder.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + } + return this; + } + + public SpannableStringBuilder build() { + return builder; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/TextWatcherSimple.java b/app/src/main/java/com/chwl/app/ui/widget/TextWatcherSimple.java new file mode 100644 index 0000000..ed32133 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/TextWatcherSimple.java @@ -0,0 +1,20 @@ +package com.chwl.app.ui.widget; + +import android.text.TextWatcher; + +/** + * create by lvzebiao @2019/12/1 + */ +public abstract class TextWatcherSimple implements 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) { + + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/TopRoundLinearLayout.java b/app/src/main/java/com/chwl/app/ui/widget/TopRoundLinearLayout.java new file mode 100644 index 0000000..4c38fc8 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/TopRoundLinearLayout.java @@ -0,0 +1,66 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Path; +import android.graphics.RectF; +import android.util.AttributeSet; +import android.widget.LinearLayout; + +import com.netease.nim.uikit.common.util.sys.ScreenUtil; + +/** + * 顶部圆角的LinearLayout,用户半屏的web view界面 + * 注意需要设置背景才有效,没有背景ViewGroup不会调用draw方法 + */ + +public class TopRoundLinearLayout extends LinearLayout { + + private Path mPath; + private int mRadius; + private int mWidth; + private int mHeight; + private int mLastRadius; + + public TopRoundLinearLayout(Context context) { + super(context); + init(); + } + + public TopRoundLinearLayout(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + private void init() { + mPath = new Path(); + mPath.setFillType(Path.FillType.EVEN_ODD); + mRadius = ScreenUtil.dip2px(16); + } + + public void setRadius(int mRadius) { + this.mRadius = mRadius; + } + + private void checkPathChanged() { + if (getWidth() == mWidth && getHeight() == mHeight && mLastRadius == mRadius) { + return; + } + mWidth = getWidth(); + mHeight = getHeight(); + mLastRadius = mRadius; + mPath.reset(); + mPath.addRoundRect(new RectF(0, 0, mWidth, mHeight), + new float[]{mRadius, mRadius, mRadius, mRadius, 0, 0, 0, 0}, + Path.Direction.CW); + } + + @Override + public void draw(Canvas canvas) { + int saveCount = canvas.save(); + checkPathChanged(); + canvas.clipPath(mPath); + super.draw(canvas); + canvas.restoreToCount(saveCount); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/widget/UserInfoDialog.java b/app/src/main/java/com/chwl/app/ui/widget/UserInfoDialog.java new file mode 100644 index 0000000..733abe3 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/UserInfoDialog.java @@ -0,0 +1,1384 @@ +package com.chwl.app.ui.widget; + +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_DRAGON_BAR; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_DRAGON_BAR_CANCEL; +import static com.chwl.core.manager.RoomEvent.DRAGON_BAR_CANCEL; +import static com.chwl.library.utils.ResUtil.getString; + +import android.annotation.SuppressLint; +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatDialog; +import androidx.recyclerview.widget.LinearLayoutManager; + +import com.chwl.app.R; +import com.chwl.app.UIHelper; +import com.chwl.app.avroom.ButtonItemFactory; +import com.chwl.app.avroom.activity.AVRoomActivity; +import com.chwl.app.avroom.giftvalue.GiftValueDialogUiHelper; +import com.chwl.app.avroom.widget.ViewItem; +import com.chwl.app.base.BaseDialogFragment; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.app.databinding.DialogUserInfoBinding; +import com.chwl.app.room_chat.fragment.RoomMsgTabFragment; +import com.chwl.app.ui.im.avtivity.NimP2PMessageActivity; +import com.chwl.app.ui.user.activity.UserInfoActivity; +import com.chwl.app.ui.user.adapter.SkillPicsAdapter; +import com.chwl.app.ui.user.decorationsend.UserInfoSkillDecoration; +import com.chwl.app.ui.utils.ImageLoadKt; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.app.ui.utils.VipUtil; +import com.chwl.app.utils.AvatarHelper; +import com.chwl.app.utils.RegexUtil; +import com.chwl.app.vip.util.VipHelper; +import com.chwl.core.Constants; +import com.chwl.core.XConstants; +import com.chwl.core.auth.AuthModel; +import com.chwl.core.bean.RoomMicInfo; +import com.chwl.core.bean.RoomQueueInfo; +import com.chwl.core.decoration.headwear.bean.HeadWearInfo; +import com.chwl.core.family.bean.FamilyInfo; +import com.chwl.core.family.model.FamilyModel; +import com.chwl.core.im.custom.bean.FaceAttachment; +import com.chwl.core.kick.KickModel; +import com.chwl.core.level.UserLevelVo; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.manager.IMNetEaseManager; +import com.chwl.core.manager.RoomEvent; +import com.chwl.core.market_verify.MarketVerifyModel; +import com.chwl.core.noble.NobleUtil; +import com.chwl.core.praise.PraiseModel; +import com.chwl.core.room.bean.RoomInfo; +import com.chwl.core.room.bean.RoomResult; +import com.chwl.core.room.dragonball.DragonBallModel; +import com.chwl.core.room.event.DatingSelectUserEvent; +import com.chwl.core.room.event.RoomAtEvent; +import com.chwl.core.room.face.FaceReceiveInfo; +import com.chwl.core.room.giftvalue.GiftValueModel; +import com.chwl.core.room.giftvalue.bean.RoomGiftValue; +import com.chwl.core.room.giftvalue.helper.GiftValueMrg; +import com.chwl.core.room.model.AvRoomModel; +import com.chwl.core.room.model.HomePartyModel; +import com.chwl.core.super_admin.model.SuperAdminModel; +import com.chwl.core.super_admin.util.SuperAdminUtil; +import com.chwl.core.user.UserModel; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.core.utils.CoreLogger; +import com.chwl.core.utils.StringFormatUtils; +import com.chwl.core.utils.net.BeanObserver; +import com.chwl.core.utils.net.DontWarnObserver; +import com.chwl.core.utils.net.RxHelper; +import com.chwl.core.vip.bean.UserVipInfo; +import com.chwl.library.common.util.OtherExtKt; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; +import com.chwl.library.utils.config.BasicConfig; +import com.hjq.toast.ToastUtils; +import com.netease.nimlib.sdk.chatroom.ChatRoomMessageBuilder; +import com.netease.nimlib.sdk.chatroom.model.ChatRoomKickOutEvent; +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage; +import com.tencent.qgame.animplayer.AnimConfig; +import com.tencent.qgame.animplayer.inter.IAnimListener; +import com.tencent.qgame.animplayer.util.ScaleType; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import io.reactivex.Single; +import io.reactivex.SingleObserver; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.disposables.Disposable; + +/** + * 替代原来的框架,用来替代UserInfoDialog的 + * 现在简单来说在view层使用model,,,,,以后可以改过来 + * + * @author xiaoyu + * @date 2017/12/13 + */ + +public class UserInfoDialog extends AppCompatDialog implements View.OnClickListener { + private Context context; + private long uid; + private boolean isAttention; + private UserInfo userInfo; + + private DialogUserInfoBinding mBinding; + + private long myUid; + private Disposable subscribe; + private String topBg = ""; + + private CompositeDisposable mCompositeDisposable; + private List buttons; + private boolean isMySelf; + + private HomePartyModel homePartyModel; + private boolean isInRoom; // true:房间内打开 false:房间外打开 + private GiftDialog.OnGiftDialogBtnClickListener giftDialogBtnClickListener; + + private SuperAdminModel mSuperAdminModel; + //找到他处理 + private ViewItem findHimView; + + private SkillPicsAdapter picsAdapter; + + private boolean mIsNeedGiftItem = true; + + + private UserInfoDialog(Context context, UserInfo userInfo, long uid, List buttons, boolean isInRoom, GiftDialog.OnGiftDialogBtnClickListener listener) { + super(context, R.style.ErbanUserInfoDialog); + this.context = context; + this.uid = uid; + this.buttons = buttons; + this.userInfo = userInfo; + isMySelf = (this.uid == AuthModel.get().getCurrentUid()); + homePartyModel = new HomePartyModel(); + mSuperAdminModel = new SuperAdminModel(); + this.isInRoom = isInRoom; + this.giftDialogBtnClickListener = listener; + } + private UserInfoDialog(Context context, UserInfo userInfo, long uid, List buttons, boolean isInRoom, GiftDialog.OnGiftDialogBtnClickListener listener,boolean isNeedRoomItem) { + super(context, R.style.ErbanUserInfoDialog); + this.context = context; + this.uid = uid; + this.buttons = buttons; + this.userInfo = userInfo; + isMySelf = (this.uid == AuthModel.get().getCurrentUid()); + homePartyModel = new HomePartyModel(); + mSuperAdminModel = new SuperAdminModel(); + this.isInRoom = isInRoom; + this.giftDialogBtnClickListener = listener; + this.mIsNeedGiftItem = isNeedRoomItem; + } + + public static void showNewUserInfoDialog(Context context, long uid) { + showNewUserInfoDialog(context, uid, true, true, true, null); + } + + @SuppressLint("CheckResult") + public static void showNewUserInfoDialog(Context context, + long uid, + boolean isInRoom, + boolean isNeedGiftItem, + boolean isNeedRoomItem, + GiftDialog.OnGiftDialogBtnClickListener listener) { + LoadingDialog loadingDialog = new LoadingDialog(context); + loadingDialog.show(); + UserModel.get().getUserInfoFromServerUpdate(uid, false) + .compose(RxHelper.bindContext(context)) + .subscribe(userInfo -> { + List list = ButtonItemFactory.createCommonButtonItems( + context, + userInfo, + uid, + isNeedGiftItem, + isNeedRoomItem, + isInRoom, + listener + ); + new UserInfoDialog(context, userInfo, uid, list, isInRoom, listener,isNeedGiftItem).show(); + loadingDialog.dismiss(); + }, throwable -> { + SingleToastUtil.showToast(throwable.getMessage()); + loadingDialog.dismiss(); + }); + + + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + EventBus.getDefault().register(this); + mCompositeDisposable = new CompositeDisposable(); + mBinding = DialogUserInfoBinding.inflate(LayoutInflater.from(context)); + setContentView(mBinding.getRoot()); + setCanceledOnTouchOutside(true); + //设置全屏 + Window window = getWindow(); + if (window != null) { + WindowManager.LayoutParams params = window.getAttributes(); + params.width = WindowManager.LayoutParams.MATCH_PARENT; + params.height = WindowManager.LayoutParams.WRAP_CONTENT; + params.gravity = Gravity.BOTTOM; + + } + + + + + myUid = AuthModel.get().getCurrentUid(); + + mBinding.ivUserCardWearMp4.setScaleType(ScaleType.CENTER_CROP); + mBinding.ivUserCardWearMp4.setLoop(Integer.MAX_VALUE); + mBinding.ivUserCardWearMp4.setAnimListener(new IAnimListener() { + @Override + public boolean onVideoConfigReady(@NonNull AnimConfig animConfig) { + return true; + } + + @Override + public void onVideoStart() { + } + + @Override + public void onVideoRender(int i, @Nullable AnimConfig animConfig) { + } + + @Override + public void onVideoComplete() { + } + + @Override + public void onVideoDestroy() { + } + + @Override + public void onFailed(int i, @Nullable String s) { + mBinding.ivUserCardWear.post(() -> { + ImageLoadUtils.loadImage(context, userInfo.getUserInfoCardPic(), mBinding.ivUserCardWear); + }); + } + }); + + + picsAdapter = new SkillPicsAdapter(); + mBinding.recyclerviewSkillCard.setAdapter(picsAdapter); + mBinding.recyclerviewSkillCard.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)); + mBinding.recyclerviewSkillCard.addItemDecoration(new UserInfoSkillDecoration(context, 8)); + + + loadButtons(); + subscribe = IMNetEaseManager.get().getChatRoomEventObservable().subscribe(this::onReceiveRoomEvent); + initAttentData(); + initDatingData(); + updateView(); + + + if (isMySelf) { + mBinding.tvReport.setVisibility(View.GONE); + } else { + mBinding.tvReport.setVisibility(View.VISIBLE); + mBinding.tvReport.setOnClickListener(this); + } + + mBinding.flAvatarLayout.setOnClickListener(this); + mBinding.gift.setOnClickListener(this); + mBinding.send.setOnClickListener(this); + mBinding.aite.setOnClickListener(this); + mBinding.follow.setOnClickListener(this); + + + if (mIsNeedGiftItem) { + if (!SuperAdminUtil.isSuperAdmin()) { + mBinding.gift.setVisibility(View.VISIBLE); + } + } + + + if (!isMySelf){ + mBinding.send.setVisibility(View.VISIBLE); + mBinding.follow.setVisibility(View.VISIBLE); + + if (!SuperAdminUtil.isSuperAdmin()) { + mBinding.aite.setVisibility(View.VISIBLE); + } + } + + mBinding.ivUserCardWearMp4.post(() -> { + int width = (int) (mBinding.ivUserCardWearMp4.getWidth() / 0.8636); + OtherExtKt.setViewWH(mBinding.ivUserCardWearMp4,width,mBinding.ivUserCardWearMp4.getHeight(),false); + }); + + mBinding.userCardWearLayout.post(() -> { + int width = (int) (mBinding.userCardWearLayout.getWidth() / 0.8636); +// int width = mBinding.userCardWearLayout.getWidth(); +// int height = (int) (mBinding.userCardWearLayout.getHeight() / 0.6111); + int height = mBinding.userCardWearLayout.getHeight(); + OtherExtKt.setViewWH(mBinding.userCardWearLayout,width,height,false); + }); + + + } + + private void initAttentData() { + if (isMySelf) { + mBinding.tvFamilyNameLabel.setText(mBinding.tvFamilyNameLabel.getText().toString().replace("TA", getString(R.string.ui_widget_userinfodialog_01))); + } else { + Disposable disposable = PraiseModel.get().isPraised(myUid, uid).subscribe(aBoolean -> { + isAttention = aBoolean; + updateAttentView(); + mBinding.follow.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + toAttent(); + } + }); + }); + mCompositeDisposable.add(disposable); + } + } + + private void initDatingData() { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo != null && + AvRoomDataManager.get().isDatingMode() && + RoomInfo.DATING_STATE_SELECT.equals(roomInfo.getBlindDateState()) && + AvRoomDataManager.get().isOwnerOnMic() && + !AvRoomDataManager.get().isSelectUser(myUid) && + AvRoomDataManager.get().isOnMic(uid) && + myUid != uid && + !AvRoomDataManager.get().isPreside(myUid) && + !AvRoomDataManager.get().isPreside(uid)) { + mBinding.tvSelectHim.setVisibility(View.VISIBLE); + mBinding.tvSelectHim.setOnClickListener(v -> { + int micPosition = AvRoomDataManager.get().getMicPosition(uid); + if (micPosition == Integer.MIN_VALUE) { + SingleToastUtil.showToast(getString(R.string.ui_widget_userinfodialog_02)); + } else { + new DatingSelectDialog(micPosition, uid, myUid, roomInfo.getUid()).show(context); + } + } + ); + } else { + mBinding.tvSelectHim.setVisibility(View.GONE); + } + } + + + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onDatingSelectUserEvent(DatingSelectUserEvent event) { + try { + dismiss(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void updateAttentView() { + mBinding.follow.setImageResource(isAttention ? R.drawable.icon_dialog_cancel_attent : R.drawable.icon_dialog_attent); + } + + private void loadButtons() { + if (buttons == null) { + buttons = new ArrayList<>(); + } + List items = addMainAndMicBottons(); + if (items != null) { + buttons.addAll(items); + } + addViewItems(buttons); + } + + private void addViewItems(List buttons) { + if (ListUtils.isListEmpty(buttons)) { + mBinding.flexbox.setVisibility(View.GONE); + mBinding.flexboxLine.setVisibility(View.GONE); + return; + } + mBinding.flexbox.post(new Runnable() { + @Override + public void run() { +// int dialogWidth = flexbox.getMeasuredWidth() == 0 ? ScreenUtil.dip2px(285) : flexbox.getMeasuredWidth(); + int dialogWidth = mBinding.flexbox.getWidth(); + + mBinding.flexbox.removeAllViews(); + //底部item,不添加到网格 + List bottomList = new ArrayList<>(); + for (int i = 0; i < buttons.size(); i++) { + ViewItem buttonItem = buttons.get(i); + if (buttonItem.mButtonType == ViewItem.BUTTON_TYPE_NORMAL) { + View item = LayoutInflater.from(getContext()).inflate(R.layout.dialog_user_card_item_new, mBinding.flexbox, false); +// item.getLayoutParams().width = OtherExtKt.toDP(38); +// item.getLayoutParams().height = OtherExtKt.toDP(38); + ImageView imageView = item.findViewById(R.id.image); + imageView.setImageResource(buttonItem.imgRes); + if (buttonItem.isFindTa) { + //找到他处理 + if (!isMySelf) { + findHimView = buttonItem; + } + } else { + item.setOnClickListener(v -> { + buttonItem.mClickListener.onClick(); + if (!buttonItem.noDissmis) { + dismiss(); + } + }); + mBinding.flexbox.addView(item); + } + } else if (buttonItem.mButtonType == ViewItem.BUTTON_TYPE_USER_CAR_BOTTOM) { + bottomList.add(buttonItem); + } + } + if (mBinding.flexbox.getChildCount() == 0) { + mBinding.flexbox.setVisibility(View.GONE); + mBinding.flexboxLine.setVisibility(View.GONE); + } else { + mBinding.flexbox.setVisibility(View.VISIBLE); + mBinding.flexboxLine.setVisibility(View.VISIBLE); + + //超出屏幕時 不居中 + mBinding.flexboxLine.post(() -> { + mBinding.flexbox.post(() -> { + int lineWidth = mBinding.flexboxLine.getWidth(); + int boxWidth = mBinding.flexbox.getWidth(); + if (boxWidth > lineWidth) { + try { + FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mBinding.flexbox.getLayoutParams(); + lp.gravity = Gravity.START; + mBinding.flexbox.setLayoutParams(lp); + } catch (Exception e) { + + } + } + }); + }); + } + } + }); + + } + + /** + * 添加主页麦位操作的button + */ + private List addMainAndMicBottons() { + if (!isInRoom) { + return null; + } + List bottomList = getMicRelativeButtons(String.valueOf(uid)); + //如果用户在麦上,而且登录用户是管理员,则显示此按钮 + if (AvRoomDataManager.get().isShowGiftValue() + && AvRoomDataManager.get().isManager()) { + + boolean onMic = AvRoomDataManager.get().isOnMic(uid); + boolean leaveMode = AvRoomDataManager.get().isLeaveMode() && AvRoomDataManager.get().isRoomOwner(uid); + + if (onMic || leaveMode) { + //个播房只有房主坑位有魅力值 + if (!SuperAdminUtil.isSuperAdmin() && + (!AvRoomDataManager.get().isSingleRoom() || AvRoomDataManager.get().isRoomOwner(uid))) { + bottomList.add(createClearGiftValueItem()); + } + } + } + return bottomList; + } + + private void onReceiveRoomEvent(RoomEvent roomEvent) { + if (roomEvent == null || roomEvent.getEvent() == RoomEvent.NONE) return; + int event = roomEvent.getEvent(); + if (event == RoomEvent.FOLLOW) { + onFollow(roomEvent.isSuccess()); + } else if (event == RoomEvent.UNFOLLOW) { + onUnFollow(roomEvent.isSuccess()); + } else if (RoomEvent.KICK_OUT_ROOM == event) { + onKickMember(roomEvent.getReason()); + } + } + + private void onKickMember(ChatRoomKickOutEvent reason) { + if (reason == null) return; + ChatRoomKickOutEvent.ChatRoomKickOutReason reasonReason = reason.getReason(); + if (reasonReason == ChatRoomKickOutEvent.ChatRoomKickOutReason.CHAT_ROOM_INVALID) { + dismiss(); + } + } + + private void updateView() { + if (userInfo != null) { + mBinding.ivUserOfficial.setVisibility(userInfo.isOfficial() ? View.VISIBLE : View.GONE); + mBinding.ivNewUser.setVisibility(userInfo.isNewUser() ? View.VISIBLE : View.GONE); + mBinding.ivNewUser.setImageResource(userInfo.isFromSayHelloChannel() ? R.drawable.ic_new_user_hello : R.drawable.ic_new_user); + mBinding.ivGoodNumber.setVisibility(userInfo.isHasPrettyErbanNo() ? View.VISIBLE : View.GONE); + + // 这个方法能让图片不失真 + ImageLoadUtils.loadAvatar(context, userInfo.getAvatar(), mBinding.avatar); + mBinding.nick.setText(RegexUtil.getPrintableString(userInfo.getNick())); + mBinding.tvErbanId.setText(getString(R.string.ui_widget_userinfodialog_06) + userInfo.getErbanNo()); + mBinding.tvErbanId.setOnLongClickListener(view -> { + copyName(); + return true; + }); + mBinding.ivCopy.setOnClickListener(view -> copyName()); + mBinding.tvGenderAge.setBirthDay(userInfo.getBirth()); + mBinding.tvGenderAge.setGender(userInfo.getGender()); + + //1.0.21版本 隐藏 vip icon +// VipHelper.loadVipIcon(mBinding.ivVipIcon, userInfo.getUserVipInfoVO()); + + //设置家族 + if (FamilyInfo.NO_FAMILY_ID.equals(userInfo.getFamilyId()) + || TextUtils.isEmpty(userInfo.getFamilyId()) + || MarketVerifyModel.get().isMarketChecking()) { + mBinding.tvFamilyName.setText(context.getResources().getString(R.string.empty_family_text)); + } else { + loadSimpleFamilyInfo(userInfo.getFamilyId()); + } + + UserLevelVo userLevelVo = userInfo.getUserLevelVo(); + mBinding.ivUserLevel.setVisibility(userLevelVo == null ? View.GONE : View.VISIBLE); + mBinding.ivUserCharm.setVisibility(View.GONE); + if (userLevelVo != null) { + mBinding.ivUserLevel.setVisibility(TextUtils.isEmpty(userLevelVo.getExperUrl()) ? View.GONE : View.VISIBLE); + if (!TextUtils.isEmpty(userLevelVo.getExperUrl())) { + ImageLoadUtils.loadImage(context, userLevelVo.getExperUrl(), mBinding.ivUserLevel); + } + if (!TextUtils.isEmpty(userLevelVo.getCharmUrl())) { + mBinding.ivUserCharm.setVisibility(View.VISIBLE); + ImageLoadUtils.loadImage(context, userLevelVo.getCharmUrl(), mBinding.ivUserCharm); + } + } + + //Vip铭牌 + if (userInfo.getUserVipInfoVO() != null && !TextUtils.isEmpty(userInfo.getUserVipInfoVO().getNameplateUrl())) { + setNamePlateVip(userInfo.getUserVipInfoVO().getNameplateUrl()); + } else { + setNamePlateVip(null); + } + + //工会长铭牌 + if (userInfo.getGuildNameplateIcon() != null && !TextUtils.isEmpty(userInfo.getGuildNameplateIcon())) { + setNameplateGuild(userInfo.getGuildNameplateIcon()); + } else { + setNameplateGuild(null); + } + + //铭牌 + if (!TextUtils.isEmpty(userInfo.getNameplatePic()) && !TextUtils.isEmpty(userInfo.getNameplateWord())) { + setNamePlate(userInfo.getNameplatePic(), userInfo.getNameplateWord()); + } else { + setNamePlate(null, null); + } + // 改变贵族 + updateNobleView(); + UserInfo.NamePlate namePlate = userInfo.getNameplate(); + if (namePlate != null) { + setOfficialMask(namePlate.getFixedWord(), namePlate.getIconPic()); + } else { + setOfficialMask(null, null); + } + + if (null != findHimView) { + //获取用户房间信息 + AvRoomModel.get().getUserRoom(userInfo.getUid()) + .subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) { + mCompositeDisposable.add(d); + } + + @Override + public void onSuccess(RoomResult roomResult) { + if (!roomResult.isSuccess()) { +// Toast.makeText(context, roomResult.getMessage(), Toast.LENGTH_SHORT).show(); + SingleToastUtil.showToastShort(roomResult.getMessage()); + return; + } + if (roomResult.getData() != null && roomResult.getData().getUid() != 0) { + int dialogWidth = context.getResources().getDimensionPixelOffset( + R.dimen.dp_room_user_dialog_width); + int itemWidth = dialogWidth / 4; + View item = LayoutInflater.from(getContext()).inflate(findHimView.resourceID, mBinding.flexbox, false); + item.getLayoutParams().width = itemWidth; + TextView textView = item.findViewById(R.id.text); + textView.setText(findHimView.mText); + ImageView imageView = item.findViewById(R.id.image); + imageView.setImageResource(findHimView.imgRes); + item.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + AVRoomActivity.start(context, roomResult.getData().getUid()); + } + }); + mBinding.flexbox.addView(item); + + } + + } + + @Override + public void onError(Throwable e) { +// Toast.makeText(context, ResUtil.getString(R.string.ui_widget_userinfodialog_08), Toast.LENGTH_SHORT).show(); + SingleToastUtil.showToastShort(getString(R.string.ui_widget_userinfodialog_09)); + } + }); + } + if (userInfo.getAbsCardPics() == null) { + mBinding.recyclerviewSkillCard.setVisibility(View.GONE); + } else { + mBinding.recyclerviewSkillCard.setVisibility(View.VISIBLE); + picsAdapter.setNewData(userInfo.getAbsCardPics()); + } + } + } + + private void copyName() { + try { + ClipboardManager cm = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); + cm.setPrimaryClip(ClipData.newPlainText("text", String.valueOf(userInfo.getErbanNo()))); + SingleToastUtil.showToast(getString(R.string.have_copy)); + } catch (Exception e) { + CoreLogger.info("copyText", e.toString()); + SingleToastUtil.showToast(e.toString()); + } + } + + private void setNamePlate(String nameplatePic, String nameplateWord) { + if (!TextUtils.isEmpty(nameplateWord) && !TextUtils.isEmpty(nameplatePic)) { + mBinding.inNameplate.getRoot().setVisibility(View.VISIBLE); + mBinding.inNameplate.tvOfficialMask.setText(nameplateWord); + ImageLoadUtils.loadImage(context, nameplatePic, mBinding.inNameplate.ivOfficialMask); + } else { + mBinding.inNameplate.getRoot().setVisibility(View.GONE); + } + } + + private void setNamePlateVip(String nameplatePic) { + if (!TextUtils.isEmpty(nameplatePic)) { + mBinding.inNameplateVip.getRoot().setVisibility(View.VISIBLE); + ImageLoadUtils.loadImage(context, nameplatePic, mBinding.inNameplateVip.ivOfficialMask); + } else { + mBinding.inNameplateVip.getRoot().setVisibility(View.GONE); + } + } + + private void setNameplateGuild(String nameplatePic) { + if (!TextUtils.isEmpty(nameplatePic)) { + mBinding.inNameplateGuild.getRoot().setVisibility(View.VISIBLE); + ImageLoadUtils.loadImage(context, nameplatePic, mBinding.inNameplateGuild.ivOfficialMask); + } else { + mBinding.inNameplateGuild.getRoot().setVisibility(View.GONE); + } + } + + private void setOfficialMask(String name, String icon) { + if (!TextUtils.isEmpty(name) && !TextUtils.isEmpty(icon)) { + mBinding.inOfficialMask.setVisibility(View.VISIBLE); + mBinding.tvOfficialMask.setText(name); + NobleUtil.loadResource(icon, mBinding.ivOfficialMask); + } else { + mBinding.inOfficialMask.setVisibility(View.GONE); + } + } + + private void loadSimpleFamilyInfo(String familyId) { + FamilyModel.Instance().loadFamilySimpleInfo( + familyId + ) + .subscribe(new SingleObserver() { + @Override + public void onSubscribe(Disposable d) { + mCompositeDisposable.add(d); + } + + @Override + public void onSuccess(FamilyInfo familyInfo) { + mBinding.tvFamilyName.setText(familyInfo.getFamilyName()); + } + + @Override + public void onError(Throwable e) { + SingleToastUtil.showToastShort(e.getMessage()); + } + }); + } + + private void updateNobleView() { + if (userInfo != null) { + // 防止访问数据库和网络同时刷新出现图标跳动 + // NobleInfo nobleInfo = userInfo.getNobleInfo(); + UserVipInfo vipInfo = userInfo.getUserVipInfoVO(); + HeadWearInfo userHeadwear = userInfo.getUserHeadwear(); + boolean havaHead = false; + // 设置普通人 + if (userHeadwear != null) { + String avatarFrame = userHeadwear.getFirstUrl(); + if (!TextUtils.isEmpty(avatarFrame)) { + havaHead = true; + AvatarHelper.loadAvatarFrame(mBinding.ivAvatarHeadWear, avatarFrame, userHeadwear.getType()); + } + } + + //资料卡装扮 + mBinding.transitionMask.setVisibility(View.INVISIBLE); + mBinding.ivAvatarBg.setVisibility(View.INVISIBLE); + + if (userInfo.getInfoCardVo() != null) { + VipUtil.INSTANCE.setUserBg(userInfo.getInfoCardVo(), mBinding.userCardWearLayout, callBack -> { + return null; + }); + } else { + + //资料卡装扮 + if (!TextUtils.isEmpty(userInfo.getUserInfoCardPic())) { + mBinding.ivUserCardWearMp4.post(() -> { + ImageLoadKt.loadAnim2(mBinding.ivUserCardWearMp4, userInfo.getUserInfoCardPic(), false, aBoolean -> { + if (!aBoolean) { + ImageLoadUtils.loadImage(context, userInfo.getUserInfoCardPic(), mBinding.ivUserCardWear); + } + return null; + }); + }); + } else { + mBinding.ivUserCardWear.setImageDrawable(null); + mBinding.ivUserCardWearMp4.setVisibility(View.INVISIBLE); + } + + if (vipInfo != null && !vipInfo.getUserCardBG().isEmpty()) { + mBinding.ivAvatarBg.setScaleType(ImageView.ScaleType.FIT_XY); + ImageLoadUtils.loadImage( + context, + vipInfo.getUserCardBG().replace("\n", ""), + mBinding.ivAvatarBg, + R.drawable.transparent_draw + ); + mBinding.ivAvatarBg.setVisibility(View.VISIBLE); + mBinding.transitionMask.setVisibility(View.VISIBLE); + } else { + mBinding.transitionMask.setVisibility(View.INVISIBLE); + mBinding.ivAvatarBg.setVisibility(View.INVISIBLE); + } + } + + } + } + + + @Override + public void onDetachedFromWindow() { + ; + super.onDetachedFromWindow(); + if (subscribe != null) { + subscribe.dispose(); + subscribe = null; + } + if (mCompositeDisposable != null) { + mCompositeDisposable.dispose(); + mCompositeDisposable = null; + } + EventBus.getDefault().unregister(this); + } + + + @Override + public void onClick(View v) { + if (v.getId() == mBinding.tvReport.getId()) { + UIHelper.showReportPage(context, uid, XConstants.REPORT_TYPE_USERCARD); + dismiss(); + } else if (v.getId() == mBinding.flAvatarLayout.getId()) { + UserInfoActivity.Companion.start(context, uid); + dismiss(); + } else if (v.getId() == mBinding.gift.getId()) { + GiftDialog dialog = new GiftDialog(context, uid, isInRoom, false, true); + if (giftDialogBtnClickListener != null) { + dialog.setGiftDialogBtnClickListener(giftDialogBtnClickListener); + } + dialog.show(); + dismiss(); + } else if (v.getId() == mBinding.send.getId()) { + if (isInRoom) { + RoomMsgTabFragment.Companion.newInstance(String.valueOf(uid)).show(context); + } else { + NimP2PMessageActivity.start(context, String.valueOf(uid)); + } + } else if (v.getId() == mBinding.aite.getId()) { + //@他处理 + if (!isMySelf) { + if (userInfo != null) { + dismiss(); + EventBus.getDefault().post(new RoomAtEvent(String.valueOf(userInfo.getUid()), userInfo.getNick())); + } else { + SingleToastUtil.showToast(getString(R.string.ui_widget_userinfodialog_05)); + } + } + } else if (v.getId() == mBinding.follow.getId()) { + toAttent(); + } + } + + /** + * 关注or取消 + */ + private void toAttent() { + if (userInfo == null) return; + + //资料卡片不允许取消关注 + if (isAttention) { + return; + } + PraiseModel.get().praise(userInfo.getUid(), !isAttention) + .subscribe(new BeanObserver() { + @Override + public void onErrorMsg(String error) { + SingleToastUtil.showToast(error); + } + + @Override + public void onSuccess(String s) { + if (!isAttention) { + onFollow(true); + } else { + onUnFollow(true); + } + } + }); + } + + @SuppressLint("CheckResult") + private void onFollow(boolean success) { + if (success) { + isAttention = true; + updateAttentView(); + SingleToastUtil.showToast( + BasicConfig.INSTANCE.getAppContext().getResources().getString(R.string.fan_success)); + // 更新粉丝数量 + UserModel.get().getUserInfo(uid).subscribe(); + } + } + + private void onUnFollow(boolean success) { + if (success) { + isAttention = false; + updateAttentView(); + UserModel.get().getUserInfo(uid).subscribe(); + } + } + + /** + * 不去判断用户在不在房间 + * 麦位操作相关的一些操作,比如上下麦 + */ + public List getMicRelativeButtons(String account) { + List buttonItems = new ArrayList<>(); + final RoomInfo currentRoom = AvRoomDataManager.get().mCurrentRoomInfo; + if (currentRoom == null) return buttonItems; + //根据账号查询在哪个坑位 + int micPosition = AvRoomDataManager.get().getMicPosition(account); + // 判断在不在麦上 + RoomQueueInfo roomQueueInfo = AvRoomDataManager.get().getRoomQueueMemberInfoByMicPosition(micPosition); + RoomMicInfo roomMicInfo = null; + if (roomQueueInfo == null) { + + } else { + roomMicInfo = roomQueueInfo.mRoomMicInfo; + } + + String currentUid = String.valueOf(AuthModel.get().getCurrentUid()); + boolean isMySelf = Objects.equals(currentUid, account); + boolean isTargetRoomAdmin = AvRoomDataManager.get().isRoomAdmin(account); + boolean isTargetRoomOwner = AvRoomDataManager.get().isRoomOwner(account); + //目标用户是否是管理,(房主或者管理员) + boolean isTargetManager = isTargetRoomOwner || isTargetRoomAdmin; + boolean isTargetOnMic = AvRoomDataManager.get().isOnMic(account); + boolean isTargetVip = AvRoomDataManager.get().isDatingVip(StringFormatUtils.toLong(account)) || + AvRoomDataManager.get().isDatingVipMic(micPosition); + //超管逻辑 + if (SuperAdminUtil.isSuperAdmin()) { + if (isMySelf) { + mBinding.gift.setVisibility(View.VISIBLE); + } + if (isTargetOnMic) { + if (isMySelf) { + buttonItems.add(createDownMicItem()); + } else { + //如果是cp房,不能抱房主下麦 + if (AvRoomDataManager.get().isCpRoom()) { + if (!isTargetRoomOwner) { + buttonItems.add(createKickMicItem()); + } + } else { + buttonItems.add(createKickMicItem()); + } + + } + } + //锁麦 + if (roomMicInfo != null) { + if (!roomMicInfo.isMicMute()) { + buttonItems.add(createBanMicItem(micPosition)); + } + if (!roomMicInfo.isMicLock() && !isTargetVip) { + buttonItems.add(createLockMicItem(micPosition)); + } + } + return buttonItems; + } + + if (AvRoomDataManager.get().isRoomOwner()) { + //房主操作 + if (isMySelf) { + //开闭麦 + if (micPosition != AvRoomDataManager.POSITON_NOT_ON_MIC) { + if (roomMicInfo != null) { + if (roomMicInfo.isMicMute()) { + buttonItems.add(createOpenMicItem(micPosition)); + } else { + buttonItems.add(createBanMicItem(micPosition)); + } + } + } + if (isTargetOnMic) { + if (!AvRoomDataManager.get().isCpRoom() && !AvRoomDataManager.get().isSingleRoom()) { + buttonItems.add(createDownMicItem()); + } + } else { + //支持自己抱自己上麦, 离开模式下不可上麦 + if (!AvRoomDataManager.get().isLeaveMode()) { + handleInviteMicItem(buttonItems); + } + } + //解锁麦 + if (micPosition != AvRoomDataManager.POSITON_NOT_ON_MIC) { + if (roomMicInfo != null && !AvRoomDataManager.get().isSingleRoom()) { + if (roomMicInfo.isMicLock()) { + buttonItems.add(createUnLockMicItem(micPosition)); + } else { + if (!isTargetVip) { + buttonItems.add(createLockMicItem(micPosition)); + } + } + } + } + } else { + //开闭麦 + if (micPosition != AvRoomDataManager.POSITON_NOT_ON_MIC) { + if (roomMicInfo != null) { + if (roomMicInfo.isMicMute()) { + buttonItems.add(createOpenMicItem(micPosition)); + } else { + buttonItems.add(createBanMicItem(micPosition)); + } + } + } + if (isTargetOnMic) { + if (!isTargetVip) { + buttonItems.add(createKickMicItem()); + } + } else { + handleInviteMicItem(buttonItems); + } + //解锁麦 + if (micPosition != AvRoomDataManager.POSITON_NOT_ON_MIC) { + if (roomMicInfo != null) { + if (roomMicInfo.isMicLock()) { + buttonItems.add(createUnLockMicItem(micPosition)); + } else { + if (!isTargetVip) { + buttonItems.add(createLockMicItem(micPosition)); + } + } + } + } + } + return buttonItems; + } else if (AvRoomDataManager.get().isRoomAdmin()) { + //管理员操作 + if (isMySelf) { + //开闭麦 + if (micPosition != AvRoomDataManager.POSITON_NOT_ON_MIC) { + if (roomMicInfo != null) { + if (roomMicInfo.isMicMute()) { + buttonItems.add(createOpenMicItem(micPosition)); + } else { + buttonItems.add(createBanMicItem(micPosition)); + } + } + } + if (isTargetOnMic) { + buttonItems.add(createDownMicItem()); + } else { + handleInviteMicItem(buttonItems); + } + //解锁麦 + if (micPosition != AvRoomDataManager.POSITON_NOT_ON_MIC) { + if (roomMicInfo != null) { + if (roomMicInfo.isMicLock()) { + buttonItems.add(createUnLockMicItem(micPosition)); + } else { + if (!isTargetVip) { + buttonItems.add(createLockMicItem(micPosition)); + } + } + } + } + } else { + //管理员操作不是自己的坑上用户 + //开闭麦 + if (micPosition != AvRoomDataManager.POSITON_NOT_ON_MIC) { + if (roomMicInfo != null) { + if (roomMicInfo.isMicMute()) { + buttonItems.add(createOpenMicItem(micPosition)); + } else { + if (!isTargetManager) { + buttonItems.add(createBanMicItem(micPosition)); + } + } + } + } + //管理员能抱所有人上麦 + if (isTargetOnMic) { + //管理员能抱管理员和游客下麦 + if (!isTargetRoomOwner && !isTargetVip) { + buttonItems.add(createKickMicItem()); + } + } else { + if (AvRoomDataManager.get().isLeaveMode()) { + + if (!isTargetRoomOwner) { + handleInviteMicItem(buttonItems); + } + + } else { + handleInviteMicItem(buttonItems); + } + } + //解锁麦 管理员能操作所有坑位 @陈金林说的 + if (micPosition != AvRoomDataManager.POSITON_NOT_ON_MIC) { + if (roomMicInfo != null) { + if (roomMicInfo.isMicLock()) { + buttonItems.add(createUnLockMicItem(micPosition)); + } else { + if (!isTargetVip) { + buttonItems.add(createLockMicItem(micPosition)); + } + } + } + } + + } + return buttonItems; + } else { + //游客操作 + if (isMySelf && isTargetOnMic) { + buttonItems.add(createDownMicItem()); + } + return buttonItems; + } + } + + /** + * 如果是超管点开资料卡片,隐藏 + * 抱ta上麦 + */ + private void handleInviteMicItem(List buttonItems) { + if (!SuperAdminUtil.isSuperAdmin() && + !(AvRoomDataManager.get().isSingleRoom() && AvRoomDataManager.get().isOpenAnotherPKMode())) { + buttonItems.add(createInviteMicItem()); + } + } + + private ViewItem createInviteMicItem() { + return new ViewItem(getString(R.string.ui_widget_userinfodialog_028), + R.drawable.user_card_ic_up_mic, + true, + () -> { + MicSelectDialog dialog = new MicSelectDialog(); + dialog.setMActionCallBack(new BaseDialogFragment.Action() { + @Override + public void onAction(int type, @Nullable Object data) { +// dismiss(); + } + }); + dialog.setTargetUser(userInfo); + dialog.setHomePartyModel(homePartyModel); + dialog.show(context); + dismiss(); + }); + } + + private ViewItem createClearGiftValueItem() { + return new ViewItem(getString(R.string.ui_widget_userinfodialog_013), R.drawable.user_card_ic_clean_gift_value, true, new ViewItem.OnClickListener() { + @Override + public void onClick() { + GiftValueModel.get().clearSingleMicValue(uid).subscribe(new DontWarnObserver() { + @Override + public void accept(RoomGiftValue roomGiftValue, String error) { + super.accept(roomGiftValue, error); + if (roomGiftValue == null) { + return; + } + if (error != null) { + SingleToastUtil.showToast(error); + return; + } + SingleToastUtil.showToast(getString(R.string.ui_widget_userinfodialog_014)); + GiftValueMrg.get().updateRoomGiftValue(roomGiftValue, true); + //通知房间其他用户更新 + GiftValueMrg.get().sendRoomGiftValueMsg(roomGiftValue); + } + }); + dismiss(); + } + }); + } + + private ViewItem createDownMicItem() { + return new ViewItem(getString(R.string.ui_widget_userinfodialog_016), R.drawable.user_card_ic_down_mic_listen, true, new ViewItem.OnClickListener() { + @Override + public void onClick() { + showDownMicDialog(); + dismiss(); + } + }); + } + + private ViewItem createBanMicItem(int micPosition) { + return new ViewItem(getString(R.string.ui_widget_userinfodialog_019), R.drawable.user_card_ic_close_mic, true, new ViewItem.OnClickListener() { + @Override + public void onClick() { + final RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) { + return; + } + mSuperAdminModel.roomOperate(SuperAdminModel.CLOSE_MIC).subscribe(); + homePartyModel.closeMicroPhone(micPosition, roomInfo.getUid()).subscribe(); + dismiss(); + } + }); + } + + private ViewItem createOpenMicItem(int micPosition) { + return new ViewItem(getString(R.string.ui_widget_userinfodialog_021), R.drawable.user_card_ic_open_mic, true, new ViewItem.OnClickListener() { + @Override + public void onClick() { + final RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) { + return; + } + homePartyModel.openMicroPhone(micPosition, roomInfo.getUid()).subscribe(); + dismiss(); + } + }); + } + + private ViewItem createLockMicItem(int micPosition) { + return new ViewItem(getString(R.string.ui_widget_userinfodialog_022), R.drawable.user_card_ic_lock_mic, true, new ViewItem.OnClickListener() { + @Override + public void onClick() { + final RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) { + return; + } + if (AvRoomDataManager.get().isQueuingMicro()) { + SingleToastUtil.showToast(getString(R.string.ui_widget_userinfodialog_024)); + return; + } + mSuperAdminModel.roomOperate(SuperAdminModel.LOCK_MIC).subscribe(); + + homePartyModel.lockMicroPhone(micPosition, roomInfo.getUid() + "", + AuthModel.get().getTicket()).subscribe(); + dismiss(); + } + }); + } + + private ViewItem createUnLockMicItem(int micPosition) { + return new ViewItem(getString(R.string.ui_widget_userinfodialog_025), R.drawable.user_card_ic_no_lock_mic, true, new ViewItem.OnClickListener() { + @Override + public void onClick() { + final RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) { + return; + } + if (AvRoomDataManager.get().isQueuingMicro()) { + SingleToastUtil.showToast(getString(R.string.ui_widget_userinfodialog_026)); + return; + } + if (AvRoomDataManager.get().isOpenPKMode()) { + SingleToastUtil.showToast(getString(R.string.ui_widget_userinfodialog_027)); + return; + } + homePartyModel.unLockMicroPhone(micPosition, roomInfo.getUid() + "", + AuthModel.get().getTicket()).subscribe(); + dismiss(); + } + }); + } + + + @SuppressLint("CheckResult") + private ViewItem createKickMicItem() { + return new ViewItem(getString(R.string.ui_widget_userinfodialog_029), R.drawable.user_card_ic_down_mic_listen, true, new ViewItem.OnClickListener() { + @Override + public void onClick() { + + if (VipHelper.notKick(userInfo)) { + ToastUtils.show(ResUtil.getString(R.string.vipPower, userInfo.getUserVipInfoVO().getVipLevel())); + return; + } + + if (SuperAdminUtil.isSuperAdmin()) { + mSuperAdminModel.roomOperate(SuperAdminModel.TAKE_OUT_MIC, uid).subscribe(); + kickDownMicCode(); + return; + } + + if (AvRoomDataManager.get().isOnMic(uid)) { + if (AvRoomDataManager.get().isGamePlaying(uid)) { + new DialogManager(context).showOkCancelWithTitleDialog(getString(R.string.ui_widget_userinfodialog_031), + (DialogManager.LambdaOkDialogListener) () -> { + kickDownMicCode(); + dismiss(); + }); + return; + } + + if (GiftValueDialogUiHelper.get().isNeedKickDownMicDialog()) { + dismiss(); + GiftValueDialogUiHelper.get().showGiftValueDialog(context, null, + GiftValueDialogUiHelper.TYPE_KICK_DOWN_MIC, + () -> kickDownMicCode()); + return; + } + kickDownMicCode(); + } + } + }); + } + + + /** + * 下麦前需要判断是否是ktv模式或者龙珠 + */ + private void showDownMicDialog() { + if (AvRoomDataManager.get().mCurrentRoomInfo == null) { + return; + } + + if (AvRoomDataManager.get().isSelfGamePlaying()) { + SingleToastUtil.showToast(getString(R.string.ui_widget_userinfodialog_017)); + return; + } + if (AvRoomDataManager.get().haveStartDragon) { + new DialogManager(context).showOkCancelDialog(getString(R.string.ui_widget_userinfodialog_018), false, new DialogManager.OkCancelDialogListener() { + @Override + public void onCancel() { + } + + @Override + public void onOk() { + DragonBallModel.get() + .clearDragonBar() + .doOnSuccess(s -> { + AvRoomDataManager.get().haveStartDragon = false; + cancelDragon(); + handleDownMicro(); + }) + .subscribe(); + } + }); + } else { + handleDownMicro(); + } + } + + private void handleDownMicro() { + if (AvRoomDataManager.get().isShowGiftValue() + && GiftValueDialogUiHelper.get().isNeedConfirmDialog(GiftValueDialogUiHelper.TYPE_DOWN_MIC)) { + GiftValueDialogUiHelper.get().showGiftValueDialog(context, null, GiftValueDialogUiHelper.TYPE_DOWN_MIC, + this::downMicCode); + } else { + downMicCode(); + } + } + + /** + * 下麦的代码 + */ + private void downMicCode() { + long currentUid = AuthModel.get().getCurrentUid(); + int micPos = AvRoomDataManager.get().getMicPosition(currentUid); + IMNetEaseManager.get().downMicroPhoneBySdk( + micPos, null); + } + + + public void cancelDragon() { + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo == null) return; + // 普通表情 + final ChatRoomMessage message = getChatRoomMessage(roomInfo, AvRoomDataManager.get().dragons, CUSTOM_MSG_DRAGON_BAR_CANCEL); + IMNetEaseManager.get().sendChatRoomMessage(message, false) + .subscribe((chatRoomMessage, throwable) -> { + IMNetEaseManager.get().getChatRoomEventObservable(). + onNext(new RoomEvent().setEvent(DRAGON_BAR_CANCEL) + .setChatRoomMessage(chatRoomMessage)); + IMNetEaseManager.get().addMessages(chatRoomMessage); + + }); + } + + private ChatRoomMessage getChatRoomMessage(RoomInfo roomInfo, List integers, int second) { + UserInfo userInfo = UserModel.get().getCacheLoginUserInfo(); + List faceReceiveInfos = new ArrayList<>(); + FaceReceiveInfo faceReceiveInfo = new FaceReceiveInfo(); + faceReceiveInfo.setNick(userInfo.getNick()); + faceReceiveInfo.setFaceId(Constants.DRAGON_BAR_ID); + faceReceiveInfo.setUid(userInfo.getUid()); + + faceReceiveInfo.setResultIndexes(integers); + faceReceiveInfos.add(faceReceiveInfo); + + // 发送云信信息给所有人 + FaceAttachment faceAttachment = + new FaceAttachment(CUSTOM_MSG_DRAGON_BAR, second); + faceAttachment.setUid(userInfo.getUid()); + faceAttachment.setFaceReceiveInfos(faceReceiveInfos); + + return ChatRoomMessageBuilder.createChatRoomCustomMessage( + // 聊天室id + roomInfo.getRoomId() + "", + // 自定义消息 + faceAttachment + ); + } + + @SuppressLint("CheckResult") + private void kickDownMicCode() { + int micPosition = AvRoomDataManager.get().getMicPosition(uid); + IMNetEaseManager.get().downMicroPhoneBySdk(micPosition, null); + RoomInfo roomInfo = AvRoomDataManager.get().mCurrentRoomInfo; + if (roomInfo != null && userInfo != null) { + Single single; + if (SuperAdminUtil.isSuperAdmin()) { + single = IMNetEaseManager.get().kickMicroBySdkBySAdmin( + uid, userInfo.getNick(), roomInfo.getRoomId()); + } else { + single = IMNetEaseManager.get().kickMicroPhoneBySdk(uid, userInfo.getNick(), + roomInfo.getRoomId()); + } + single.subscribe( + chatRoomMessage -> { + KickModel.get().onSendRoomMessageSuccess(chatRoomMessage); + dismiss(); + }, + Throwable::printStackTrace); + } + + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/UserInfoView.java b/app/src/main/java/com/chwl/app/ui/widget/UserInfoView.java new file mode 100644 index 0000000..0ffca63 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/UserInfoView.java @@ -0,0 +1,72 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.Nullable; +import androidx.appcompat.widget.AppCompatImageView; + +import com.chwl.app.R; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.app.utils.RegexUtil; +import com.chwl.core.user.bean.SimpleUserInfo; + +/** + * 用户信息展示 一个通用的展示,用户昵称,性别,经验等级,魅力等级 + * Created by lvzebiao on 2019/1/3. + */ + +public class UserInfoView extends LinearLayout { + + private TextView tvNick; + private AppCompatImageView ivGender; + private AppCompatImageView ivUserLevel; + private AppCompatImageView ivCharmLevel; + + public UserInfoView(Context context) { + this(context, null); + } + + public UserInfoView(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public UserInfoView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + setOrientation(LinearLayout.HORIZONTAL); + setGravity(Gravity.CENTER_VERTICAL); + inflate(getContext(), R.layout.view_user_info, this); + findView(); + } + + private void findView() { + tvNick = findViewById(R.id.tv_nick); + ivGender = findViewById(R.id.iv_gender); + ivUserLevel = findViewById(R.id.iv_user_level); + ivCharmLevel = findViewById(R.id.iv_charm_level); + } + + public void setData(SimpleUserInfo info) { + if (info == null) { + return; + } + tvNick.setText(RegexUtil.getPrintableString(info.getNick())); + ivGender.setImageResource(info.getGender() == 1 ? R.drawable.ic_gender_male : R.drawable.ic_gender_female); + ivUserLevel.setVisibility(View.GONE); + if (info.getUserLevelVo() != null && !TextUtils.isEmpty(info.getUserLevelVo().getExperUrl())) { + ivUserLevel.setVisibility(View.VISIBLE); + ImageLoadUtils.loadImage(getContext(), info.getUserLevelVo().getExperUrl(), ivUserLevel); + } + ivCharmLevel.setVisibility(View.GONE); + if (info.getUserLevelVo() != null && !TextUtils.isEmpty(info.getUserLevelVo().getCharmUrl())) { + ivCharmLevel.setVisibility(View.VISIBLE); + ImageLoadUtils.loadImage(getContext(), info.getUserLevelVo().getCharmUrl(), ivCharmLevel); + } + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/UserInfoWrapContentPager.java b/app/src/main/java/com/chwl/app/ui/widget/UserInfoWrapContentPager.java new file mode 100644 index 0000000..033cecb --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/UserInfoWrapContentPager.java @@ -0,0 +1,46 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.viewpager.widget.ViewPager; + +import com.netease.nim.uikit.common.util.sys.ScreenUtil; + +/** + * @author jack + * @Description + * @Date 2018/10/31 + */ +public class UserInfoWrapContentPager extends ViewPager { + public UserInfoWrapContentPager(@NonNull Context context) { + super(context); + } + + public UserInfoWrapContentPager(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int height = 0; + //下面遍历所有child的高度 + final int position = getCurrentItem(); + View child = getChildAt(position); + if (child != null) { + child.measure(widthMeasureSpec, + MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); + height = child.getMeasuredHeight(); + if (position == 1 && height < ScreenUtil.screenHeight * 0.8) { + height = (int) (ScreenUtil.screenHeight * 0.8); + } + heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); + } + + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/UserMagicIndicator.java b/app/src/main/java/com/chwl/app/ui/widget/UserMagicIndicator.java new file mode 100644 index 0000000..8955487 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/UserMagicIndicator.java @@ -0,0 +1,81 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import androidx.core.content.ContextCompat; + +import com.chwl.app.R; +import com.chwl.app.decoration.view.widgets.BadgeScaleTransitionPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.CommonNavigatorAdapter; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.indicators.LinePagerIndicator; +import com.chwl.core.home.bean.TabInfo; +import com.chwl.library.utils.ResUtil; + +import java.util.List; + +public class UserMagicIndicator extends CommonNavigatorAdapter { + + private Context mContext; + private List mTitleList; + private int mBottomMargin; + + public UserMagicIndicator(Context context, List titleList, int bottomMargin) { + mContext = context; + mTitleList = titleList; + mBottomMargin = bottomMargin; + } + + @Override + public int getCount() { + return mTitleList == null ? 0 : mTitleList.size(); + } + + @Override + public IPagerTitleView getTitleView(Context context, final int i) { + BadgeScaleTransitionPagerTitleView scaleTransitionPagerTitleView = new BadgeScaleTransitionPagerTitleView(context); + scaleTransitionPagerTitleView.setNormalColor(ContextCompat.getColor(mContext, R.color.color_999999)); + scaleTransitionPagerTitleView.setSelectedColor(ContextCompat.getColor(mContext, R.color.color_333333)); + scaleTransitionPagerTitleView.setMinScale(1); + scaleTransitionPagerTitleView.setTextSize(16); + scaleTransitionPagerTitleView.setText(mTitleList.get(i).getName()); + if (mTitleList.get(i).getName().equals(ResUtil.getString(R.string.ui_widget_usermagicindicator_01))) { + scaleTransitionPagerTitleView.findViewById(R.id.car_badge).setId(R.id.car_badge_garage); + } + scaleTransitionPagerTitleView.setOnClickListener(view -> { + if (mOnItemSelectListener != null) { + mOnItemSelectListener.onItemSelect(i); + } + }); + return scaleTransitionPagerTitleView; + } + + + @Override + public IPagerIndicator getIndicator(Context context) { + LinePagerIndicator indicator = new LinePagerIndicator(context); + indicator.setMode(LinePagerIndicator.MODE_EXACTLY); + indicator.setLineHeight(UIUtil.dip2px(mContext, 4)); + indicator.setRoundRadius(UIUtil.dip2px(mContext, 22)); + indicator.setLineWidth(UIUtil.dip2px(mContext, 7)); + indicator.setColors(context.getResources().getColor(R.color.color_333333)); + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + lp.bottomMargin = mBottomMargin; + indicator.setLayoutParams(lp); + return indicator; + } + + private OnItemSelectListener mOnItemSelectListener; + + public void setOnItemSelectListener(OnItemSelectListener onItemSelectListener) { + mOnItemSelectListener = onItemSelectListener; + } + + public interface OnItemSelectListener { + void onItemSelect(int position); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/WrapContentViewPager.java b/app/src/main/java/com/chwl/app/ui/widget/WrapContentViewPager.java new file mode 100644 index 0000000..be4de60 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/WrapContentViewPager.java @@ -0,0 +1,44 @@ +package com.chwl.app.ui.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.viewpager.widget.ViewPager; + +/** + * @author jack + * @Description + * @Date 2018/10/31 + */ +public class WrapContentViewPager extends ViewPager { + public WrapContentViewPager(@NonNull Context context) { + super(context); + } + + public WrapContentViewPager(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int height = 0; + //下面遍历所有child的高度 + final int position = getCurrentItem(); + View child = getChildAt(position); + if (child != null) { + child.measure(widthMeasureSpec, + MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); + height = child.getMeasuredHeight(); + final int pb = getPaddingBottom(); + final int pt = getPaddingTop(); + height += (pb + pt); + heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); + } + + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/XRecyclerView/ScaleTransitionPagerTitleView.java b/app/src/main/java/com/chwl/app/ui/widget/XRecyclerView/ScaleTransitionPagerTitleView.java new file mode 100644 index 0000000..c593cd5 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/XRecyclerView/ScaleTransitionPagerTitleView.java @@ -0,0 +1,85 @@ +package com.chwl.app.ui.widget.XRecyclerView; + +import android.content.Context; +import android.text.TextPaint; + +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.titles.ColorTransitionPagerTitleView; + + +/** + * 带颜色渐变和缩放的指示器标题 + * 博客: http://hackware.lucode.net + * + * @author hackware + * @date 2016/6/26 + */ +public class ScaleTransitionPagerTitleView extends ColorTransitionPagerTitleView { + private float mMinScale = 0.75f; + /** + * 选中是否加粗 + */ + private boolean selectedBold; + + private boolean isAlwaysBold; + + public ScaleTransitionPagerTitleView(Context context, boolean selectedBold) { + super(context); + this.selectedBold = selectedBold; + } + + public ScaleTransitionPagerTitleView(Context context) { + this(context, true); + } + + @Override + public void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight) { + super.onEnter(index, totalCount, enterPercent, leftToRight); + // 实现颜色渐变 + setScaleX(mMinScale + (1.0f - mMinScale) * enterPercent); + setScaleY(mMinScale + (1.0f - mMinScale) * enterPercent); + } + + @Override + public void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight) { + super.onLeave(index, totalCount, leavePercent, leftToRight); + // 实现颜色渐变 + setScaleX(1.0f + (mMinScale - 1.0f) * leavePercent); + setScaleY(1.0f + (mMinScale - 1.0f) * leavePercent); + } + + @Override + public void onSelected(int index, int totalCount) { + super.onSelected(index, totalCount); + if (!isAlwaysBold) { + TextPaint paint = getPaint(); + paint.setFakeBoldText(selectedBold); + invalidate(); + } + } + + @Override + public void onDeselected(int index, int totalCount) { + super.onDeselected(index, totalCount); + if (!isAlwaysBold) { + TextPaint paint = getPaint(); + paint.setFakeBoldText(false); + invalidate(); + } + } + + public float getMinScale() { + return mMinScale; + } + + public void setMinScale(float minScale) { + mMinScale = minScale; + } + + public void setAlwaysBold() { + isAlwaysBold = true; + TextPaint paint = getPaint(); + paint.setFakeBoldText(true); + invalidate(); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/adapter/GiftDialogNumberAdapter.kt b/app/src/main/java/com/chwl/app/ui/widget/adapter/GiftDialogNumberAdapter.kt new file mode 100644 index 0000000..d13861d --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/adapter/GiftDialogNumberAdapter.kt @@ -0,0 +1,12 @@ +package com.chwl.app.ui.widget.adapter + +import com.chwl.app.bindadapter.BaseBindingAdapter +import com.chwl.app.databinding.ItemGiftNumberNewBinding + +class GiftDialogNumberAdapter : BaseBindingAdapter() { + + override fun onBindView(viewBinding: ItemGiftNumberNewBinding, data: Int, pos: Int) { + viewBinding.number.text = if (data == -1) "all" else data.toString() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/widget/bubble/LeBubbleTextView.java b/app/src/main/java/com/chwl/app/ui/widget/bubble/LeBubbleTextView.java new file mode 100644 index 0000000..31ad48d --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/bubble/LeBubbleTextView.java @@ -0,0 +1,73 @@ +package com.chwl.app.ui.widget.bubble; + +import android.content.Context; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.View; +import android.widget.TextView; + + +/** + * Created by dupengtao on 15/7/25. + *

+ * + * + * + * + * + * + * + * + * + * + * + *

+ * + * + * + * + * + * + * + * + * + * + * + * + */ +public class LeBubbleTextView extends LeBubbleView implements Runnable { + + private TextView tvContent; + + public LeBubbleTextView(Context context) { + super(context); + } + + public LeBubbleTextView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public LeBubbleTextView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @Override + protected void initChildView(float radius, int backgroundColor, int textColor, float textSize, String content) { + super.initChildView(radius, backgroundColor, textColor, textSize, content); + tvContent = new TextView(mContext); + tvContent.setId(View.generateViewId()); + tvContent.setTextColor(textColor); + tvContent.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize); + tvContent.setText(content); + int px22 = dip2px(21); + int px16 = dip2px(15); + tvContent.setPaddingRelative(px22, px16, px22, px16); + conRl.addView(tvContent); + } + + public TextView getContentTextView(){ + return tvContent; + } + + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/bubble/LeBubbleTextViewHelper.java b/app/src/main/java/com/chwl/app/ui/widget/bubble/LeBubbleTextViewHelper.java new file mode 100644 index 0000000..a75c961 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/bubble/LeBubbleTextViewHelper.java @@ -0,0 +1,123 @@ +package com.chwl.app.ui.widget.bubble; + +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.PopupWindow; + + +/** + * Created by dupengtao on 15/10/9. + */ +public class LeBubbleTextViewHelper { + + private LeBubbleView mBubbleView; + private PopupWindow mBubblePopupWindow; + private View mAnchor; + private int mBubbleViewWidth; + private int mBubbleViewHeight; + + public LeBubbleTextViewHelper() { + } + + public LeBubbleTextViewHelper(LeBubbleView bubbleView) { + mBubbleView = bubbleView; + } + + /** + * 初始化 + * @param anchor 目标的view + * @param bubbleViewLayoutRes bubbleTextView资源文件 + */ + public void init(final View anchor, final int bubbleViewLayoutRes) { + + mBubbleView = (LeBubbleView) LayoutInflater.from(anchor.getContext()).inflate( + bubbleViewLayoutRes, null); + mAnchor = anchor; + mBubblePopupWindow = new PopupWindow(mBubbleView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true); + mBubblePopupWindow.setFocusable(false); + mBubblePopupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); + mBubbleView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); + mBubbleViewWidth = mBubbleView.getMeasuredWidth(); + mBubbleViewHeight = mBubbleView.getMeasuredHeight(); + } + + /** + * 显示 + */ + public void show() { + show(0, 0); + } + + /** + * 显示 + * @param xCustomOffset x轴偏移量 + * @param yCustomOffset y轴偏移量 + */ + public void show(int xCustomOffset, int yCustomOffset) { + + int[] location = new int[2]; + mAnchor.getLocationInWindow(location); + LeBubbleTextView.ArrowDirection arrowDirection = mBubbleView.getArrowDirection(); + int xOffset = 0, yOffset = 0; + int anchorWidth = mAnchor.getWidth(); + int anchorHeight = mAnchor.getHeight(); + switch (arrowDirection) { + case LEFT: { + xOffset = anchorWidth; + int arrowOffset = (mBubbleViewHeight / 2) - (int) (mBubbleViewHeight * mBubbleView.getRelative()); + yOffset = -(mBubbleViewHeight - anchorHeight) / 2 + arrowOffset; + } + break; + case TOP: { + yOffset = anchorHeight; + int arrowOffset = (mBubbleViewWidth / 2) - (int) (mBubbleViewWidth * mBubbleView.getRelative()); + xOffset = -(mBubbleViewWidth - anchorWidth) / 2 + arrowOffset; + } + break; + case BOTTOM: { + yOffset = -mBubbleViewHeight; + int arrowOffset = (mBubbleViewWidth / 2) - (int) (mBubbleViewWidth * mBubbleView.getRelative()); + xOffset = -(mBubbleViewWidth - anchorWidth) / 2 + arrowOffset; + } + break; + default: { + xOffset = -mBubbleViewWidth - 10; + int arrowOffset = (mBubbleViewHeight / 2) - (int) (mBubbleViewHeight * mBubbleView.getRelative()); + yOffset = -(mBubbleViewHeight - anchorHeight) / 2 + arrowOffset; + } + } + mBubblePopupWindow.showAtLocation(mAnchor, Gravity.NO_GRAVITY, location[0] + xOffset + xCustomOffset, location[1] + yOffset + yCustomOffset); + } + + public PopupWindow getBubblePopupWindow() { + return mBubblePopupWindow; + } + + /** + * 消失 + */ + public void dismissBubblePopupWindow() { + mBubblePopupWindow.dismiss(); + } + + /** + * @see LeBubbleTextViewHelper#getBubbleView() + * @return + */ + @Deprecated + public LeBubbleTextView getBubbleTextView() { + if(mBubbleView instanceof LeBubbleTextView) { + return (LeBubbleTextView)mBubbleView; + }else { + return null; + } + } + + public LeBubbleView getBubbleView() { + return mBubbleView; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/bubble/LeBubbleTextViews.java b/app/src/main/java/com/chwl/app/ui/widget/bubble/LeBubbleTextViews.java new file mode 100644 index 0000000..8469a6e --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/bubble/LeBubbleTextViews.java @@ -0,0 +1,98 @@ +package com.chwl.app.ui.widget.bubble; + +import android.content.Context; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.View; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.List; + + +/** + * Created by dupengtao on 15/7/25. + *

+ * + * + * + * + * + * + * + * + * + * + * + *

+ * + * + * + * + * + * + * + * + * + * + * + * + */ +public class LeBubbleTextViews extends LeBubbleView implements Runnable { + + private TextView tvContent; + private ArrayList views; + + public LeBubbleTextViews(Context context) { + super(context); + } + + public LeBubbleTextViews(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public LeBubbleTextViews(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @Override + protected void initChildView(float radius, int backgroundColor, int textColor, float textSize, String... contents) { + super.initChildView(radius, backgroundColor, textColor, textSize, contents); + views = new ArrayList<>(contents.length); + int curId = 0; + View curView = null; + for(String content : contents){ + tvContent = new TextView(mContext); + tvContent.setId(curId); + tvContent.setTextColor(textColor); + tvContent.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize); + tvContent.setText(content); + int px22 = dip2px(21); + int px16 = dip2px(15); + tvContent.setPaddingRelative(px22, px16, px22, px16); + if(curId > 0){ + + RelativeLayout.LayoutParams contentTvParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT); + contentTvParams.setMargins(dip2px(22), dip2px(1), dip2px(22), dip2px(15)); + //contentTvParams.addRule(RelativeLayout.ALIGN_TOP,titleTextView.getId()); + contentTvParams.addRule(RelativeLayout.BELOW, curView.getId()); + tvContent.setLayoutParams(contentTvParams); + +// RelativeLayout.LayoutParams curParams = (RelativeLayout.LayoutParams)curView.getLayoutParams(); +// LayoutParams tvParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); +// curParams.addRule(RelativeLayout.BELOW, tvContent.getId()); + + conRl.addView(tvContent,contentTvParams); + } + views.add(tvContent); + curId = View.generateViewId(); + curView = tvContent; + } + } + + public List getContentTextViews() { + return views; + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/bubble/LeBubbleTitleTextView.java b/app/src/main/java/com/chwl/app/ui/widget/bubble/LeBubbleTitleTextView.java new file mode 100644 index 0000000..c538240 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/bubble/LeBubbleTitleTextView.java @@ -0,0 +1,173 @@ +package com.chwl.app.ui.widget.bubble; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Color; +import android.graphics.Rect; +import android.util.AttributeSet; +import android.view.TouchDelegate; +import android.view.View; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.chwl.app.R; + + +/** + * Created by dupengtao on 15/7/25. + *

+ * + * + * + * + * + * + * + * + * + * + * + *

+ * + * + * + * + * + * + * + * + * + * + * + * + */ +public class LeBubbleTitleTextView extends LeBubbleView implements Runnable { + + private ImageView cancelImage; + private TextView titleTextView; + private TextView contentTextView; + private String titleText; + + + public LeBubbleTitleTextView(Context context) { + super(context); + } + + public LeBubbleTitleTextView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public LeBubbleTitleTextView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @Override + protected void onInitialize(AttributeSet attrs, int defStyleAttr, TypedArray a) { + titleText = a.getString(R.styleable.LeBubbleTextView_bubbleTitleText); + } + + private void initCancelImageView() { + cancelImage = new ImageView(mContext); + } + + private void initContentTextView(int textColor, String content) { + contentTextView = new TextView(mContext); + contentTextView.setId(View.generateViewId()); + LayoutParams contentTvParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + contentTvParams.setMargins(dip2px(22), dip2px(1), dip2px(22), dip2px(15)); + //contentTvParams.addRule(RelativeLayout.ALIGN_TOP,titleTextView.getId()); + contentTvParams.addRule(RelativeLayout.BELOW, titleTextView.getId()); + contentTextView.setLayoutParams(contentTvParams); + //dark + contentTextView.setTextColor(textColor); + contentTextView.setTextSize(14); + + contentTextView.setText(content); + } + + private void initTitleTextView(int textColor) { + titleTextView = new TextView(mContext); + titleTextView.setId(View.generateViewId()); + LayoutParams titleTvParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + titleTvParams.setMargins(dip2px(22), dip2px(15), dip2px(22), 0); + titleTextView.setLayoutParams(titleTvParams); + titleTextView.setSingleLine(true); + //dark + if (curStyle == STYLE_DARK) { + titleTextView.setTextColor(Color.WHITE); + } else { + titleTextView.setTextColor(Color.BLACK); + } + titleTextView.setTextSize(17); + + titleTextView.setText(titleText); + + System.out.print(1); + } + + private void initCancelView(int conRlw) { + cancelImage.setId(View.generateViewId()); + LayoutParams cancelParams = new LayoutParams(dip2px(13), dip2px(13)); + //cancelParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); + cancelParams.addRule(RelativeLayout.ALIGN_PARENT_TOP); + cancelParams.setMargins(conRlw - dip2px(22), dip2px(8), dip2px(8), 0); + cancelImage.setLayoutParams(cancelParams); + //cancelImage.setImageResource(R.drawable.le_bubble_cancel); + int cancel = R.drawable.le_bubble_cancel; + Bitmap source = BitmapFactory.decodeResource(this.getResources(), cancel); + int color; + if (curStyle == STYLE_DARK) { + color = Color.parseColor("#99FFFFFF"); + } else { + color = Color.parseColor("#99000000"); + } + TintedBitmapDrawable cancelBitmapDrawable = new TintedBitmapDrawable(mContext.getResources(), source, color); + cancelImage.setImageDrawable(cancelBitmapDrawable); + increaseClickArea(); + } + + private void increaseClickArea() { + Rect conRlRect = new Rect(); + conRl.getHitRect(conRlRect); + Rect rect = new Rect(conRlRect); + //cancelImage.getHitRect(rect); + //rect.top -= 300; // increase top hit area + rect.left = rect.right / 2; // increase left hit area + //rect.bottom += 300; // increase bottom hit area + //rect.right += 300; // increase right hit area + conRl.setTouchDelegate(new TouchDelegate(rect, cancelImage)); + } + + + @Override + protected void initChildView(float radius, int backgroundColor, int textColor, float textSize, String content) { + super.initChildView(radius, backgroundColor, textColor, textSize, content); + //cancel view + initCancelImageView(); + //title view + initTitleTextView(textColor); + conRl.addView(titleTextView); + //content view + initContentTextView(textColor, content); + conRl.addView(contentTextView); + } + + public void setCancelImageOnClickListener(OnClickListener l) { + cancelImage.setOnClickListener(l); + } + + @Override + protected void onPostCallBack(int conRlw, int conRlh) { + super.onPostCallBack(conRlw, conRlh); + //add cancel image view + initCancelView(conRlw); + conRl.addView(cancelImage); + } + + public View getCancelImage() { + return cancelImage; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/bubble/LeBubbleView.java b/app/src/main/java/com/chwl/app/ui/widget/bubble/LeBubbleView.java new file mode 100644 index 0000000..7d6c11c --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/bubble/LeBubbleView.java @@ -0,0 +1,300 @@ +package com.chwl.app.ui.widget.bubble; + +import android.content.Context; +import android.content.res.ColorStateList; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Color; +import android.graphics.Matrix; +import android.util.AttributeSet; +import android.view.View; +import android.widget.ImageView; +import android.widget.RelativeLayout; + +import com.chwl.app.R; + + +/** + * Created by dupengtao on 15/7/25. + *

+ * + * + * + * + * + * + * + * + * + * + * + *

+ * + * + * + * + * + * + * + * + * + * + * + * + */ +public class LeBubbleView extends RelativeLayout implements Runnable { + + public static final int STYLE_DARK = 1; + public static final int STYLE_LIGHT = 2; + public static final int STYLE_OTHER = 3; + + protected Context mContext; + protected ArrowDirection arrowDirection; + protected float relative; + protected RelativeLayout conRl; + protected ImageView arrowImage; + protected int pressBackgroundColor, backgroundColor; + protected TintedBitmapDrawable norDrawable, pressDrawable; + protected int mArrowOffset; + protected int curStyle; + + + public LeBubbleView(Context context) { + super(context); + initialize(context, null, 0); + } + + public LeBubbleView(Context context, AttributeSet attrs) { + super(context, attrs); + initialize(context, attrs, 0); + } + + public LeBubbleView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initialize(context, attrs, defStyleAttr); + } + + private void initialize(Context context, AttributeSet attrs, int defStyleAttr) { + mContext = context; + //TODO custom attribute + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LeBubbleTextView, defStyleAttr, R.style.LeBubbleTextView_Dark); + float radius = a.getDimension(R.styleable.LeBubbleTextView_bubbleCornerRadius, 0); + backgroundColor = a.getColor(R.styleable.LeBubbleTextView_bubbleBackgroundColor, 0); + +// TypedArray typedArray = getResources().obtainTypedArray(R.array.feed_icons); +// String[] titleArr = getResources().getStringArray(R.array.feed_names); +// if( null != titleArr ){ +// int titleLength = titleArr.length; +// for( int index = 0; index < titleLength; index++ ){ +// int feedResId = typedArray.getResourceId( index, 0 ); +// //... +// } +// } + pressBackgroundColor = a.getColor(R.styleable.LeBubbleTextView_bubbleBackgroundPressColor, 0); + int textColor = a.getColor(R.styleable.LeBubbleTextView_bubbleTextColor, 0); + float textSize = a.getDimension(R.styleable.LeBubbleTextView_bubbleTextSize, 0); + String contentText = a.getString(R.styleable.LeBubbleTextView_bubbleText); + + + + int intDirection = a.getInt(R.styleable.LeBubbleTextView_bubbleArrowDirection, 3); + setCurDirection(intDirection); + + float relativePosition = a.getFraction(R.styleable.LeBubbleTextView_relativePosition, 1, 1, 0.3f); + + setRelativePosition(relativePosition); + setCurThemeStyle(textColor); + onInitialize(attrs, defStyleAttr, a); + a.recycle(); + + String[] contents = contentText.split(","); + initContent(radius, backgroundColor, textColor, textSize, contents); + + } + + protected void onInitialize(AttributeSet attrs, int defStyleAttr, TypedArray a) { + + } + + public void setCurThemeStyle(int textColor) { + + int darkColor = mContext.getResources().getColor(R.color.bubbleView_dark_text_color); + int lightColor = mContext.getResources().getColor(R.color.bubbleView_light_text_color); + if (textColor == darkColor) { + curStyle = STYLE_DARK; + } else if (textColor == lightColor) { + curStyle = STYLE_LIGHT; + } else { + curStyle = STYLE_OTHER; + } + } + + private void setRelativePosition(float relativePosition) { + if (relativePosition < 0.2f) { + relative = 0.2f; + } else if (relativePosition > 0.8f) { + relative = 0.8f; + } else { + relative = relativePosition; + } + } + + private void setCurDirection(int intDirection) { + switch (intDirection) { + case 1: { + arrowDirection = ArrowDirection.LEFT; + } + break; + case 2: { + arrowDirection = ArrowDirection.TOP; + } + break; + case 3: { + arrowDirection = ArrowDirection.RIGHT; + } + break; + case 4: { + arrowDirection = ArrowDirection.BOTTOM; + } + } + } + + + private void initContent(float radius, final int backgroundColor, int textColor, float textSize, String... contents) { + + + conRl = new RelativeLayout(mContext); + conRl.setId(View.generateViewId()); + LayoutParams conRlParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + //conRl.setLayoutParams(conRlParams); + LeRoundRectDrawable2 roundRectDrawable = new LeRoundRectDrawable2(backgroundColor, radius); + conRl.setBackground(roundRectDrawable); + + initChildView(radius, backgroundColor, textColor, textSize, contents); + arrowImage = new ImageView(mContext); + arrowImage.setId(View.generateViewId()); + LayoutParams arrowParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + + int r; + switch (arrowDirection) { + case LEFT: { + r = 180; + conRlParams.addRule(RelativeLayout.END_OF, arrowImage.getId()); + } + break; + case TOP: { + r = 270; + conRlParams.addRule(RelativeLayout.BELOW, arrowImage.getId()); + } + break; + case BOTTOM: { + r = 90; + arrowParams.addRule(RelativeLayout.BELOW, conRl.getId()); + } + break; + default: { + r = 0; + arrowParams.addRule(RelativeLayout.END_OF, conRl.getId()); + } + } + + //int arrowRes = backgroundColor == Color.parseColor("#B3000000")?R.drawable.le_bubble_arrow_light:R.drawable.le_bubble_arrow_light; + int arrowRes = R.drawable.le_bubble_arrow_light; + Bitmap source = BitmapFactory.decodeResource(this.getResources(), arrowRes); + + Bitmap rotateBitmap = rotateBitmap(source, r); + + norDrawable = new TintedBitmapDrawable(mContext.getResources(), rotateBitmap, backgroundColor); + pressDrawable = new TintedBitmapDrawable(mContext.getResources(), rotateBitmap, pressBackgroundColor); + + arrowImage.setImageDrawable(norDrawable); + this.addView(arrowImage, arrowParams); + this.addView(conRl, conRlParams); + + arrowImage.setImageTintList(ColorStateList.valueOf(backgroundColor)); + + setBackground(new LeStateColorDrawable(Color.TRANSPARENT) { + @Override + protected void onIsPressed(boolean isPressed) { + LeRoundRectDrawable2 conRlBackground = (LeRoundRectDrawable2) conRl.getBackground(); + if (isPressed) { + conRlBackground.getPaint().setColor(pressBackgroundColor); + //arrowImage.setImageTintList(ColorStateList.valueOf(pressBackgroundColor)); + arrowImage.setImageDrawable(pressDrawable); + } else { + conRlBackground.getPaint().setColor(backgroundColor); + //arrowImage.setImageTintList(ColorStateList.valueOf(backgroundColor)); + arrowImage.setImageDrawable(norDrawable); + } + conRl.invalidate(); + arrowImage.invalidate(); + } + }); + + conRl.post(this); + + this.setClickable(true); + + } + + protected void initChildView(float radius, int backgroundColor, int textColor, float textSize, String... content) { + + } + + protected void initChildView(float radius, int backgroundColor, int textColor, float textSize, String content) { + + } + + public Bitmap rotateBitmap(Bitmap source, float angle) { + Matrix matrix = new Matrix(); + matrix.postRotate(angle); + return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true); + } + + protected int dip2px(float dpValue) { + final float scale = mContext.getResources() + .getDisplayMetrics().density; + return (int) (dpValue * scale + 0.5f); + } + + @Override + public void run() { + int conRlw = conRl.getWidth(); + int conRlh = conRl.getHeight(); + LayoutParams params = (LayoutParams) arrowImage.getLayoutParams(); + switch (arrowDirection) { + case TOP: + case BOTTOM: + mArrowOffset = (int) ((conRlw * relative) - arrowImage.getWidth() / 2); + params.setMargins(mArrowOffset, 0, 0, 0); + break; + case LEFT: + default: + mArrowOffset = (int) ((conRlh * relative) - arrowImage.getHeight() / 2); + params.setMargins(0, mArrowOffset, 0, 0); + } + + onPostCallBack(conRlw, conRlh); + } + + protected void onPostCallBack(int conRlw, int conRlh) { + + } + + public ArrowDirection getArrowDirection() { + return arrowDirection; + } + + public int getArrowOffset() { + return mArrowOffset; + } + + public float getRelative() { + return relative; + } + + public enum ArrowDirection { + LEFT, TOP, RIGHT, BOTTOM + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/bubble/LeRoundRectDrawable2.java b/app/src/main/java/com/chwl/app/ui/widget/bubble/LeRoundRectDrawable2.java new file mode 100644 index 0000000..5186892 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/bubble/LeRoundRectDrawable2.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.chwl.app.ui.widget.bubble; + +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Outline; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; + + +/** + * Very simple drawable that draws a rounded rectangle background with arbitrary corners and also + * reports proper outline for L. + *

+ * Simpler and uses less resources compared to GradientDrawable or ShapeDrawable. + */ +public class LeRoundRectDrawable2 extends Drawable { + private float mRadius; + private final Paint mPaint; + private final RectF mBoundsF; + private final Rect mBoundsI; + private float mPadding; + private boolean mInsetForPadding = false; + private boolean mInsetForRadius = true; + + public LeRoundRectDrawable2(int backgroundColor, float radius) { + mRadius = radius; + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); + mPaint.setColor(backgroundColor); + mBoundsF = new RectF(); + mBoundsI = new Rect(); + } + + void setPadding(float padding, boolean insetForPadding, boolean insetForRadius) { + if (padding == mPadding && mInsetForPadding == insetForPadding && + mInsetForRadius == insetForRadius) { + return; + } + mPadding = padding; + mInsetForPadding = insetForPadding; + mInsetForRadius = insetForRadius; + updateBounds(null); + invalidateSelf(); + } + + float getPadding() { + return mPadding; + } + + @Override + public void draw(Canvas canvas) { + canvas.drawRoundRect(mBoundsF, mRadius, mRadius, mPaint); + } + + private void updateBounds(Rect bounds) { + if (bounds == null) { + bounds = getBounds(); + } + mBoundsF.set(bounds.left, bounds.top, bounds.right, bounds.bottom); + mBoundsI.set(bounds); + //if (mInsetForPadding) { + //float vInset = LeRoundRectDrawable2WithShadow.calculateVerticalPadding(mPadding, mRadius, mInsetForRadius); + //float hInset = LeRoundRectDrawable2WithShadow.calculateHorizontalPadding(mPadding, mRadius, mInsetForRadius); + //mBoundsI.inset((int) Math.ceil(hInset), (int) Math.ceil(vInset)); + // to make sure they have same bounds. + //mBoundsF.set(mBoundsI); + //} + } + + @Override + protected void onBoundsChange(Rect bounds) { + super.onBoundsChange(bounds); + updateBounds(bounds); + } + + @Override + public void getOutline(Outline outline) { + outline.setRoundRect(mBoundsI, mRadius); + } + + void setRadius(float radius) { + if (radius == mRadius) { + return; + } + mRadius = radius; + updateBounds(null); + invalidateSelf(); + } + + @Override + public void setAlpha(int alpha) { + // not supported because older versions do not support + } + + @Override + public void setColorFilter(ColorFilter cf) { + // not supported because older versions do not support + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } + + public float getRadius() { + return mRadius; + } + + public void setColor(int color) { + mPaint.setColor(color); + invalidateSelf(); + } + + public Paint getPaint() { + return mPaint; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/bubble/LeStateColorDrawable.java b/app/src/main/java/com/chwl/app/ui/widget/bubble/LeStateColorDrawable.java new file mode 100644 index 0000000..6e1f2f7 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/bubble/LeStateColorDrawable.java @@ -0,0 +1,49 @@ +package com.chwl.app.ui.widget.bubble; + +import android.graphics.drawable.ColorDrawable; + +/** + * Created by dupengtao on 15/8/12. + */ +public abstract class LeStateColorDrawable extends ColorDrawable { + + private boolean mPressed = false; + + public LeStateColorDrawable(int color) { + super(color); + } + + @Override + protected boolean onStateChange(int[] state) { + + boolean pressed = isPressed(state); + if (mPressed != pressed) { + mPressed = pressed; + onIsPressed(mPressed); + } + return true; + } + + protected abstract void onIsPressed(boolean isPressed); + + @Override + public boolean setState(int[] stateSet) { + return super.setState(stateSet); + } + + @Override + public boolean isStateful() { + return true; + } + + private boolean isPressed(int[] state) { + boolean pressed = false; + for (int i = 0, j = state != null ? state.length : 0; i < j; i++) { + if (state[i] == android.R.attr.state_pressed) { + pressed = true; + break; + } + } + return pressed; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/bubble/TintedBitmapDrawable.java b/app/src/main/java/com/chwl/app/ui/widget/bubble/TintedBitmapDrawable.java new file mode 100644 index 0000000..0062162 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/bubble/TintedBitmapDrawable.java @@ -0,0 +1,45 @@ +package com.chwl.app.ui.widget.bubble; + +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.LightingColorFilter; +import android.graphics.Paint; +import android.graphics.drawable.BitmapDrawable; + +/** + * Created by dupengtao on 15/8/24. + */ +public final class TintedBitmapDrawable extends BitmapDrawable { + private int tint; + private int alpha; + + public TintedBitmapDrawable(final Resources res, final Bitmap bitmap, final int tint) { + super(res, bitmap); + this.tint = tint; + this.alpha = Color.alpha(tint); + } + + public TintedBitmapDrawable(final Resources res, final int resId, final int tint) { + super(res, BitmapFactory.decodeResource(res, resId)); + this.tint = tint; + this.alpha = Color.alpha(tint); + } + + public void setTint(final int tint) { + this.tint = tint; + this.alpha = Color.alpha(tint); + } + + @Override + public void draw(final Canvas canvas) { + final Paint paint = getPaint(); + if (paint.getColorFilter() == null) { + paint.setColorFilter(new LightingColorFilter(tint, 0)); + paint.setAlpha(alpha); + } + super.draw(canvas); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/widget/dialog/AllPlayEffectDialog.java b/app/src/main/java/com/chwl/app/ui/widget/dialog/AllPlayEffectDialog.java new file mode 100644 index 0000000..f36bac1 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/dialog/AllPlayEffectDialog.java @@ -0,0 +1,527 @@ +package com.chwl.app.ui.widget.dialog; + +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_LUCKY_GIFT_SERVER_ALL; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_LUCKY_SEA_GIFT_SERVER_ALL; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_BOX_ALL_ROOM_NOTIFY_BY_SVGA; +import static com.chwl.core.im.custom.bean.CustomAttachment.CUSTOM_MSG_SUB_DRAW_GIFT_L5; + +import android.content.Context; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.text.Layout; +import android.text.Spanned; +import android.text.StaticLayout; +import android.text.TextPaint; +import android.text.TextUtils; +import android.text.style.ForegroundColorSpan; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; +import androidx.core.text.HtmlCompat; + +import com.opensource.svgaplayer.SVGADrawable; +import com.opensource.svgaplayer.SVGADynamicEntity; +import com.opensource.svgaplayer.SVGAImageView; +import com.opensource.svgaplayer.SVGAParser; +import com.opensource.svgaplayer.SVGAVideoEntity; +import com.chwl.app.R; +import com.chwl.app.avroom.activity.AVRoomActivity; +import com.chwl.app.common.svga.SimpleSvgaCallback; +import com.chwl.app.databinding.DialogAllPlayEffectBinding; +import com.chwl.app.ui.webview.CommonWebViewActivity; +import com.chwl.app.utils.RegexUtil; +import com.chwl.app.utils.SpannableBuilder; +import com.chwl.core.gift.bean.LuckyBagNoticeInfo; +import com.chwl.core.im.custom.bean.CustomAttachment; +import com.chwl.core.im.custom.bean.NotifyH5Info; +import com.chwl.core.im.custom.bean.PlayEffectInfo; +import com.chwl.core.im.custom.bean.RoomBoxPrizeInfo; +import com.chwl.core.im.custom.bean.RoomLuckySeaMsgBean; +import com.chwl.core.im.custom.bean.TarotMsgBean; +import com.chwl.core.treasurefairy.bean.FairyMsgInfoBean; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.StringUtils; + +public class AllPlayEffectDialog extends BaseDialog { + + private final PlayEffectInfo playEffectInfo; + private DialogAllPlayEffectBinding binding; + + public AllPlayEffectDialog(Context context, @NonNull PlayEffectInfo playEffectInfo) { + super(context, R.style.FullScreenDialog); + this.playEffectInfo = playEffectInfo; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + requestWindowFeature(Window.FEATURE_NO_TITLE); + binding = DialogAllPlayEffectBinding.inflate(LayoutInflater.from(getContext())); + setContentView(binding.getRoot()); + setCancelable(true); + setCanceledOnTouchOutside(true); + Window window = getWindow(); + if (window != null) { + window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); + WindowManager.LayoutParams windowParams = window.getAttributes(); + windowParams.width = WindowManager.LayoutParams.MATCH_PARENT; + windowParams.height = WindowManager.LayoutParams.WRAP_CONTENT; + windowParams.dimAmount = 0.0f; + windowParams.gravity = Gravity.TOP; + windowParams.x = 0; + windowParams.y = 0; + window.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL); + window.setAttributes(windowParams); + window.setWindowAnimations(R.style.anim_left); + } + switch (playEffectInfo.getSecond()) { + case CUSTOM_MSG_SUB_BOX_ALL_ROOM_NOTIFY_BY_SVGA: + showBoxNotifyBySVGA(playEffectInfo.getRoomBoxPrizeInfo()); + break; + case CUSTOM_MSG_LUCKY_SEA_GIFT_SERVER_ALL: + showLuckySeaNotifyBySVGA(playEffectInfo.getRoomLuckySeaMsgBean()); + break; + case CUSTOM_MSG_LUCKY_GIFT_SERVER_ALL: + showLuckyBagNotify(playEffectInfo.getLuckyBagNoticeInfo()); + break; + case CUSTOM_MSG_SUB_DRAW_GIFT_L5: + showFairyNotifyBySVGA(playEffectInfo.getFairyMsgInfo()); + break; + case CustomAttachment.CUSTOM_MESS_TAROT_SENIOR_PRIZE_WINNING: + showTarotNotifyBySvga(playEffectInfo.getTarotMsgBean()); + break; + case CustomAttachment.CUSTOM_MSG_NOTIFY_H5_SUB_WHOLE_SERVICE: + showNotifyH5BySvga(playEffectInfo.getNotifyH5()); + break; + default: + break; + } + } + + + private void showBoxNotifyBySVGA(RoomBoxPrizeInfo roomBoxPrizeInfo) { + SpannableBuilder text = new SpannableBuilder() + .append( + ResUtil.getString(R.string.avroom_widget_roomeffectview_011), + new ForegroundColorSpan(Color.WHITE) + ) + .append( + StringUtils.abbreviate(roomBoxPrizeInfo.getNick(), 8) + " ", + new ForegroundColorSpan(ContextCompat.getColor(getContext(), R.color.notice_nick)) + ) + .append( + ResUtil.getString(R.string.treasure_in_find_love) + ResUtil.getString( + R.string.avroom_widget_roomeffectview_013 + ), new ForegroundColorSpan(Color.WHITE) + ) + .append( + roomBoxPrizeInfo.getPrizeName(), + new ForegroundColorSpan(ContextCompat.getColor(getContext(), R.color.notice_nick)) + ); + if (roomBoxPrizeInfo.getPrizeNum() > 1) { + text.append("x" + roomBoxPrizeInfo.getPrizeNum(), new ForegroundColorSpan(Color.WHITE)); + } + + SVGAImageView svgaImageView = new SVGAImageView(getContext()); + svgaImageView.setLoops(1); + svgaImageView.setClearsAfterDetached(true); + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT); + svgaImageView.setLayoutParams(params); + svgaImageView.setCallback(new SimpleSvgaCallback() { + @Override + public void onFinished() { + closeSelf(); + } + }); + binding.flSvgaNotify.addView(svgaImageView); + try { + SVGAParser.Companion.shareParser().decodeFromAssets("svga/box_notify.svga", new SVGAParser.ParseCompletion() { + @Override + public void onComplete(@NonNull SVGAVideoEntity svgaVideoEntity) { + SVGADynamicEntity dynamicEntity = new SVGADynamicEntity(); + TextPaint textPaint = new TextPaint(); + textPaint.setColor(Color.WHITE);//字体颜色 + textPaint.setTextSize(24);//字体大小 + dynamicEntity.setDynamicText(new StaticLayout( + text.build(), + 0, + text.build().length(), + textPaint, + 0, + Layout.Alignment.ALIGN_CENTER, + 1.0f, + 0.0f, + false + ), "bg"); + SVGADrawable drawable = new SVGADrawable(svgaVideoEntity, dynamicEntity); + svgaImageView.setImageDrawable(drawable); + svgaImageView.stepToFrame(0, true); + } + + @Override + public void onError() { + closeSelf(); + } + }, null); + } catch (Exception e) { + e.printStackTrace(); + closeSelf(); + } + } + + private void showLuckySeaNotifyBySVGA(RoomLuckySeaMsgBean roomLuckySeaMsgBean) { + SpannableBuilder text = new SpannableBuilder() + .append( + ResUtil.getString(R.string.congratulation), + new ForegroundColorSpan(Color.WHITE) + ) + .append( + roomLuckySeaMsgBean.getNick() + " ", + new ForegroundColorSpan(ContextCompat.getColor(getContext(), R.color.notice_nick)) + ) + .append( + ResUtil.getString(R.string.in_the_star_kitchen_draw), + new ForegroundColorSpan(Color.WHITE) + ) + .append( + String.valueOf(roomLuckySeaMsgBean.getItemMultiple()), + new ForegroundColorSpan(ContextCompat.getColor(getContext(), R.color.color_00EAFF)) + ) + .append( + ResUtil.getString(R.string.times_reward_get), + new ForegroundColorSpan(Color.WHITE) + ) + .append( + String.valueOf(roomLuckySeaMsgBean.getDiamonds()), + new ForegroundColorSpan(ContextCompat.getColor(getContext(), R.color.color_00EAFF)) + ) + .append( + ResUtil.getString(R.string.diamond_point), + new ForegroundColorSpan(Color.WHITE) + ); + SVGAImageView svgaImageView = new SVGAImageView(getContext()); + svgaImageView.setLoops(1); + svgaImageView.setClearsAfterDetached(true); + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT); + svgaImageView.setLayoutParams(params); + svgaImageView.setCallback(new SimpleSvgaCallback() { + @Override + public void onFinished() { + closeSelf(); + } + }); + binding.flSvgaNotify.addView(svgaImageView); + try { + SVGAParser.Companion.shareParser().decodeFromAssets("svga/lucky_sea_notify.svga", new SVGAParser.ParseCompletion() { + @Override + public void onComplete(@NonNull SVGAVideoEntity svgaVideoEntity) { + SVGADynamicEntity dynamicEntity = new SVGADynamicEntity(); + TextPaint textPaint = new TextPaint(); + textPaint.setColor(Color.WHITE);//字体颜色 + textPaint.setTextSize(24);//字体大小 + dynamicEntity.setDynamicText(new StaticLayout( + text.build(), + 0, + text.build().length(), + textPaint, + 0, + Layout.Alignment.ALIGN_CENTER, + 1.0f, + 0.0f, + false + ), "noble_text_tx"); + svgaImageView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (!TextUtils.isEmpty(roomLuckySeaMsgBean.getSkipUrl())) { + CommonWebViewActivity.start(getContext(), roomLuckySeaMsgBean.getSkipUrl()); + } + } + }); + SVGADrawable drawable = new SVGADrawable(svgaVideoEntity, dynamicEntity); + svgaImageView.setImageDrawable(drawable); + svgaImageView.stepToFrame(0, true); + } + + @Override + public void onError() { + closeSelf(); + } + }, null); + } catch (Exception e) { + e.printStackTrace(); + closeSelf(); + } + } + + private void showLuckyBagNotify(LuckyBagNoticeInfo luckyBagNoticeInfo) { + SpannableBuilder text = new SpannableBuilder() + .append( + ResUtil.getString(R.string.avroom_widget_roomeffectview_04), + new ForegroundColorSpan(Color.WHITE) + ) + .append( + subAndReplaceDot(luckyBagNoticeInfo.getNick(), 6) + " ", + new ForegroundColorSpan(ContextCompat.getColor(getContext(),R.color.notice_nick)) + ) + .append( + ResUtil.getString(R.string.avroom_widget_roomeffectview_05), + new ForegroundColorSpan(Color.WHITE) + ) + .append( + luckyBagNoticeInfo.getLuckyBagName() + " ", + new ForegroundColorSpan(ContextCompat.getColor(getContext(), R.color.notice_nick)) + ) + .append( + ResUtil.getString(R.string.avroom_widget_roomeffectview_06), + new ForegroundColorSpan(Color.WHITE) + ) + .append( + luckyBagNoticeInfo.getGoldPrice() + " ", + new ForegroundColorSpan(ContextCompat.getColor(getContext(), R.color.notice_nick)) + ) + .append( + ResUtil.getString(R.string.avroom_widget_roomeffectview_07), + new ForegroundColorSpan(Color.WHITE) + ) + .append( + luckyBagNoticeInfo.getGiftName(), + new ForegroundColorSpan(ContextCompat.getColor(getContext(), R.color.notice_nick)) + ); + SVGAImageView svgaImageView = new SVGAImageView(getContext()); + svgaImageView.setLoops(1); + svgaImageView.setClearsAfterDetached(true); + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT); + svgaImageView.setLayoutParams(params); + svgaImageView.setCallback(new SimpleSvgaCallback() { + @Override + public void onFinished() { + closeSelf(); + } + }); + binding.flSvgaNotify.addView(svgaImageView); + try { + SVGAParser.Companion.shareParser().decodeFromAssets("svga/lucky_gift_notify.svga", new SVGAParser.ParseCompletion() { + @Override + public void onComplete(@NonNull SVGAVideoEntity svgaVideoEntity) { + SVGADynamicEntity dynamicEntity = new SVGADynamicEntity(); + TextPaint textPaint = new TextPaint(); + textPaint.setColor(Color.WHITE);//字体颜色 + textPaint.setTextSize(24);//字体大小 + dynamicEntity.setDynamicText(new StaticLayout( + text.build(), + 0, + text.build().length(), + textPaint, + 0, + Layout.Alignment.ALIGN_CENTER, + 1.0f, + 0.0f, + false + ), "fdpp_copywriting"); + svgaImageView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + //跳轉房間要移除監聽,不然可能NPE + svgaImageView.setCallback(null); + AVRoomActivity.start(getContext(), luckyBagNoticeInfo.getRoomUid()); + } + }); + SVGADrawable drawable = new SVGADrawable(svgaVideoEntity, dynamicEntity); + svgaImageView.setImageDrawable(drawable); + svgaImageView.stepToFrame(0, true); + } + + @Override + public void onError() { + closeSelf(); + } + }, null); + } catch (Exception e) { + e.printStackTrace(); + closeSelf(); + } + } + + private void showNotifyH5BySvga(NotifyH5Info info) { + SVGAImageView svgaImageView = new SVGAImageView(getContext()); + svgaImageView.setLoops(1); + svgaImageView.setClearsAfterDetached(true); + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT); + svgaImageView.setLayoutParams(params); + svgaImageView.setCallback(new SimpleSvgaCallback() { + @Override + public void onFinished() { + closeSelf(); + } + }); + binding.flSvgaNotify.addView(svgaImageView); + try { + SVGAParser.Companion.shareParser().decodeFromAssets("svga/svga_notify_h5.svga", new SVGAParser.ParseCompletion() { + @Override + public void onComplete(@NonNull SVGAVideoEntity svgaVideoEntity) { + SVGADynamicEntity dynamicEntity = new SVGADynamicEntity(); + TextPaint textPaint = new TextPaint(); + textPaint.setColor(Color.WHITE);//字体颜色 + textPaint.setTextSize(24);//字体大小 + dynamicEntity.setDynamicText(new StaticLayout( + info.getContent(), + 0, + info.getContent().length(), + textPaint, + 0, + Layout.Alignment.ALIGN_CENTER, + 1.0f, + 0.0f, + false + ), "bg"); + SVGADrawable drawable = new SVGADrawable(svgaVideoEntity, dynamicEntity); + svgaImageView.setImageDrawable(drawable); + svgaImageView.stepToFrame(0, true); + } + + @Override + public void onError() { + closeSelf(); + } + }, null); + } catch (Exception e) { + e.printStackTrace(); + closeSelf(); + } + } + + private void showTarotNotifyBySvga(TarotMsgBean tarotMsgBean) { + String string = getContext().getString( + R.string.avroom_widget_roomeffectview_026, + StringUtils.abbreviate(RegexUtil.getPrintableString(tarotMsgBean.getNick()), 8), + tarotMsgBean.getDrawGoldNum()); + Spanned spanned = HtmlCompat.fromHtml(string, HtmlCompat.FROM_HTML_MODE_COMPACT); + SVGAImageView svgaImageView = new SVGAImageView(getContext()); + svgaImageView.setLoops(1); + svgaImageView.setClearsAfterDetached(true); + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT); + svgaImageView.setLayoutParams(params); + svgaImageView.setCallback(new SimpleSvgaCallback() { + @Override + public void onFinished() { + closeSelf(); + } + }); + binding.flSvgaNotify.addView(svgaImageView); + try { + SVGAParser.Companion.shareParser().decodeFromAssets("svga/svga_tarot_senior.svga", new SVGAParser.ParseCompletion() { + @Override + public void onComplete(@NonNull SVGAVideoEntity svgaVideoEntity) { + SVGADynamicEntity dynamicEntity = new SVGADynamicEntity(); + TextPaint textPaint = new TextPaint(); + textPaint.setColor(Color.WHITE);//字体颜色 + textPaint.setTextSize(24);//字体大小 + dynamicEntity.setDynamicText(new StaticLayout( + spanned, + 0, + spanned.length(), + textPaint, + 0, + Layout.Alignment.ALIGN_CENTER, + 1.0f, + 0.0f, + false + ), "taxt"); + SVGADrawable drawable = new SVGADrawable(svgaVideoEntity, dynamicEntity); + svgaImageView.setImageDrawable(drawable); + svgaImageView.stepToFrame(0, true); + } + + @Override + public void onError() { + closeSelf(); + } + }, null); + } catch (Exception e) { + e.printStackTrace(); + closeSelf(); + } + } + + private void showFairyNotifyBySVGA(FairyMsgInfoBean fairyMsgInfo) { + SpannableBuilder text = new SpannableBuilder() + .append("好運爆棚!", new ForegroundColorSpan(ContextCompat.getColor(getContext(), R.color.color_8C4700))) + .append( + subAndReplaceDot(fairyMsgInfo.getNick(), 6) + " ", + new ForegroundColorSpan(ContextCompat.getColor(getContext(), R.color.color_EC4613)) + ) + .append(" 在奪寶精靈中獲得 ", new ForegroundColorSpan(ContextCompat.getColor(getContext(), R.color.color_8C4700))) + .append( + fairyMsgInfo.getRewardName(), + new ForegroundColorSpan(ContextCompat.getColor(getContext(), R.color.color_EC4613)) + ); + SVGAImageView svgaImageView = new SVGAImageView(getContext()); + svgaImageView.setLoops(1); + svgaImageView.setClearsAfterDetached(true); + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT); + svgaImageView.setLayoutParams(params); + svgaImageView.setCallback(new SimpleSvgaCallback() { + @Override + public void onFinished() { + closeSelf(); + } + }); + binding.flSvgaNotify.addView(svgaImageView); + try { + SVGAParser.Companion.shareParser().decodeFromAssets("svga/all_fairy.svga", new SVGAParser.ParseCompletion() { + @Override + public void onComplete(@NonNull SVGAVideoEntity svgaVideoEntity) { + SVGADynamicEntity dynamicEntity = new SVGADynamicEntity(); + TextPaint textPaint = new TextPaint(); + textPaint.setColor(Color.WHITE);//字体颜色 + textPaint.setTextSize(24);//字体大小 + dynamicEntity.setDynamicText(new StaticLayout( + text.build(), + 0, + text.build().length(), + textPaint, + 0, + Layout.Alignment.ALIGN_CENTER, + 1.0f, + 0.0f, + false + ), "touming_text_name"); + SVGADrawable drawable = new SVGADrawable(svgaVideoEntity, dynamicEntity); + svgaImageView.setImageDrawable(drawable); + svgaImageView.stepToFrame(0, true); + } + + @Override + public void onError() { + closeSelf(); + } + }, null); + } catch (Exception e) { + e.printStackTrace(); + closeSelf(); + } + } + + private String subAndReplaceDot(String nick, int maxLength) { + if(nick.length() > maxLength){ + return nick.substring(0,maxLength)+"..."; + }else { + return nick; + } + } + + private void closeSelf() { + try { + dismiss(); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/dialog/AllServiceGiftGoRoomTipsDialog.kt b/app/src/main/java/com/chwl/app/ui/widget/dialog/AllServiceGiftGoRoomTipsDialog.kt new file mode 100644 index 0000000..9f15a31 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/dialog/AllServiceGiftGoRoomTipsDialog.kt @@ -0,0 +1,100 @@ +package com.chwl.app.ui.widget.dialog + +import android.content.Context +import android.os.Bundle +import android.view.Gravity +import android.view.LayoutInflater +import android.view.Window +import android.view.WindowManager +import androidx.databinding.DataBindingUtil +import com.example.lib_utils.ktx.singleClick +import com.chwl.app.R +import com.chwl.app.avroom.activity.AVRoomActivity +import com.chwl.app.databinding.AllServiceGiftGoRoomTipsDialogBinding +import com.chwl.core.initial.InitialModel +import com.chwl.library.common.util.SPUtils +import com.chwl.library.utils.JavaUtil + +/** + * Created by Max on 2023/10/30 10:29 + * Desc:跳转房间提示 + **/ +class AllServiceGiftGoRoomTipsDialog( + context: Context, + private val roomName: String, + private val roomId: Long +) : + BaseDialog(context, R.style.dialog) { + + private var binding: AllServiceGiftGoRoomTipsDialogBinding? = null + + companion object { + /** + * 是否需要提示前往房间 + */ + fun isNeedTips(): Boolean { + return !SPUtils.getBoolean("all_service_gift_go_room_no_tips", false) + } + + /** + * 忽略提示/不在提示 + */ + private fun ignoreTips() { + SPUtils.putBoolean("all_service_gift_go_room_no_tips", true) + } + } + + private var isCheck: Boolean = false + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setCancelable(false) + requestWindowFeature(Window.FEATURE_NO_TITLE) + val inflate = + LayoutInflater.from(context) + .inflate(R.layout.all_service_gift_go_room_tips_dialog, null) + setContentView(inflate.rootView) + binding = DataBindingUtil.bind(inflate) + + binding?.tvRoomName?.text = roomName + binding?.ivCheckbox?.setOnClickListener { + updateCheckbox(!isCheck) + } + binding?.tvTips?.setOnClickListener { + updateCheckbox(!isCheck) + } + binding?.tvGo?.singleClick { + if (isCheck) { + ignoreTips() + } + AVRoomActivity.start(context, roomId) + dismiss() + } + binding?.tvCancel?.singleClick { + if (isCheck) { + ignoreTips() + } + dismiss() + } + updateCheckbox(false) + } + + override fun onStart() { + super.onStart() + this.window?.attributes?.let { + it.width = WindowManager.LayoutParams.MATCH_PARENT + it.height = WindowManager.LayoutParams.WRAP_CONTENT + it.gravity = Gravity.CENTER + window?.attributes = it + } + } + + private fun updateCheckbox(isCheck: Boolean) { + this.isCheck = isCheck + if (isCheck) { + binding?.ivCheckbox?.setImageResource(R.drawable.base_ic_checkbox_selected) + } else { + binding?.ivCheckbox?.setImageResource(R.drawable.base_ic_checkbox_unselected) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/widget/dialog/AllServiceGiftLevelDialog.kt b/app/src/main/java/com/chwl/app/ui/widget/dialog/AllServiceGiftLevelDialog.kt new file mode 100644 index 0000000..6eb3c15 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/dialog/AllServiceGiftLevelDialog.kt @@ -0,0 +1,184 @@ +package com.chwl.app.ui.widget.dialog + +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import android.view.LayoutInflater +import android.view.ViewConfiguration +import android.view.Window +import android.view.WindowManager +import android.widget.TextView +import androidx.core.view.isVisible +import androidx.databinding.DataBindingUtil +import com.example.lib_utils.ktx.getColorById +import com.example.lib_utils.ktx.singleClick +import com.example.lib_utils.spannable.SpannableTextBuilder +import com.chwl.app.R +import com.chwl.app.avroom.activity.AVRoomActivity +import com.chwl.app.databinding.DialogGiftAllServiceLevelBinding +import com.chwl.core.initial.InitialModel +import com.chwl.core.noble.bean.AllServiceGiftProtocol +import com.chwl.library.utils.JavaUtil +import com.example.lib_utils.ktx.getStringById +import io.reactivex.Observable +import io.reactivex.disposables.Disposable +import java.util.concurrent.TimeUnit + +/** + * Created by Max on 2023/10/27 18:42 + * Desc:全服礼物弹窗 + **/ +class AllServiceGiftLevelDialog : BaseDialog { + + private var data: AllServiceGiftProtocol.DataBean? = null + private var binding: DialogGiftAllServiceLevelBinding? = null + + private var disposable: Disposable? = null + + companion object { + private var marqueeError = false + } + + constructor(context: Context?, data: AllServiceGiftProtocol.DataBean) : super( + context, R.style.FullScreenDialog + ) { + this.data = data + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + requestWindowFeature(Window.FEATURE_NO_TITLE) + val inflate = LayoutInflater.from(context).inflate(R.layout.dialog_gift_all_service_level, null) + setContentView(inflate.rootView) + setCancelable(true) + setCanceledOnTouchOutside(true) + binding = DataBindingUtil.bind(inflate) + val window = window + if (window != null) { + window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + val windowParams = window.attributes + windowParams.width = WindowManager.LayoutParams.MATCH_PARENT + //MATCH_PARENT会挡住键盘, + // wrap_parent在小米8又会截掉一点,在华为测试关闭按钮点击不到 + //暂时找不到原因, + windowParams.height = WindowManager.LayoutParams.WRAP_CONTENT + windowParams.dimAmount = 0.0f + windowParams.gravity = Gravity.TOP + windowParams.x = 0 + windowParams.y = 0 + window.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL) + window.attributes = windowParams + window.setWindowAnimations(R.style.anim_left) + } + val data = this.data + val binding = this.binding + if (data != null && binding != null) { + init(data, binding) + } else { + dismiss() + } + } + + private fun init( + data: AllServiceGiftProtocol.DataBean, + binding: DialogGiftAllServiceLevelBinding + ) { + binding.ivAvatar.singleClick { + goRoom(data) + } + binding.tvRoomGo.singleClick { + goRoom(data) + } + binding.giftBean = data + if ((data.giftNum) <= 1) { + binding.tvCount.text = "" + } else { + binding.tvCount.text = "X${data.giftNum}" + } + val message = context.getString(R.string.all_gift_message_format) + .format(data.sendUserNick ?: "", data.recvUserNick ?: "", data.giftName ?: "") + SpannableTextBuilder(binding.tvMessage).appendText(message) + .setTextStyle( + data.sendUserNick ?: "", + binding.tvMessage.context.getColorById(R.color.color_FFE468) + ) + .setTextStyle( + data.recvUserNick + " ", + binding.tvMessage.context.getColorById(R.color.color_FFE468) + ) + .setTextStyle( + data.giftName ?: "", + binding.tvMessage.context.getColorById(R.color.white) + ).apply() + when (data.levelNum.toIntOrNull()) { + 2 -> { + binding.ivAvatarBg.setImageResource(R.drawable.all_service_gift_bg_avatar_2) + binding.layoutRoot.setBackgroundResource(R.drawable.all_service_gift_bg_2) + binding.tvRoomGo.setBackgroundResource(R.drawable.all_service_gift_bg_room_go2) + } + + 3 -> { + binding.ivAvatarBg.setImageResource(R.drawable.all_service_gift_bg_avatar_3) + binding.layoutRoot.setBackgroundResource(R.drawable.all_service_gift_bg_3) + binding.tvRoomGo.setBackgroundResource(R.drawable.all_service_gift_bg_room_go3) + } + + else -> { + binding.ivAvatarBg.setImageDrawable(null) + binding.layoutRoot.setBackgroundResource(R.drawable.all_service_gift_bg_1) + binding.tvRoomGo.setBackgroundResource(R.drawable.all_service_gift_bg_room_go1) + } + } + setupTextMarquee(binding.tvMessage) + disposable = Observable.timer(data.notifyStaySecond.toLong(), TimeUnit.SECONDS) + .subscribe { dismiss() } + binding.groupRoom.isVisible = data.roomUid != 0L + } + + /** + * 添加跑马灯 + * 以及反射一些参数影响跑马灯 + */ + private fun setupTextMarquee(view: TextView) { + view.isSelected = true + if (marqueeError) { + return + } + try { + val configuration = ViewConfiguration.get( + context + ) + val claz: Class<*> = configuration.javaClass + val field = claz.getDeclaredField("mFadingMarqueeEnabled") + field.isAccessible = true + field[configuration] = true + } catch (e: Exception) { + e.printStackTrace() + marqueeError = true + } + } + + private fun goRoom( + data: AllServiceGiftProtocol.DataBean + ) { + if (data.roomUid <= 0L) { + // 非房间场景送的礼物 + return + } + if (AllServiceGiftGoRoomTipsDialog.isNeedTips()) { + AllServiceGiftGoRoomTipsDialog(context, data.roomTitle ?: "", data.roomUid).show() + } else { + AVRoomActivity.start(context, data.roomUid) + } + } + + override fun dismiss() { + super.dismiss() + if (disposable?.isDisposed != true) { + disposable?.dispose() + } + disposable = null + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/widget/dialog/AllServiceVipLevelUPDialog.java b/app/src/main/java/com/chwl/app/ui/widget/dialog/AllServiceVipLevelUPDialog.java new file mode 100644 index 0000000..ff6f012 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/dialog/AllServiceVipLevelUPDialog.java @@ -0,0 +1,153 @@ +package com.chwl.app.ui.widget.dialog; + +import android.content.Context; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.text.Layout; +import android.text.StaticLayout; +import android.text.TextPaint; +import android.text.style.ForegroundColorSpan; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.Window; +import android.view.WindowManager; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; + +import com.chwl.core.utils.extension.StringExtensionKt; +import com.example.lib_utils.ServiceTime; +import com.opensource.svgaplayer.SVGADrawable; +import com.opensource.svgaplayer.SVGADynamicEntity; +import com.opensource.svgaplayer.SVGAImageView; +import com.opensource.svgaplayer.SVGAParser; +import com.opensource.svgaplayer.SVGAVideoEntity; +import com.chwl.app.R; +import com.chwl.app.common.svga.SimpleSvgaCallback; +import com.chwl.app.common.widget.CircleImageSpan; +import com.chwl.app.databinding.DialogVipAllServiceLevelUpBinding; +import com.chwl.app.utils.SpannableBuilder; +import com.chwl.core.vip.bean.VipMessageInfo; +import com.chwl.library.utils.ResUtil; + +import java.net.URL; + +/** + * Created by MadisonRong on 11/05/2018. + */ + +public class AllServiceVipLevelUPDialog extends BaseDialog { + + + private final VipMessageInfo vipMessageInfo; + private DialogVipAllServiceLevelUpBinding binding; + private long startTime = 0; + private int frameCount = 0; + + public AllServiceVipLevelUPDialog(Context context, @NonNull VipMessageInfo vipMessageInfo) { + super(context, R.style.FullScreenDialog); + this.vipMessageInfo = vipMessageInfo; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + requestWindowFeature(Window.FEATURE_NO_TITLE); + binding = DialogVipAllServiceLevelUpBinding.inflate(LayoutInflater.from(getContext())); + setContentView(binding.getRoot()); + setCancelable(true); + setCanceledOnTouchOutside(true); + Window window = getWindow(); + if (window != null) { + window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); + WindowManager.LayoutParams windowParams = window.getAttributes(); + windowParams.width = WindowManager.LayoutParams.MATCH_PARENT; + windowParams.height = WindowManager.LayoutParams.WRAP_CONTENT; + windowParams.dimAmount = 0.0f; + windowParams.gravity = Gravity.TOP; + windowParams.x = 0; + windowParams.y = 0; + window.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL); + window.setAttributes(windowParams); + window.setWindowAnimations(R.style.anim_left); + } + showVipNotifyBySVGA(); + } + + + private void showVipNotifyBySVGA() { + SpannableBuilder text = new SpannableBuilder() + .append(ResUtil.getString(R.string.widget_dialog_allserviceviplevelupdialog_01), new ForegroundColorSpan(Color.WHITE)) + .append("-", new CircleImageSpan(new ColorDrawable(Color.TRANSPARENT), vipMessageInfo.getAvatar(), 50, 50)) + .append(" " + StringExtensionKt.sub(vipMessageInfo.getNick(), 6) + " ", new ForegroundColorSpan(getContext().getResources().getColor(R.color.notice_nick))) + .append(ResUtil.getString(R.string.widget_dialog_allserviceviplevelupdialog_02) + vipMessageInfo.getCurrVipName(), new ForegroundColorSpan(Color.WHITE) + "!"); + + SVGAImageView svgaImageView = new SVGAImageView(getContext()); + svgaImageView.setLoops(1); + svgaImageView.setClearsAfterDetached(true); + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT); + svgaImageView.setLayoutParams(params); + svgaImageView.setCallback(new SimpleSvgaCallback() { + @Override + public void onFinished() { + long offset = ServiceTime.INSTANCE.getTime() - startTime; + if (offset < 6000) { + int centerFrame = frameCount / 2; + if (centerFrame > 0) { + // 目前的SVGA资源最后一帧是半透明的,这里强制跳到中间帧,最大程度避免这种情况 + svgaImageView.stepToFrame(centerFrame, false); + } + svgaImageView.postDelayed(() -> { + closeSelf(); + }, 6000 - offset); + } else { + closeSelf(); + } + } + }); + binding.flSvgaVipNotify.addView(svgaImageView); + try { + SVGAParser.Companion.shareParser().decodeFromURL(new URL(vipMessageInfo.getFloatPic()), new SVGAParser.ParseCompletion() { + @Override + public void onComplete(@NonNull SVGAVideoEntity svgaVideoEntity) { + frameCount = svgaVideoEntity.getFrames(); + startTime = ServiceTime.INSTANCE.getTime(); + SVGADynamicEntity dynamicEntity = new SVGADynamicEntity(); + TextPaint textPaint = new TextPaint(); + textPaint.setColor(Color.WHITE);//字体颜色 + textPaint.setTextSize(24);//字体大小 + dynamicEntity.setDynamicText(new StaticLayout( + text.build(), + 0, + text.build().length(), + textPaint, + 0, + Layout.Alignment.ALIGN_CENTER, + 1.0f, + 0.0f, + false + ), "noble_text_tx"); + SVGADrawable drawable = new SVGADrawable(svgaVideoEntity, dynamicEntity); + svgaImageView.setImageDrawable(drawable); + svgaImageView.stepToFrame(0, true); + } + + @Override + public void onError() { + closeSelf(); + } + }, null); + } catch (Exception e) { + e.printStackTrace(); + closeSelf(); + } + } + + private void closeSelf() { + try { + dismiss(); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/dialog/BaseDialog.java b/app/src/main/java/com/chwl/app/ui/widget/dialog/BaseDialog.java new file mode 100644 index 0000000..9c97884 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/dialog/BaseDialog.java @@ -0,0 +1,26 @@ +package com.chwl.app.ui.widget.dialog; + +import android.content.Context; + +import androidx.appcompat.app.AppCompatDialog; + +import com.chwl.library.utils.SingleToastUtil; + +/** + * Created by huangmeng1 on 2018/4/11. + */ + +public class BaseDialog extends AppCompatDialog { + public BaseDialog(Context context) { + super(context); + } + + public BaseDialog(Context context, int theme) { + super(context, theme); + } + + public void toast(String msg) { +// Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT).show(); + SingleToastUtil.showToastShort(msg); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/dialog/CommonDialog.java b/app/src/main/java/com/chwl/app/ui/widget/dialog/CommonDialog.java new file mode 100644 index 0000000..797de64 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/dialog/CommonDialog.java @@ -0,0 +1,123 @@ +package com.chwl.app.ui.widget.dialog; + +import android.content.Context; +import android.os.Bundle; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.style.AbsoluteSizeSpan; +import android.text.style.StyleSpan; +import android.widget.TextView; + +import androidx.annotation.ColorRes; + +import com.chwl.app.R; +import com.chwl.core.utils.CoreTextUtils; +import com.chwl.library.utils.ResUtil; + +import static android.graphics.Typeface.BOLD; + +/** + * @author jack + * @Description + * @Date 2019/1/21 + */ +public class CommonDialog extends BaseDialog { + private String tipMsg = ""; + + private String okText = ResUtil.getString(R.string.widget_dialog_commontipdialog_01); + private String cancelText = ResUtil.getString(R.string.widget_dialog_commontipdialog_02); + private boolean isBold; + private @ColorRes + int color = -1; + private int textSize = -1; + + public CommonDialog(Context context) { + super(context, R.style.dialog); + init(); + } + + private void init() { + this.setCancelable(true); + this.setCanceledOnTouchOutside(true); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.layout_common_dialog); + + TextView tip = findViewById(R.id.message); + tip.setText(tipMsg); + if (color != -1) { + tip.setTextColor(getContext().getResources().getColor(color)); + } + SpannableStringBuilder builder = new SpannableStringBuilder(tipMsg); + if (textSize != -1) { + AbsoluteSizeSpan sizeSpan = new AbsoluteSizeSpan(textSize); + builder.setSpan(sizeSpan, 0, builder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); + } + if (isBold) { + StyleSpan boldSpan = new StyleSpan(BOLD); + builder.setSpan(boldSpan, 0, builder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); + } + tip.setText(builder); + TextView ok = findViewById(R.id.btn_ok); + ok.setText(okText); + ok.setOnClickListener(v -> { + this.dismiss(); + if (l != null) { + l.onOk(); + } + }); + TextView cancel = findViewById(R.id.btn_cancel); + cancel.setText(cancelText); + cancel.setOnClickListener(v -> { + this.dismiss(); + if (l != null) { + l.onCancel(); + } + }); + } + + public void setTipMsg(String tipMsg) { + this.tipMsg = tipMsg; + } + + public void setBold(boolean isBold) { + this.isBold = isBold; + } + + public void setTextColor(@ColorRes int color) { + this.color = color; + } + + public void setTextSize(int textSize) { + this.textSize = textSize; + } + + private OnActionListener l; + + public void setOkText(String okText) { + if (!CoreTextUtils.isEmptyText(okText)) + this.okText = okText; + } + + public void setCancelText(String cancelText) { + if (!CoreTextUtils.isEmptyText(cancelText)) + this.cancelText = cancelText; + } + + public void setOnActionListener(OnActionListener l) { + this.l = l; + } + + public interface OnActionListener { + default void onOk() { + } + + default void onCancel() { + } + } + + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/dialog/CommonLoadingDialog.java b/app/src/main/java/com/chwl/app/ui/widget/dialog/CommonLoadingDialog.java new file mode 100644 index 0000000..c766007 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/dialog/CommonLoadingDialog.java @@ -0,0 +1,73 @@ +package com.chwl.app.ui.widget.dialog; + +import android.content.Context; +import android.graphics.drawable.AnimationDrawable; +import android.os.Bundle; +import android.view.Window; +import android.widget.ImageView; +import android.widget.TextView; + +import com.opensource.svgaplayer.SVGAImageView; +import com.opensource.svgaplayer.SVGAParser; +import com.opensource.svgaplayer.SVGAVideoEntity; +import com.chwl.app.R; +import com.chwl.library.utils.ResUtil; + +/** + * @author jack + * @Description + * @Date 2019/1/22 + */ +public class CommonLoadingDialog extends BaseDialog { + + private String msg = ResUtil.getString(R.string.widget_dialog_commonloadingdialog_01); + + private TextView tvTip; +// private SVGAImageView loading; + + public CommonLoadingDialog(Context context, String tip) { + super(context, R.style.dialog); + msg = tip; + init(); + } + + private void init() { + this.setCancelable(false); + this.setCanceledOnTouchOutside(false); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.layout_progress_dialog); +// loading = (SVGAImageView) findViewById(R.id.dialog_loading) ; + tvTip = (TextView) findViewById(R.id.tv_tip); + tvTip.setText(msg); + } + + @Override + protected void onStart() { + super.onStart(); + Window window = getWindow(); + if (window != null) { + window.getAttributes().dimAmount = 0f; + window.setAttributes(window.getAttributes()); + } + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public CommonLoadingDialog showDialog() { + super.show(); + return this; + } + +// @Override +// public void onDetachedFromWindow() { +// super.onDetachedFromWindow(); +// loading.stopAnimation(); +// loading.clear(); +// } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/dialog/CommonMessageDialog.kt b/app/src/main/java/com/chwl/app/ui/widget/dialog/CommonMessageDialog.kt new file mode 100644 index 0000000..d3d8968 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/dialog/CommonMessageDialog.kt @@ -0,0 +1,17 @@ +package com.chwl.app.ui.widget.dialog + +import android.content.Context +import com.chwl.app.R +import com.chwl.app.databinding.DialogCommonMessageBinding +import com.chwl.app.base.BaseBindingDialog +import com.chwl.library.annatation.ActLayoutRes + +@ActLayoutRes(R.layout.dialog_common_message) +class CommonMessageDialog(context: Context, theme: Int) : + BaseBindingDialog(context, theme) { + constructor(context: Context) : this(context, R.style.dialog) + + override fun init() { + setCancelable(true) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/widget/dialog/CommonTipDialog.java b/app/src/main/java/com/chwl/app/ui/widget/dialog/CommonTipDialog.java new file mode 100644 index 0000000..d48825a --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/dialog/CommonTipDialog.java @@ -0,0 +1,123 @@ +package com.chwl.app.ui.widget.dialog; + +import static android.graphics.Typeface.BOLD; + +import android.content.Context; +import android.os.Bundle; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.style.AbsoluteSizeSpan; +import android.text.style.StyleSpan; +import android.widget.TextView; + +import androidx.annotation.ColorRes; + +import com.chwl.app.R; +import com.chwl.core.utils.CoreTextUtils; +import com.chwl.library.utils.ResUtil; + +/** + * @author jack + * @Description + * @Date 2019/1/21 + */ +public class CommonTipDialog extends BaseDialog { + private String tipMsg = ""; + + private String okText = ResUtil.getString(R.string.widget_dialog_commontipdialog_01); + private String cancelText = ResUtil.getString(R.string.widget_dialog_commontipdialog_02); + private boolean isBold; + private @ColorRes + int color = -1; + private int textSize = -1; + + public CommonTipDialog(Context context) { + super(context, R.style.dialog); + init(); + } + + private void init() { + this.setCancelable(true); + this.setCanceledOnTouchOutside(true); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.layout_ok_cancel_dialog); + + TextView tip = findViewById(R.id.message); + tip.setText(tipMsg); + if (color != -1) { + tip.setTextColor(getContext().getResources().getColor(color)); + } + SpannableStringBuilder builder = new SpannableStringBuilder(tipMsg); + if (textSize != -1) { + AbsoluteSizeSpan sizeSpan = new AbsoluteSizeSpan(textSize); + builder.setSpan(sizeSpan, 0, builder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); + } + if (isBold) { + StyleSpan boldSpan = new StyleSpan(BOLD); + builder.setSpan(boldSpan, 0, builder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); + } + tip.setText(builder); + TextView ok = findViewById(R.id.btn_ok); + ok.setText(okText); + ok.setOnClickListener(v -> { + this.dismiss(); + if (l != null) { + l.onOk(); + } + }); + TextView cancel = findViewById(R.id.btn_cancel); + cancel.setText(cancelText); + cancel.setOnClickListener(v -> { + this.dismiss(); + if (l != null) { + l.onCancel(); + } + }); + } + + public void setTipMsg(String tipMsg) { + this.tipMsg = tipMsg; + } + + public void setBold(boolean isBold) { + this.isBold = isBold; + } + + public void setTextColor(@ColorRes int color) { + this.color = color; + } + + public void setTextSize(int textSize) { + this.textSize = textSize; + } + + private OnActionListener l; + + public void setOkText(String okText) { + if (!CoreTextUtils.isEmptyText(okText)) + this.okText = okText; + } + + public void setCancelText(String cancelText) { + if (!CoreTextUtils.isEmptyText(cancelText)) + this.cancelText = cancelText; + } + + public void setOnActionListener(OnActionListener l) { + this.l = l; + } + + public interface OnActionListener { + default void onOk() { + } + + default void onCancel() { + } + } + + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/dialog/ExchangeDiamondTipDialog.java b/app/src/main/java/com/chwl/app/ui/widget/dialog/ExchangeDiamondTipDialog.java new file mode 100644 index 0000000..a7c8d81 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/dialog/ExchangeDiamondTipDialog.java @@ -0,0 +1,79 @@ +package com.chwl.app.ui.widget.dialog; + +import android.content.Context; +import android.os.Bundle; +import android.widget.ImageView; +import android.widget.TextView; + +import com.chwl.app.R; + +/** + * @author jack + * @Description + * @Date 2019/1/21 + */ +public class ExchangeDiamondTipDialog extends BaseDialog { + + private String mTvDiamond = ""; + private String mTvConsumeGold = ""; + + public ExchangeDiamondTipDialog(Context context) { + super(context, R.style.dialog); + init(); + } + + private void init() { + this.setCancelable(true); + this.setCanceledOnTouchOutside(true); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.layout_exchange_diamond_dialog); + + TextView ok = findViewById(R.id.btn_ok); + ok.setOnClickListener(v -> { + this.dismiss(); + if (l != null) { + l.onOk(); + } + }); + ImageView cancel = findViewById(R.id.mIvClose); + cancel.setOnClickListener(v -> { + this.dismiss(); + if (l != null) { + l.onCancel(); + } + }); + TextView tvConsumeDiamond = findViewById(R.id.mTvConsumeGold); + tvConsumeDiamond.setText(mTvConsumeGold); + TextView tvDiamond = findViewById(R.id.mTvDiamond); + tvDiamond.setText(mTvDiamond); + + } + + public void setTvDiamond(String tvDiamond){ + this.mTvDiamond = tvDiamond; + } + + public void setTvConsumeGold(String tvConsumeGold) { + this.mTvConsumeGold = tvConsumeGold; + } + + private OnActionListener l; + + public void setOnActionListener(OnActionListener l) { + this.l = l; + } + + public interface OnActionListener { + default void onOk() { + } + + default void onCancel() { + } + } + + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/dialog/GiftManualQuantityDialog.java b/app/src/main/java/com/chwl/app/ui/widget/dialog/GiftManualQuantityDialog.java new file mode 100644 index 0000000..2f2303b --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/dialog/GiftManualQuantityDialog.java @@ -0,0 +1,92 @@ +package com.chwl.app.ui.widget.dialog; + +import android.app.Dialog; +import android.content.Context; +import android.graphics.Color; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.Gravity; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.EditText; +import android.widget.TextView; + +import com.chwl.app.R; +import com.chwl.app.utils.KeyBoardUtils; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; + +/** + * @author jack + * @Description + * @Date 2019/3/13 + */ +public class GiftManualQuantityDialog extends Dialog implements View.OnClickListener { + + private EditText etInput; + private TextView tvOk; + + private Context context; + + public GiftManualQuantityDialog(Context context) { + super(context, R.style.inputDialog); + this.context = context; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Window window = getWindow(); + if (window != null) { + window.getDecorView().setBackgroundColor(Color.TRANSPARENT); + window.getDecorView().setPadding(0, 0, 0, 0); + window.getDecorView().setMinimumWidth(context.getResources().getDisplayMetrics().widthPixels); + WindowManager.LayoutParams lps = window.getAttributes(); + lps.width = WindowManager.LayoutParams.MATCH_PARENT; + lps.height = WindowManager.LayoutParams.WRAP_CONTENT; + lps.gravity = Gravity.BOTTOM; + window.setAttributes(lps); + + } + + setContentView(R.layout.dialog_manual_quantity_gift); + setCanceledOnTouchOutside(true); + etInput = (EditText) findViewById(R.id.et_input); + tvOk = (TextView) findViewById(R.id.tv_ok); + tvOk.setOnClickListener(this); + } + + @Override + protected void onStart() { + super.onStart(); + KeyBoardUtils.showKeyBoard(context, etInput); + } + + @Override + public void onClick(View v) { + int id = v.getId(); + if (id == tvOk.getId()) { + String str = etInput.getText().toString(); + if (TextUtils.isEmpty(str)) { +// Toast.makeText(context, ResUtil.getString(R.string.widget_dialog_giftmanualquantitydialog_01), Toast.LENGTH_SHORT).show(); + SingleToastUtil.showToastShort(ResUtil.getString(R.string.widget_dialog_giftmanualquantitydialog_02)); + return; + } + + if (onConfirmClick != null) { + onConfirmClick.onConfirm(Integer.parseInt(str)); + } + } + } + + private OnConfirmClick onConfirmClick; + + public void setOnConfirmClick(OnConfirmClick onConfirmClick) { + this.onConfirmClick = onConfirmClick; + } + + public interface OnConfirmClick { + void onConfirm(int quantity); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/dialog/GiveDiamondTipDialog.java b/app/src/main/java/com/chwl/app/ui/widget/dialog/GiveDiamondTipDialog.java new file mode 100644 index 0000000..4a8e9d1 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/dialog/GiveDiamondTipDialog.java @@ -0,0 +1,152 @@ +package com.chwl.app.ui.widget.dialog; + +import static android.graphics.Typeface.BOLD; + +import android.content.Context; +import android.os.Bundle; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.style.AbsoluteSizeSpan; +import android.text.style.StyleSpan; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.ColorRes; +import androidx.constraintlayout.widget.ConstraintLayout; + +import com.chwl.app.R; +import com.chwl.core.utils.CoreTextUtils; +import com.chwl.library.utils.ResUtil; + +/** + * @author jack + * @Description + * @Date 2019/1/21 + */ +public class GiveDiamondTipDialog extends BaseDialog { + private String tipMsg = ""; + + private String okText = ResUtil.getString(R.string.dialog_lucky_money_confirm_btn); + private boolean isBold; + private boolean isTipMessageGone; + private @ColorRes + int color = -1; + private int textSize = -1; + private String mTvDiamond = ""; + private String mTvSeCharge = ""; + private String mTvConsumeDiamond = ""; + + public GiveDiamondTipDialog(Context context) { + super(context, R.style.dialog); + init(); + } + + private void init() { + this.setCancelable(true); + this.setCanceledOnTouchOutside(true); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.layout_give_diamond_dialog); + + TextView tip = findViewById(R.id.message); + tip.setText(tipMsg); + if (color != -1) { + tip.setTextColor(getContext().getResources().getColor(color)); + } + SpannableStringBuilder builder = new SpannableStringBuilder(tipMsg); + if (textSize != -1) { + AbsoluteSizeSpan sizeSpan = new AbsoluteSizeSpan(textSize); + builder.setSpan(sizeSpan, 0, builder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); + } + if (isBold) { + StyleSpan boldSpan = new StyleSpan(BOLD); + builder.setSpan(boldSpan, 0, builder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); + } + tip.setText(builder); + TextView ok = findViewById(R.id.btn_ok); + ok.setText(okText); + ok.setOnClickListener(v -> { + this.dismiss(); + if (l != null) { + l.onOk(); + } + }); + ImageView cancel = findViewById(R.id.mIvClose); + cancel.setOnClickListener(v -> { + this.dismiss(); + if (l != null) { + l.onCancel(); + } + }); + ConstraintLayout mCsMessage = findViewById(R.id.mCsMessage); + if(isTipMessageGone){ + mCsMessage.setVisibility(View.GONE); + }else { + mCsMessage.setVisibility(View.VISIBLE); + } + TextView tvSeCharge = findViewById(R.id.mTvSeCharge); + tvSeCharge.setText(mTvSeCharge); + TextView tvConsumeDiamond = findViewById(R.id.mTvConsumeDiamond); + tvConsumeDiamond.setText(mTvConsumeDiamond); + TextView tvDiamond = findViewById(R.id.mTvDiamond); + tvDiamond.setText(mTvDiamond); + + } + + public void setTvDiamond(String tvDiamond){ + this.mTvDiamond = tvDiamond; + } + + public void setTvSeCharge(String tvSeCharge) { + this.mTvSeCharge = tvSeCharge; + } + + public void setTvConsumeDiamond(String tvConsumeDiamond) { + this.mTvConsumeDiamond = tvConsumeDiamond; + } + + public void setBold(boolean isBold) { + this.isBold = isBold; + } + + public void setTextColor(@ColorRes int color) { + this.color = color; + } + + public void setTextSize(int textSize) { + this.textSize = textSize; + } + + public void setTipMessageGone(boolean isGone){ + this.isTipMessageGone = isGone; + } + + public void setTipMsg(String tipMsg) { + this.tipMsg = tipMsg; + } + + private OnActionListener l; + + public void setOkText(String okText) { + if (!CoreTextUtils.isEmptyText(okText)) + this.okText = okText; + } + + public void setOnActionListener(OnActionListener l) { + this.l = l; + } + + public interface OnActionListener { + default void onOk() { + } + + default void onCancel() { + } + } + + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/dialog/MonsterDialog.java b/app/src/main/java/com/chwl/app/ui/widget/dialog/MonsterDialog.java new file mode 100644 index 0000000..d725fe0 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/dialog/MonsterDialog.java @@ -0,0 +1,174 @@ +package com.chwl.app.ui.widget.dialog; + +import android.content.Context; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.util.Log; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; + +import androidx.databinding.DataBindingUtil; + +import com.chwl.app.R; +import com.chwl.app.avroom.activity.AVRoomActivity; +import com.chwl.app.databinding.DialogMonsterBinding; +import com.chwl.app.ui.webview.CommonWebViewActivity; +import com.chwl.core.UriProvider; +import com.chwl.core.monsterhunting.bean.MonsterDataBean; +import com.chwl.core.monsterhunting.bean.MonsterInfo; +import com.chwl.core.monsterhunting.bean.MonsterProtocol; +import com.chwl.library.utils.SizeUtils; + +import java.text.SimpleDateFormat; + +/** + * Created by huangmeng1 on 2018/3/29. + */ + +public class MonsterDialog extends BaseDialog implements View.OnClickListener { + + private static final String TAG = "MonsterDialog"; + + private MonsterDataBean dataBean; + private DialogMonsterBinding binding; + private SimpleDateFormat simformat = new SimpleDateFormat("mm:ss"); + private long count; + private CountDownTimer countDownTimer; + + public MonsterDialog(Context context, MonsterDataBean dataBean) { + this(context, 0); + this.dataBean = dataBean; + } + + public MonsterDialog(Context context, int theme) { + super(context, theme); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + View inflate = LayoutInflater.from(getContext()).inflate(R.layout.dialog_monster, null); + setContentView(inflate.getRootView()); + setCanceledOnTouchOutside(true); + setCancelable(true); + binding = DataBindingUtil.bind(inflate); + + binding.ivClose.setOnClickListener(v -> dismiss()); + binding.ivBg.setOnClickListener(this); + binding.tvMsg.setOnClickListener(this); + + long beforeAppearSeconds = dataBean.getBeforeAppearSeconds(); + long millisInFuture = beforeAppearSeconds * 1000; + if (millisInFuture == 0) { + binding.llTime.setVisibility(View.INVISIBLE); + } + + if (beforeAppearSeconds >= 30) { + count = 30; + } else if (beforeAppearSeconds < 30 && beforeAppearSeconds > 15) { + count = beforeAppearSeconds - 15; + } else if (beforeAppearSeconds <= 15) { + count = 15; + } + if (dataBean.getMonsterStatus() == MonsterInfo.MONSTER_STATUS_DID_DEAD) { + binding.getRoot().postDelayed(new Runnable() { + @Override + public void run() { + dismiss(); + } + }, 30 * 1000); + } else if (dataBean.getMonsterStatus() == MonsterInfo.MONSTER_STATUS_DID_LEAVE) { + binding.getRoot().postDelayed(new Runnable() { + @Override + public void run() { + dismiss(); + } + }, 10 * 1000); + } + countDownTimer = new CountDownTimer(millisInFuture, 1000) { + @Override + public void onTick(long millisUntilFinished) { + Log.e(TAG, "onTick() called with: millisUntilFinished = [" + millisUntilFinished + "]"); + count--; + if (count == 0) { + cancelCountDownTimer(); + dismiss(); + } + String format = simformat.format(millisUntilFinished); + String[] chars = format.split(""); + binding.tv1.setText(chars[1]); + binding.tv2.setText(chars[2]); + binding.tv3.setText(chars[4]); + binding.tv4.setText(chars[5]); + } + + @Override + public void onFinish() { + binding.tv1.setText("0"); + binding.tv2.setText("0"); + binding.tv3.setText("0"); + binding.tv4.setText("0"); + dismiss(); + } + }; + countDownTimer.start(); + + Window window = getWindow(); + if (window != null) { + window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); + WindowManager.LayoutParams windowParams = window.getAttributes(); + windowParams.width = WindowManager.LayoutParams.MATCH_PARENT; + windowParams.height = WindowManager.LayoutParams.WRAP_CONTENT; + windowParams.dimAmount = 0.0f; + windowParams.gravity = Gravity.TOP; + windowParams.x = 0; + windowParams.y = SizeUtils.dp2px(getContext(), 15); + window.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL); + window.setAttributes(windowParams); + window.setWindowAnimations(R.style.anim_left); + } + if (dataBean != null) { + binding.setMonsterInfo(dataBean); + } + + this.setOnCancelListener(dialog -> { + cancelCountDownTimer(); + }); + + this.setOnDismissListener(dialog -> { + cancelCountDownTimer(); + }); + } + + public void cancelCountDownTimer() { + if (countDownTimer != null) { + countDownTimer.cancel(); + } + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.iv_bg: + case R.id.tv_msg: + long beforeAppearSeconds = dataBean.getBeforeAppearSeconds(); + if (beforeAppearSeconds >= 30) { + CommonWebViewActivity.start(getContext(), UriProvider.IM_SERVER_URL + "/molistar/modules/monster/intro.html"); + } else if (beforeAppearSeconds < 30 && beforeAppearSeconds > 15) { + CommonWebViewActivity.start(getContext(), UriProvider.IM_SERVER_URL + "/molistar/modules/monster/intro.html"); + } else if (beforeAppearSeconds <= 15) { + AVRoomActivity.start(getContext(), dataBean.getAppearRoomUid()); + } + if (dataBean.getMonsterStatus() == MonsterInfo.MONSTER_STATUS_DID_DEAD) { + CommonWebViewActivity.start(getContext(), UriProvider.IM_SERVER_URL + + "/molistar/modules/monster/index.html?monsterId=" + dataBean.getMonsterId()); + } + break; + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/dialog/OpenNobleDialog.java b/app/src/main/java/com/chwl/app/ui/widget/dialog/OpenNobleDialog.java new file mode 100644 index 0000000..e23c11a --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/dialog/OpenNobleDialog.java @@ -0,0 +1,81 @@ +package com.chwl.app.ui.widget.dialog; + +import android.content.Context; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; +import android.widget.TextView; + +import androidx.appcompat.app.AppCompatDialog; + +import com.chwl.app.R; +import com.chwl.app.ui.webview.CommonWebViewActivity; +import com.chwl.core.UriProvider; +import com.chwl.core.noble.NobleUtil; +import com.chwl.library.utils.ResUtil; + +/** + *

开通贵族弹窗提示

+ * + * @author jiahui + * @date 2018/1/17 + */ +public class OpenNobleDialog extends AppCompatDialog implements View.OnClickListener { + public static final String TAG = "OpenNobleDialog"; + private TextView tvTitle; + private TextView tvFirstLine; + private TextView tvSecondLine; + private int currentLevel; + private int needLevel; + /** 比如 送该礼物 / 发送该表情 */ + private String xxxOperation; + + public OpenNobleDialog(Context context, int currentLevel, int needLevel, String xxxOperation) { + super(context, R.style.ErbanUserInfoDialog); + this.currentLevel = currentLevel; + this.needLevel = needLevel; + this.xxxOperation = xxxOperation; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + setContentView(R.layout.fragment_dialog_open_noble); + setCanceledOnTouchOutside(true); + findViewById(R.id.btn_close).setOnClickListener(this); + findViewById(R.id.btn_open_noble).setOnClickListener(this); + tvTitle = (TextView) findViewById(R.id.tv_title); + tvFirstLine = (TextView) findViewById(R.id.tv_first_line); + tvSecondLine = (TextView) findViewById(R.id.tv_second_line); + + // 点击房间在线列表的贵族位置 + if (currentLevel == 0 && needLevel == 0 && TextUtils.isEmpty(xxxOperation)) { + tvTitle.setText(ResUtil.getString(R.string.widget_dialog_opennobledialog_01)); + tvFirstLine.setText(ResUtil.getString(R.string.widget_dialog_opennobledialog_02)); + tvSecondLine.setText(ResUtil.getString(R.string.widget_dialog_opennobledialog_03)); + } else { + // 显示文案 + String currentLevelName = TextUtils.isEmpty(NobleUtil.getNobleName(currentLevel)) ? ResUtil.getString(R.string.widget_dialog_opennobledialog_04) : NobleUtil.getNobleName(currentLevel); + String needNobleName = TextUtils.isEmpty(NobleUtil.getNobleName(needLevel)) ? ResUtil.getString(R.string.widget_dialog_opennobledialog_05) : NobleUtil.getNobleName(needLevel); + String firstLineText = getContext().getResources().getString(R.string.noble_current_level, currentLevelName); + String secondLineText = getContext().getResources().getString(R.string.noble_need_level, needNobleName); + tvTitle.setText(secondLineText); + tvFirstLine.setText(ResUtil.getString(R.string.widget_dialog_opennobledialog_06)); + tvSecondLine.setText(firstLineText); + } + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.btn_close: + dismiss(); + break; + case R.id.btn_open_noble: + String query = (needLevel <= 0) ? "" : "?nobleId=" + needLevel; + CommonWebViewActivity.start(getContext(), UriProvider.getNobleIntro() + query); + dismiss(); + break; + default: + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/dialog/OpenNobleGlobalNoticeDialog.java b/app/src/main/java/com/chwl/app/ui/widget/dialog/OpenNobleGlobalNoticeDialog.java new file mode 100644 index 0000000..9cfbc24 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/dialog/OpenNobleGlobalNoticeDialog.java @@ -0,0 +1,77 @@ +package com.chwl.app.ui.widget.dialog; + +import android.animation.Animator; +import android.content.Context; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.Gravity; +import android.view.Window; +import android.view.WindowManager; + +import androidx.appcompat.app.AppCompatDialog; + +import com.chwl.app.R; +import com.chwl.app.ui.widget.MarqueeLayout; +import com.chwl.library.utils.SizeUtils; + +/** + *

+ * + * @author jiahui + * @date 2018/1/22 + */ +public class OpenNobleGlobalNoticeDialog extends AppCompatDialog implements MarqueeLayout.OnAnimatorListener { + + private MarqueeLayout mMarqueeLayout; + private CharSequence mContent; + + public OpenNobleGlobalNoticeDialog(Context context, CharSequence content) { + this(context, 0); + mContent = content; + } + + public OpenNobleGlobalNoticeDialog(Context context, int theme) { + super(context, theme); + } + + protected OpenNobleGlobalNoticeDialog(Context context, boolean cancelable, OnCancelListener cancelListener) { + super(context, cancelable, cancelListener); + } + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.noble_open_global_notice_layout); + mMarqueeLayout = (MarqueeLayout) findViewById(R.id.marquee_view); + + Window window = getWindow(); + if (window != null) { + window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); + WindowManager.LayoutParams windowParams = window.getAttributes(); + windowParams.width = WindowManager.LayoutParams.MATCH_PARENT; + windowParams.dimAmount = 0.0f; + windowParams.gravity = Gravity.TOP ; + windowParams.x = 0; + windowParams.y = SizeUtils.dp2px(getContext(), 100); + window.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL); + window.setAttributes(windowParams); + } + + if (TextUtils.isEmpty(mContent)) dismiss(); + + mMarqueeLayout.setOnAnimatorListener(this); + mMarqueeLayout.setText(mContent); + mMarqueeLayout.startMarquee(); + } + + + @Override + public void onAnimationEnd(Animator animation) { + if (isShowing()) { + dismiss(); + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/drawgift/DrawGiftHelper.java b/app/src/main/java/com/chwl/app/ui/widget/drawgift/DrawGiftHelper.java new file mode 100644 index 0000000..973353f --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/drawgift/DrawGiftHelper.java @@ -0,0 +1,134 @@ +package com.chwl.app.ui.widget.drawgift; + +import android.app.Activity; +import android.graphics.Bitmap; +import android.graphics.drawable.Drawable; +import android.util.SparseArray; +import android.view.WindowManager; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.bumptech.glide.request.target.CustomTarget; +import com.bumptech.glide.request.transition.Transition; +import com.netease.nim.uikit.common.util.sys.ScreenUtil; +import com.netease.nim.uikit.support.glide.GlideApp; +import com.chwl.app.R; +import com.chwl.library.utils.ResUtil; + +import java.util.List; + +public class DrawGiftHelper { + //为了节省内存。通过giftId当做Key来缓存Bitmap(如果你的giftId是String,那么这里要修改成HashMap) + //其实这个东西你可以做成单例。我现在没用单例,就需要每次进入直播间都重新缓存 + private final SparseArray cacheBitmapByGiftIdMap; + private final Activity activity; + private DrawGiftView drawGiftView; + + public DrawGiftHelper(Activity activity) { + this.activity = activity; + cacheBitmapByGiftIdMap = new SparseArray<>(); + } + + public void lazyDrawGiftView(int bottomSheetHeight, DrawGiftView.DrawGiftListener onDrawGiftListener) { + if (drawGiftView == null) { + drawGiftView = new DrawGiftView(activity); + int newSize = ScreenUtil.dip2px(10); + drawGiftView.setDrawStrokeInterval(newSize); + drawGiftView.setOnDrawGiftListener(onDrawGiftListener); + drawGiftView.showInActivityWindow(activity, bottomSheetHeight); + drawGiftView.setPlaceHolderText(ResUtil.getString(R.string.widget_drawgift_drawgifthelper_01)); + } + } + + public void setCurrentGift(int giftId, String giftUrl, int giftPrice) { + if (drawGiftView == null) return; + GlideApp.with(activity) + .asBitmap() + .load(giftUrl) + .into(new CustomTarget() { + @Override + public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition transition) { + if (drawGiftView!=null){ + drawGiftView.setCurrentGift(giftId, obtainThumbBitmap(giftId, resource), giftPrice); + } + } + + @Override + public void onLoadCleared(@Nullable Drawable placeholder) { + + } + }); + } + + //是否可以画 + public void setDrawEnable(boolean drawEnable) { + if (drawGiftView != null) { + drawGiftView.setDrawEnable(drawEnable); + } + } + + public void setMaxDrawSize(int maxDrawSize) { + if (drawGiftView != null) { + drawGiftView.setMaxDrawSize(maxDrawSize); + } + } + + public void removeLastStroke() { + if (drawGiftView != null) { + drawGiftView.removeLastStroke(); + } + } + + public void clearDrawGift() { + if (drawGiftView != null) { + drawGiftView.removeAll(); + } + } + + @Nullable + public List> getDrawFixedArray() { + if (drawGiftView != null) { + return drawGiftView.transformGiftArrayFitScreen(activity); + } + return null; + } + + //计算需要的金币并setText + public int getTotalPrice() { + int totalPrice = 0; + List allDrawGiftArray = drawGiftView.getAllDrawGiftArray(); + for (DrawGiftModel giftModel : allDrawGiftArray) { + totalPrice += giftModel.getGiftPrice(); + } + return totalPrice; + } + + public int getDrawGiftSize() { + return drawGiftView == null ? 0 : drawGiftView.getAllDrawGiftArray().size(); + } + + public void resetDrawGiftView() { + if (drawGiftView != null) { + //底部弹框消失 + //移除掉draw礼物View层。 + //FrameLayout contentParent = (FrameLayout) getWindow().getDecorView().findViewById(android.R.id.content); + WindowManager mWindowManager = activity.getWindowManager(); + mWindowManager.removeView(drawGiftView); + //如果不 = null,leakCanary会报内存泄漏,但其实是误报 + drawGiftView = null; + } + } + + //从缓存里取出bitmap + private Bitmap obtainThumbBitmap(int giftId, Bitmap largeBitmap) { + Bitmap thumbGiftBitmap = cacheBitmapByGiftIdMap.get(giftId); + if (thumbGiftBitmap == null) { + int newSize = ScreenUtil.dip2px(20); + thumbGiftBitmap = Bitmap.createScaledBitmap(largeBitmap, newSize, newSize, true); + cacheBitmapByGiftIdMap.put(giftId, thumbGiftBitmap); + } + return thumbGiftBitmap; + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/drawgift/DrawGiftModel.java b/app/src/main/java/com/chwl/app/ui/widget/drawgift/DrawGiftModel.java new file mode 100644 index 0000000..17c7ac3 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/drawgift/DrawGiftModel.java @@ -0,0 +1,67 @@ +package com.chwl.app.ui.widget.drawgift; + +import android.graphics.Bitmap; +import android.graphics.Matrix; + +public class DrawGiftModel { + + private float x; + private float y; + private int giftId; + private int giftPrice;//礼物价格,为了方便画的过程中,快速的计算出当前一共画了多少钱的礼物,默认0 + private Bitmap giftBitmap; + + //在收到礼物显示动画的时候,本demo为了体现出礼物放大消失的动画,引入了这个Matrix参数,如果没有放大动画,就不需要这两个 + private Matrix matrix; + + public float getX() { + return x; + } + + public void setX(float x) { + this.x = x; + } + + public float getY() { + return y; + } + + public void setY(float y) { + this.y = y; + } + + public int getgiftId() { + return giftId; + } + + public void setgiftId(int giftId) { + this.giftId = giftId; + } + + public Bitmap getGiftBitmap() { + return giftBitmap; + } + + public void setGiftBitmap(Bitmap giftBitmap) { + this.giftBitmap = giftBitmap; + } + + public Matrix getMatrix() { + if (matrix == null){ + matrix = new Matrix(); + } + return matrix; + } + + public void setMatrix(Matrix matrix) { + this.matrix = matrix; + } + + public int getGiftPrice() { + return giftPrice; + } + + public void setGiftPrice(int giftPrice) { + this.giftPrice = giftPrice; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/drawgift/DrawGiftPlayHelper.java b/app/src/main/java/com/chwl/app/ui/widget/drawgift/DrawGiftPlayHelper.java new file mode 100644 index 0000000..bc89ff4 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/drawgift/DrawGiftPlayHelper.java @@ -0,0 +1,165 @@ +package com.chwl.app.ui.widget.drawgift; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.util.DisplayMetrics; +import android.util.SparseArray; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.widget.FrameLayout; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.FutureTarget; +import com.netease.nim.uikit.common.util.sys.ScreenUtil; +import com.chwl.app.R; +import com.chwl.core.gift.GiftModel; +import com.chwl.core.gift.bean.GiftInfo; +import com.chwl.library.utils.ListUtils; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; + +public class DrawGiftPlayHelper { + //为了节省内存。通过giftId当做Key来缓存Bitmap(如果你的giftId是String,那么这里要修改成HashMap) + //其实这个东西你可以做成单例。我现在没用单例,就需要每次进入直播间都重新缓存 + private final SparseArray cacheBitmapByGiftIdMap; + private final Activity activity; + private MyHandler handler; + //播放礼物动画的层 + private DrawGiftPlayView playView; + + public DrawGiftPlayHelper(Activity activity) { + this.activity = activity; + cacheBitmapByGiftIdMap = new SparseArray<>(); + } + + //播放礼物draw动画,insertToFirst = 是否插入到队列前面 + public void playDrawGift(List allDrawGiftArray, boolean insertToFirst) { + if (playView == null) { + playView = new DrawGiftPlayView(activity); + playView.setOnDrawAnimationListener(new DrawGiftPlayView.DrawAnimationListener() { + + @Override + public void onAnimationNodeEnd(DrawGiftPlayView drawGiftPlayView) { + + } + + @Override + public void onAnimationAllOver(DrawGiftPlayView drawGiftPlayView) { + //动画放完了,移除掉播放礼物View层。当然这里你也可以不移除,一直保留 + FrameLayout contentParent = (FrameLayout) activity.getWindow().getDecorView().findViewById(android.R.id.content); + contentParent.removeView(drawGiftPlayView); + } + }); + } + + if (playView.getParent() == null) { + //添加到decorView + FrameLayout contentParent = (FrameLayout) activity.getWindow().getDecorView().findViewById(android.R.id.content); + FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + layoutParams.topMargin = ScreenUtil.getStatusBarHeight(activity); + playView.setLayoutParams(layoutParams); + contentParent.addView(playView); + } + + playView.addDrawGifts(allDrawGiftArray, insertToFirst); + } + + //子线程处理播放礼物的数据 + public void prepareShowDrawGift(int giftId, List> fixedArray, boolean insertToFirst) { + if (ListUtils.isListEmpty(fixedArray)) return; + //把服务器推送来的ResUtil.getString(R.string.widget_drawgift_drawgiftplayhelper_01) 和 本地的 giftBeanList 一一对应上,找到礼物的bitmap + final List allDrawGiftArray = new ArrayList<>(); + + //经过测试,这个子线程耗时仅为30ms左右(前提是bitmap已经被是从本地取的) + Thread thread = new Thread() { + @Override + public void run() { + + //本机屏幕宽高 + DisplayMetrics displayMetrics = new DisplayMetrics(); + ((WindowManager) activity.getApplicationContext().getSystemService(Context.WINDOW_SERVICE)) + .getDefaultDisplay().getMetrics(displayMetrics); + float viewWidth = displayMetrics.widthPixels; + float viewHeight = displayMetrics.heightPixels; + GiftInfo giftBean = GiftModel.get().findGiftInfoById(giftId); + Bitmap thumbGiftBitmap = cacheBitmapByGiftIdMap.get(giftId); + + //fixedArray 是服务器推送过来的礼物json + for (List fixedMap : fixedArray) { + + //将服务器推送来的x,y转成绝对像素坐标 + DrawGiftModel drawGiftModel = new DrawGiftModel(); + drawGiftModel.setX(fixedMap.get(0) / 1000f * viewWidth); + drawGiftModel.setY(fixedMap.get(1) / 1000f * viewHeight); + if (thumbGiftBitmap != null) { + //缓存中就有bitmap + drawGiftModel.setGiftBitmap(thumbGiftBitmap); + } else { + //缓存没有bitmap + //从Glide里找出礼物的bitmap + FutureTarget futureBitmap = Glide.with(activity).asBitmap() + .load(giftBean.getGiftUrl()) + .submit(); + try { + Bitmap bitmap = futureBitmap.get(); + thumbGiftBitmap = obtainThumbBitmap(giftId, bitmap); + drawGiftModel.setGiftBitmap(thumbGiftBitmap); + } catch (Exception e) { + e.printStackTrace(); + //万一下载失败了,取本地的图片占位 + Bitmap errorBitmap = BitmapFactory.decodeResource(activity.getResources(), R.drawable.default_cover); + drawGiftModel.setGiftBitmap(errorBitmap); + } + } + allDrawGiftArray.add(drawGiftModel); + } + + if (handler == null) handler = new MyHandler(DrawGiftPlayHelper.this); + Message message = Message.obtain(handler, 1, insertToFirst ? 1 : 0, 0, allDrawGiftArray); + handler.sendMessage(message); + } + }; + thread.start(); + } + + //从缓存里取出bitmap + private Bitmap obtainThumbBitmap(int giftId, Bitmap largeBitmap) { + Bitmap thumbGiftBitmap = cacheBitmapByGiftIdMap.get(giftId); + if (thumbGiftBitmap == null) { + int newSize = ScreenUtil.dip2px(20); + thumbGiftBitmap = Bitmap.createScaledBitmap(largeBitmap, newSize, newSize, true); + cacheBitmapByGiftIdMap.put(giftId, thumbGiftBitmap); + } + return thumbGiftBitmap; + } + + private static class MyHandler extends Handler { + + private final WeakReference reference; + + public MyHandler(DrawGiftPlayHelper context) { + super(Looper.getMainLooper()); + reference = new WeakReference<>(context); + } + + @Override + public void handleMessage(Message msg) { + final DrawGiftPlayHelper activity = (DrawGiftPlayHelper) reference.get(); + if (activity == null) { + return; + } + if (msg.what == 1) { + List allDrawGiftArray = (List) msg.obj; + activity.playDrawGift(allDrawGiftArray, msg.arg1 == 1); + } + } + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/drawgift/DrawGiftPlayView.java b/app/src/main/java/com/chwl/app/ui/widget/drawgift/DrawGiftPlayView.java new file mode 100644 index 0000000..c9e2e1b --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/drawgift/DrawGiftPlayView.java @@ -0,0 +1,216 @@ +package com.chwl.app.ui.widget.drawgift; + +import android.animation.Animator; +import android.animation.ValueAnimator; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.os.Handler; +import android.os.Message; +import android.util.AttributeSet; +import android.view.View; + +import java.util.LinkedList; +import java.util.List; + +public class DrawGiftPlayView extends View { + + //需要被画上的全部的礼物,采用链表的方式,每次取第0个 + private final LinkedList> allDrawGiftsLinkedList; + + //当前这幅画播放到第几个礼物 + private int currentGiftShowIndex; + + private DrawAnimationListener onDrawAnimationListener; + + //为了体现最后的消失动画效果,才引入了这个Paint + private final Paint mPaint = new Paint();; + + private static final int DRAW_ONE_GIFT = 0; + + private final Handler mHandler; + + private final Handler.Callback mCallback = new Handler.Callback() { + @Override + public boolean handleMessage(Message msg) { + switch (msg.what) { + case DRAW_ONE_GIFT: + //画一个礼物 + currentGiftShowIndex = msg.arg1; + invalidate(); + + if (currentGiftShowIndex == allDrawGiftsLinkedList.getFirst().size()){ + //进入这里,说明已经播放完最后一个礼物了 + //播放扩大动画,然后消失 + ValueAnimator valueAnimator = ValueAnimator.ofFloat(1, 2); + valueAnimator.setDuration(500); + valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + float p = (float) animation.getAnimatedValue(); + //透明效果(所有礼物都做这个动作) + mPaint.setAlpha((int)((2.0F - p) * 255)); + //放大效果(所有礼物都做这个动作) + for (DrawGiftModel giftModel : allDrawGiftsLinkedList.getFirst()) { + + giftModel.getMatrix().reset(); + giftModel.getMatrix().preTranslate(giftModel.getX() - giftModel.getGiftBitmap().getWidth() / 2F, giftModel.getY() - giftModel.getGiftBitmap().getHeight() / 2F); + giftModel.getMatrix().postScale((float) (1.0F + (p - 1) * 0.4), (float) (1.0F + (p - 1) * 0.4), giftModel.getX(), giftModel.getY()); + } + + invalidate(); + } + }); + valueAnimator.addListener(new Animator.AnimatorListener(){ + + @Override + public void onAnimationStart(Animator animation) { + + } + + @Override + public void onAnimationEnd(Animator animation) { + //放大动画结束 + mPaint.reset(); + + currentGiftShowIndex = 0; + allDrawGiftsLinkedList.removeFirst(); + + if (onDrawAnimationListener != null) { + //当前的这一幅画结束 + onDrawAnimationListener.onAnimationNodeEnd(DrawGiftPlayView.this); + + if (allDrawGiftsLinkedList.isEmpty()){ + //所有画全部结束 + onDrawAnimationListener.onAnimationAllOver(DrawGiftPlayView.this); + } else { + //还有画没播完,继续画下一幅画 + //要先清理掉画布上的上一幅画 + invalidate(); + + Message message = Message.obtain(); + message.arg1 = 0; + message.what = DRAW_ONE_GIFT; + mHandler.sendMessageDelayed(message, 50); + } + } + } + + @Override + public void onAnimationCancel(Animator animation) { + + } + + @Override + public void onAnimationRepeat(Animator animation) { + + } + }); + valueAnimator.start(); + } else { + //继续画下一个礼物 + Message message = Message.obtain(); + message.arg1 = currentGiftShowIndex + 1; + message.what = DRAW_ONE_GIFT; + mHandler.sendMessageDelayed(message, 50); + } + + return true; + } + return true; + } + }; + + public DrawGiftPlayView(Context context) { + this(context, null); + } + + public DrawGiftPlayView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public DrawGiftPlayView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + mHandler = new Handler(mCallback); + allDrawGiftsLinkedList = new LinkedList>(); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + int size = allDrawGiftsLinkedList.getFirst().size(); + for(int i = 0; i <= currentGiftShowIndex && i < size; i++) { + DrawGiftModel giftModel = allDrawGiftsLinkedList.getFirst().get(i); + canvas.drawBitmap(giftModel.getGiftBitmap(), giftModel.getMatrix(), mPaint); + } + } + + public void addDrawGifts(List currentDrawGiftArray, boolean insertToFirst){ + + //处理每个小bitmap的大小和位置 + for(int i = 0; i < currentDrawGiftArray.size(); i++) { + DrawGiftModel giftModel = currentDrawGiftArray.get(i); + + giftModel.getMatrix().reset(); + giftModel.getMatrix().postTranslate(giftModel.getX() - giftModel.getGiftBitmap().getWidth() / 2F, giftModel.getY() - giftModel.getGiftBitmap().getHeight() / 2F); + } + + //添加到队列 + if (insertToFirst){ + if (allDrawGiftsLinkedList.size() > 0){ + //说明队列里已经有画在draw了。 + //由于我目前的逻辑是:取first节点,画完了再remove;而不是先remove再设置为全局变量。所以要插入到第1个元素 + allDrawGiftsLinkedList.add(1, currentDrawGiftArray); + } else { + //说明当前列表是空的,直接插入到表头 + allDrawGiftsLinkedList.offerFirst(currentDrawGiftArray); + } + } else { + //插入到表尾 + allDrawGiftsLinkedList.offerLast(currentDrawGiftArray); + } + + if (allDrawGiftsLinkedList.size() == 1){ + //刚插入完,size==1,说明是刚开始,这时候要开始播放 + List firstDrawGiftArray = this.allDrawGiftsLinkedList.getFirst(); + + if (firstDrawGiftArray != null){ + //说明有需要播放的,开始draw + Message message = Message.obtain(); + message.arg1 = 0; + message.what = DRAW_ONE_GIFT; + mHandler.sendMessage(message); + } + } + } + + @Override + public void onAttachedToWindow(){ + super.onAttachedToWindow(); + } + + @Override + public void onDetachedFromWindow() { + super.onDetachedFromWindow(); + mHandler.removeCallbacksAndMessages(null); + mPaint.reset(); + currentGiftShowIndex = 0; + } + + public void setOnDrawAnimationListener(DrawAnimationListener onDrawAnimationListener) { + this.onDrawAnimationListener = onDrawAnimationListener; + } + + public interface DrawAnimationListener{ + //礼物动画全部结束 + public void onAnimationNodeEnd(DrawGiftPlayView drawGiftPlayView); + //礼物动画当前的这一幅画结束 + public void onAnimationAllOver(DrawGiftPlayView drawGiftPlayView); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/drawgift/DrawGiftView.java b/app/src/main/java/com/chwl/app/ui/widget/drawgift/DrawGiftView.java new file mode 100644 index 0000000..e5fbf52 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/drawgift/DrawGiftView.java @@ -0,0 +1,354 @@ +package com.chwl.app.ui.widget.drawgift; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.PorterDuff; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.view.WindowManager; + +import com.netease.nim.uikit.common.util.sys.ScreenUtil; +import com.chwl.app.R; +import com.chwl.library.utils.ResUtil; + +import java.util.ArrayList; +import java.util.List; + +//手绘礼物的View +public class DrawGiftView extends View { + + private final Bitmap placeholderBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.drawgift_placeholder); + private final Paint textPaint = new Paint(); + //当前被画上去的全部的DrawGiftModel + private List allDrawGiftArray; + private float mLastX; + private float mLastY; + //每一笔的最后一个图的index,所以:这个List.size = 一共几笔 + private List strokeFirstPositionArray; + private DrawGiftListener onDrawGiftListener; + //当前选中的礼物的id和bitmap + private int currentGiftId; + private Bitmap currentGiftBitmap; + private int currentGiftPrice; + //连续两个礼物之间的间距(像素),0表示用当前礼物的宽 + private int drawStrokeInterval; + //是否可以画 + private boolean drawEnable = false; + //没画的时候,显示的默认文本 + private String placeHolderText = ResUtil.getString(R.string.widget_drawgift_drawgiftview_01); + private int maxDrawSize = 300; + //一次触摸事件只调用一次onReachMaxDrawSize + private boolean isCallMaxDrawSize; + + + public DrawGiftView(Context context) { + this(context, null); + } + + public DrawGiftView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public DrawGiftView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + private void init() { + textPaint.setStyle(Paint.Style.FILL); + textPaint.setColor(0xff999999); + textPaint.setStrokeWidth(8); + textPaint.setTextSize(ScreenUtil.dip2px(20)); + textPaint.setTextAlign(Paint.Align.CENTER); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + if (!drawEnable) { + //因为选了普通礼物,所以当前View不能画 + //这时候要清空之前画的内容(一定要draw一些东西,只调用invalidate的话无法清空) + canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); + return; + } + + if (allDrawGiftArray.isEmpty()) { + float placeHolderViewHeight = 500; + canvas.drawBitmap(placeholderBitmap, (getWidth() - placeholderBitmap.getWidth()) / 2f, (getHeight() - placeHolderViewHeight) / 2, null); + if (placeHolderText != null) { + float baseline = (getHeight() - placeHolderViewHeight) / 2 + placeholderBitmap.getHeight() + 60; + canvas.drawText(placeHolderText, getWidth() / 2f, baseline, textPaint); + } + } else { + for (DrawGiftModel giftModel : allDrawGiftArray) { + canvas.drawBitmap(giftModel.getGiftBitmap(), giftModel.getX() - giftModel.getGiftBitmap().getWidth() / 2f, giftModel.getY() - giftModel.getGiftBitmap().getHeight() / 2f, null); + //这里肯定是不能recycle的 + } + } + } + + //正常情况下一个View的如果Down事件return false,那么就吃不到后面的move事件了。 + //但是本View是被windowManager.addView(view) 添加到windowManager层。那么后续的move up都肯定会触发 + @Override + public boolean onTouchEvent(MotionEvent event) { + int action = event.getAction(); + switch (action) { + case MotionEvent.ACTION_DOWN: + if (!drawEnable || currentGiftBitmap == null) { + //不允许画 || 当前没选中任何礼物 + return super.onTouchEvent(event); + } + isCallMaxDrawSize = false; + + if (allDrawGiftArray.size() >= maxDrawSize) { + if (onDrawGiftListener != null) { + isCallMaxDrawSize = true; + onDrawGiftListener.onReachMaxDrawSize(); + } + return super.onTouchEvent(event); + } + //点下 + mLastX = checkIfBelongHorizontalEdge(event.getX()); + mLastY = checkIfBelongVerticalEdge(event.getY()); + addDrawGiftModel(mLastX, mLastY, currentGiftBitmap); + invalidate(); + + //记录这一笔的开头 + strokeFirstPositionArray.add(allDrawGiftArray.size() - 1); + return true; + case MotionEvent.ACTION_MOVE: + if (!drawEnable || currentGiftBitmap == null) { + //不允许画 || 当前没选中任何礼物 + return super.onTouchEvent(event); + } + if (allDrawGiftArray.size() >= maxDrawSize) { + if (onDrawGiftListener != null && !isCallMaxDrawSize) { + isCallMaxDrawSize = true; + onDrawGiftListener.onReachMaxDrawSize(); + } + return super.onTouchEvent(event); + } + float moveX = checkIfBelongHorizontalEdge(event.getX()); + float moveY = checkIfBelongVerticalEdge(event.getY()); + + //距离上一个礼物的移动距离 + float distance = (float) (Math.pow(moveX - mLastX, 2) + Math.pow(moveY - mLastY, 2)); + //理应移动多少才需要画新礼物 + float reference = (float) Math.pow(drawStrokeInterval == 0 ? currentGiftBitmap.getWidth() : drawStrokeInterval, 2); + + if (distance >= reference) { + //距离拉开了,应该画新礼物 + if (moveX >= getLeft() && moveX < getRight() && moveY >= getTop() && moveY < getBottom()) { + //看看新礼物是否在View内 + addDrawGiftModel(moveX, moveY, currentGiftBitmap); + mLastX = moveX; + mLastY = moveY; + invalidate(); + } else { + //越界 + } + } + break; + case MotionEvent.ACTION_CANCEL: + break; + case MotionEvent.ACTION_UP: + if (!drawEnable && onDrawGiftListener != null) { + //不允许画,那么要回调up事件,为了让底部的sheet收起来 + onDrawGiftListener.onTouchEventUpWhenDrawDisable(this); + } + + break; + } + return super.onTouchEvent(event); + } + + private void addDrawGiftModel(float x, float y, Bitmap bitmap) { + DrawGiftModel mDIYGiftModel = new DrawGiftModel(); + mDIYGiftModel.setGiftBitmap(bitmap); + mDIYGiftModel.setgiftId(currentGiftId); + mDIYGiftModel.setGiftPrice(currentGiftPrice); + mDIYGiftModel.setX(x); + mDIYGiftModel.setY(y); + allDrawGiftArray.add(mDIYGiftModel); + if (onDrawGiftListener != null) { + onDrawGiftListener.onGiftPainted(this, currentGiftId); + } + } + + //检查是否是屏幕边缘 + private float checkIfBelongHorizontalEdge(float intrinsicX) { + if (intrinsicX > getWidth() - (currentGiftBitmap.getWidth() / 2)) { + //超过右边界 + return getWidth() - (currentGiftBitmap.getWidth() / 2); + } else if (intrinsicX < currentGiftBitmap.getWidth() / 2) { + //超过左边界 + return currentGiftBitmap.getWidth() / 2; + } else { + return intrinsicX; + } + } + + //检查是否是屏幕边缘 + private float checkIfBelongVerticalEdge(float intrinsicY) { + if (intrinsicY > getHeight() - (currentGiftBitmap.getHeight() / 2)) { + //超过右边界 + return getHeight() - (currentGiftBitmap.getHeight() / 2); + } else if (intrinsicY < currentGiftBitmap.getHeight() / 2) { + //超过左边界 + return currentGiftBitmap.getHeight() / 2; + } else { + return intrinsicY; + } + } + + //清空当前画的所有礼物 + public void removeAll() { + strokeFirstPositionArray.clear(); + allDrawGiftArray.clear(); + postInvalidate(); + } + + //移除最后一笔 + public void removeLastStroke() { + if (strokeFirstPositionArray.isEmpty()) { + return; + } + + int lastStrokeIndex = strokeFirstPositionArray.get(strokeFirstPositionArray.size() - 1); + + //先从全部礼物里删除最后一笔礼物 + for (int i = allDrawGiftArray.size() - 1; i >= lastStrokeIndex; i--) { + allDrawGiftArray.remove(i); + } + + //移除最后一笔的记录点 + strokeFirstPositionArray.remove(strokeFirstPositionArray.size() - 1); + + invalidate(); + } + + //设置当前这笔礼物 + public void setCurrentGift(int giftId, Bitmap giftBitmap, int giftPrice) { + this.currentGiftId = giftId; + this.currentGiftBitmap = giftBitmap; + this.currentGiftPrice = giftPrice; + } + + //bottomSheetHeight是底部不能画的区域的高度 + public void showInActivityWindow(Activity activity, int bottomSheetHeight) { + WindowManager mWindowManager = activity.getWindowManager(); + WindowManager.LayoutParams wl = new WindowManager.LayoutParams(); + + //用TYPE_APPLICATION 是本View所在的层级,如果太高了(超过了应用)还要申请权限 + wl.type = WindowManager.LayoutParams.TYPE_APPLICATION; + + //据说这个可以让触摸事件穿透到view层,但是我们的sheet是dialog,所以无用 +// wl.flags = WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE; + + wl.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; + wl.gravity = Gravity.TOP;//这个top会盖住titleBar,但是盖不住状态栏 + wl.width = WindowManager.LayoutParams.MATCH_PARENT; + wl.height = activity.getWindow().getDecorView().findViewById(android.R.id.content).getHeight() - bottomSheetHeight; + wl.token = activity.getWindow().getAttributes().token; + wl.format = PixelFormat.TRANSLUCENT;//Toast就是用这个实现的透明 + //wl.alpha = 0.7f; + mWindowManager.addView(this, wl); + } + + @Override + public void onAttachedToWindow() { + super.onAttachedToWindow(); + allDrawGiftArray = new ArrayList<>(); + strokeFirstPositionArray = new ArrayList<>(); + } + + @Override + public void onDetachedFromWindow() { + super.onDetachedFromWindow(); + allDrawGiftArray.clear(); + strokeFirstPositionArray.clear(); + } + + @Override + public void onFinishInflate() { + super.onFinishInflate(); + } + + public List getAllDrawGiftArray() { + return allDrawGiftArray; + } + + //由于不同手机屏幕尺寸不同,如果礼物画在大屏幕的最右边(X很大)在小屏幕上绘制礼物的时候,X会超出屏幕。因此在这里转成百分比再上传给服务器 + public List> transformGiftArrayFitScreen(Context context) { + + DisplayMetrics displayMetrics = new DisplayMetrics(); + ((WindowManager) context.getApplicationContext().getSystemService(Context.WINDOW_SERVICE)) + .getDefaultDisplay().getMetrics(displayMetrics); + + //fixedArray是需要转成json发送给服务器的 + List> fixedArray = new ArrayList<>(); + float viewWidth = displayMetrics.widthPixels; + float viewHeight = displayMetrics.heightPixels; + List param = null; + for (DrawGiftModel giftModel : allDrawGiftArray) { + //x 和 y转为屏幕比例 + param = new ArrayList<>(); + param.add((int) ((giftModel.getX() / viewWidth) * 1000)); + param.add((int) ((giftModel.getY() / viewHeight) * 1000)); + fixedArray.add(param); + } + return fixedArray; + } + + //连续两个礼物之间的间距(像素),0表示用当前礼物的宽 + public void setDrawStrokeInterval(int drawStrokeInterval) { + this.drawStrokeInterval = drawStrokeInterval; + } + + //还没画的时候,提示语 + public void setPlaceHolderText(String placeHolderText) { + this.placeHolderText = placeHolderText; + invalidate(); + } + + public void setMaxDrawSize(int maxDrawSize) { + this.maxDrawSize = maxDrawSize; + } + + //是否可以画 + public void setDrawEnable(boolean drawEnable) { + if (drawEnable != this.drawEnable) { + this.drawEnable = drawEnable; + if (!drawEnable) { + allDrawGiftArray.clear(); + strokeFirstPositionArray.clear(); + } + invalidate(); + } + } + + public void setOnDrawGiftListener(DrawGiftListener onDrawGiftListener) { + this.onDrawGiftListener = onDrawGiftListener; + } + + public interface DrawGiftListener { + + void onReachMaxDrawSize(); + + //新的礼物节点被画上 + public void onGiftPainted(DrawGiftView drawGiftView, int giftId); + + //当drawDisable的情况下,触发的touchUp回调 + public void onTouchEventUpWhenDrawDisable(DrawGiftView drawGiftView); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/dynamicface/DynamicFaceAdapter.java b/app/src/main/java/com/chwl/app/ui/widget/dynamicface/DynamicFaceAdapter.java new file mode 100644 index 0000000..1b94745 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/dynamicface/DynamicFaceAdapter.java @@ -0,0 +1,116 @@ +package com.chwl.app.ui.widget.dynamicface; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +import com.chwl.app.R; +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.app.vip.util.VipHelper; +import com.chwl.core.gift.bean.SimpleVipInfo; +import com.chwl.core.room.face.FaceInfo; +import com.chwl.core.utils.CoreTextUtils; +import com.chwl.library.utils.config.BasicConfig; + +import java.io.File; +import java.util.List; + +/** + * @author chenran + * @date 2017/9/8 + */ + +public class DynamicFaceAdapter extends BaseAdapter implements View.OnClickListener { + private List faceInfoList; + private Context context; + private OnFaceItemClickListener onFaceItemClickListener; + + public DynamicFaceAdapter(Context context, List faceInfoList) { + this.faceInfoList = faceInfoList; + this.context = context; + } + + public void setOnFaceItemClickListener(OnFaceItemClickListener onFaceItemClickListener) { + this.onFaceItemClickListener = onFaceItemClickListener; + } + + @Override + public int getCount() { + if (faceInfoList == null) { + return 0; + } else { + return faceInfoList.size(); + } + } + + @Override + public Object getItem(int position) { + return null; + } + + @Override + public long getItemId(int position) { + return 0; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + FaceViewHolder holder; + if (null == convertView) { + holder = new FaceViewHolder(); + //mContext指的是调用的Activity + convertView = LayoutInflater.from(context).inflate(R.layout.list_item_face, null); + holder.faceIcon = (ImageView) convertView.findViewById(R.id.face_image); + holder.faceName = (TextView) convertView.findViewById(R.id.face_name); + holder.container = convertView.findViewById(R.id.face_layout); + holder.ivNobleTag = convertView.findViewById(R.id.iv_noble_tag); + holder.ivVipLocked = convertView.findViewById(R.id.iv_vip_locked); + convertView.setTag(holder); + } else { + holder = (FaceViewHolder) convertView.getTag(); + } + FaceInfo faceInfo = faceInfoList.get(position); + holder.container.setTag(faceInfo); + holder.container.setOnClickListener(this); + File file = new File(faceInfo.getFacePath(faceInfo.getIconImageIndex())); + ImageLoadUtils.loadImage(BasicConfig.INSTANCE.getAppContext(), file, holder.faceIcon); + holder.faceName.setText(faceInfo.getCNName()); + SimpleVipInfo vipInfo = faceInfo.getFaceVipInfo(); + boolean isLocked = vipInfo != null && VipHelper.getMyVipLevel() < vipInfo.getVipLevel(); + holder.ivVipLocked.setVisibility(isLocked ? View.VISIBLE : View.GONE); + holder.faceIcon.setAlpha(isLocked ? 0.5f : 1f); + String vipIcon = vipInfo == null ? "" : vipInfo.getVipIcon(); + if (CoreTextUtils.isEmptyText(vipIcon)) { + // 普通表情 + holder.ivNobleTag.setImageDrawable(null); + } else { + ImageLoadUtils.loadImage(context, vipIcon, holder.ivNobleTag); + } + + return convertView; + } + + @Override + public void onClick(View v) { + if (onFaceItemClickListener != null) { + FaceInfo faceInfo = (FaceInfo) v.getTag(); + onFaceItemClickListener.onFaceItemClick(faceInfo); + } + } + + public interface OnFaceItemClickListener { + void onFaceItemClick(FaceInfo faceInfo); + } + + private class FaceViewHolder { + private ImageView faceIcon; + private TextView faceName; + private View container; + private ImageView ivNobleTag; + private ImageView ivVipLocked; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/dynamicface/DynamicFaceAdapterNew.kt b/app/src/main/java/com/chwl/app/ui/widget/dynamicface/DynamicFaceAdapterNew.kt new file mode 100644 index 0000000..4c59dcf --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/dynamicface/DynamicFaceAdapterNew.kt @@ -0,0 +1,41 @@ +package com.chwl.app.ui.widget.dynamicface + +import android.view.View +import com.chwl.app.bindadapter.BaseBindingAdapter +import com.chwl.app.databinding.ItemDynamicFaceBinding +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.app.ui.utils.loadImage +import com.chwl.app.vip.util.VipHelper +import com.chwl.core.room.face.FaceInfo +import com.chwl.core.utils.CoreTextUtils +import com.chwl.library.common.util.isVerify +import com.chwl.library.utils.config.BasicConfig +import java.io.File + +class DynamicFaceAdapterNew : BaseBindingAdapter() { + + override fun onBindView(viewBinding: ItemDynamicFaceBinding, data: FaceInfo, pos: Int) { + viewBinding.faceLayout.tag = data + if (data.pic.isVerify()) { + viewBinding.faceImage.loadImage(data.pic) + } else { + val file= File(data.getFacePath(data.iconImageIndex)) + ImageLoadUtils.loadImage(BasicConfig.INSTANCE.appContext, file, viewBinding.faceImage) + } + viewBinding.faceName.text = data.cnName + val vipInfo = data.faceVipInfo + val isLocked = vipInfo != null && VipHelper.getMyVipLevel() < vipInfo.vipLevel + viewBinding.ivVipLocked.setVisibility(if (isLocked) View.VISIBLE else View.GONE) + viewBinding.faceImage.setAlpha(if (isLocked) 0.5f else 1f) + val vipIcon = if (vipInfo == null) "" else vipInfo.vipIcon + if (CoreTextUtils.isEmptyText(vipIcon)) { + // 普通表情 + viewBinding.ivNobleTag.setImageDrawable(null) + } else { + ImageLoadUtils.loadImage(viewBinding.ivNobleTag.context, vipIcon, viewBinding.ivNobleTag) + } + + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/widget/dynamicface/DynamicFaceBuilder.java b/app/src/main/java/com/chwl/app/ui/widget/dynamicface/DynamicFaceBuilder.java new file mode 100644 index 0000000..834d5a5 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/dynamicface/DynamicFaceBuilder.java @@ -0,0 +1,360 @@ +package com.chwl.app.ui.widget.dynamicface; + +/** + * Created by chenran on 2017/9/9. + */ + +public class DynamicFaceBuilder { +// public static final int FACE_ITEM_DAXIAO = 1; +// public static final int FACE_ITEM_LIUHAN = 2; +// public static final int FACE_ITEM_SEMIMI = 3; +// public static final int FACE_ITEM_LIULEI = 4; +// public static final int FACE_ITEM_FEIWEN = 5; +// public static final int FACE_ITEM_JUSANG = 6; +// public static final int FACE_ITEM_WUYAN = 7; +// public static final int FACE_ITEM_KAXINTUSHETOU = 8; +// public static final int FACE_ITEM_BAIBAI = 9; +// public static final int FACE_ITEM_BISHI = 10; +// public static final int FACE_ITEM_EMOHUAIXIAO = 11; +// public static final int FACE_ITEM_TIANSHIWEIXIAO = 12; +// public static final int FACE_ITEM_SHENGQI = 13; +// public static final int FACE_ITEM_BAOBAO = 14; +// public static final int FACE_ITEM_TINGYINYUE = 15; +// public static final int FACE_ITEM_WABIKONG = 16; +// public static final int FACE_ITEM_SHAIZI = 17; +// public static final int FACE_ITEM_SHITOUJIANDAOBU = 18; +// public static final int FACE_ITEM_CHOUQIAN = 19; +// +// private HashMap faceMap; +// +// public DynamicFaceBuilder() { +// faceMap = new HashMap<>(); +// +// } +// +// public int[] daxiao_res = new int[]{ +// R.drawable.daxiao_1_1, +// R.drawable.daxiao_1_2, +// R.drawable.daxiao_1_3, +// R.drawable.daxiao_1_4, +// R.drawable.daxiao_1_5, +// R.drawable.daxiao_1_6 +// }; +// +// public int[] liuhan_res = new int[]{ +// R.drawable.liuhan_2_1, +// R.drawable.liuhan_2_2, +// R.drawable.liuhan_2_3, +// R.drawable.liuhan_2_4, +// R.drawable.liuhan_2_5, +// R.drawable.liuhan_2_6, +// R.drawable.liuhan_2_7, +// R.drawable.liuhan_2_8 +// }; +// +// public int[] semimi_res = new int[]{ +// R.drawable.semimi_3_1, +// R.drawable.semimi_3_2, +// R.drawable.semimi_3_3 +// }; +// +// public int[] liulei_res = new int[]{ +// R.drawable.liulei_4_1, +// R.drawable.liulei_4_2, +// R.drawable.liulei_4_3, +// R.drawable.liulei_4_4 +// }; +// +// public int[] feiwen_res = new int[]{ +// R.drawable.feiwen_5_1, +// R.drawable.feiwen_5_2, +// R.drawable.feiwen_5_3, +// R.drawable.feiwen_5_4, +// R.drawable.feiwen_5_5, +// R.drawable.feiwen_5_6, +// R.drawable.feiwen_5_7, +// R.drawable.feiwen_5_8 +// }; +// +// public int[] jusang_res = new int[]{ +// R.drawable.jusang_6_1, +// R.drawable.jusang_6_2, +// R.drawable.jusang_6_3, +// R.drawable.jusang_6_4, +// R.drawable.jusang_6_5, +// R.drawable.jusang_6_6, +// R.drawable.jusang_6_7, +// R.drawable.jusang_6_8 +// }; +// +// public int[] wuyan_res = new int[]{ +// R.drawable.wuyan_7_1, +// R.drawable.wuyan_7_2, +// R.drawable.wuyan_7_3, +// R.drawable.wuyan_7_4, +// R.drawable.wuyan_7_5, +// R.drawable.wuyan_7_6, +// R.drawable.wuyan_7_7 +// }; +// +// public int[] kaixintushetou_res = new int[]{ +// R.drawable.kaxintushetou_8_1, +// R.drawable.kaxintushetou_8_2, +// R.drawable.kaxintushetou_8_3, +// R.drawable.kaxintushetou_8_4, +// R.drawable.kaxintushetou_8_5, +// R.drawable.kaxintushetou_8_6, +// R.drawable.kaxintushetou_8_7, +// R.drawable.kaxintushetou_8_8 +// }; +// +// public int[] baibai_res = new int[]{ +// R.drawable.baibai_9_1, +// R.drawable.baibai_9_2, +// R.drawable.baibai_9_3, +// R.drawable.baibai_9_4, +// R.drawable.baibai_9_5, +// R.drawable.baibai_9_6 +// }; +// +// public int[] bishi_res = new int[]{ +// R.drawable.bishi_10_1, +// R.drawable.bishi_10_2 +// }; +// +// public int[] emohuaixiao_res = new int[]{ +// R.drawable.emohuaixiao_11_1, +// R.drawable.emohuaixiao_11_2, +// R.drawable.emohuaixiao_11_3, +// R.drawable.emohuaixiao_11_4 +// }; +// +// public int[] tianshiweixiao_res = new int[]{ +// R.drawable.tianshiweixiao_12_1, +// R.drawable.tianshiweixiao_12_2, +// R.drawable.tianshiweixiao_12_3, +// R.drawable.tianshiweixiao_12_4, +// R.drawable.tianshiweixiao_12_5, +// R.drawable.tianshiweixiao_12_6 +// }; +// +// public int[] shengqi_res = new int[]{ +// R.drawable.shengqi_13_1, +// R.drawable.shengqi_13_2, +// R.drawable.shengqi_13_3, +// R.drawable.shengqi_13_4, +// R.drawable.shengqi_13_5, +// R.drawable.shengqi_13_6 +// }; +// +// public int[] baobao_res = new int[]{ +// R.drawable.baobao_14_1, +// R.drawable.baobao_14_2, +// R.drawable.baobao_14_3, +// R.drawable.baobao_14_4, +// R.drawable.baobao_14_5 +// }; +// +// public int[] tingyinyue_res = new int[]{ +// R.drawable.tingyinyue_15_1, +// R.drawable.tingyinyue_15_2, +// R.drawable.tingyinyue_15_3, +// R.drawable.tingyinyue_15_4, +// R.drawable.tingyinyue_15_5, +// R.drawable.tingyinyue_15_6 +// }; +// +// public int[] wabikong_res = new int[]{ +// R.drawable.wabikong_21_1, +// R.drawable.wabikong_21_2, +// R.drawable.wabikong_21_3 +// }; +// +// public int[] shaizi_res = new int[]{ +// R.drawable.shaizi_17_1, +// R.drawable.shaizi_17_2, +// R.drawable.shaizi_17_3, +// R.drawable.shaizi_17_4, +// R.drawable.shaizi_17_5 +// }; +// +// public int[] shaizi_result_res = new int[] { +// R.drawable.shaizi_17_6, +// R.drawable.shaizi_17_7, +// R.drawable.shaizi_17_8, +// R.drawable.shaizi_17_9, +// R.drawable.shaizi_17_10, +// R.drawable.shaizi_17_11 +// }; +// +// public int[] shitoujiandaobu_res = new int[]{ +// R.drawable.shitoujiandaobu_18_1, +// R.drawable.shitoujiandaobu_18_2, +// R.drawable.shitoujiandaobu_18_3 +// }; +// +// public int[] shitoujiandaobu_result_res = new int[]{ +// R.drawable.shitoujiandaobu_18_1, +// R.drawable.shitoujiandaobu_18_2, +// R.drawable.shitoujiandaobu_18_3 +// }; +// +// public int[] chouqian_res = new int[]{ +// R.drawable.chouqian_20_1, +// R.drawable.chouqian_20_2, +// R.drawable.chouqian_20_3, +// R.drawable.chouqian_20_4, +// R.drawable.chouqian_20_5, +// R.drawable.chouqian_20_6 +// }; +// +// public int[] chouqian_result_res = new int[]{ +// R.drawable.chouqian_20_7, +// R.drawable.chouqian_20_8, +// R.drawable.chouqian_20_9, +// R.drawable.chouqian_20_10, +// R.drawable.chouqian_20_11, +// R.drawable.chouqian_20_12, +// R.drawable.chouqian_20_13, +// R.drawable.chouqian_20_14 +// }; +// +// public void createFaceItem(int faceId) { +// FaceItem faceItem = new FaceItem(faceId); +// if (faceId == FACE_ITEM_DAXIAO) { +// faceItem.setFaceName(ResUtil.getString(R.string.widget_dynamicface_dynamicfacebuilder_01)); +// faceItem.setFaceResId(R.drawable.daxiao_1_0); +// } else if (faceId == FACE_ITEM_LIUHAN) { +// faceItem.setFaceName(ResUtil.getString(R.string.widget_dynamicface_dynamicfacebuilder_02)); +// faceItem.setFaceResId(R.drawable.liuhan_2_0); +// } else if (faceId == FACE_ITEM_SEMIMI) { +// faceItem.setFaceName(ResUtil.getString(R.string.widget_dynamicface_dynamicfacebuilder_03)); +// faceItem.setFaceResId(R.drawable.semimi_3_0); +// }else if (faceId == FACE_ITEM_LIULEI) { +// faceItem.setFaceName(ResUtil.getString(R.string.widget_dynamicface_dynamicfacebuilder_04)); +// faceItem.setFaceResId(R.drawable.liulei_4_0); +// }else if (faceId == FACE_ITEM_FEIWEN) { +// faceItem.setFaceName(ResUtil.getString(R.string.widget_dynamicface_dynamicfacebuilder_05)); +// faceItem.setFaceResId(R.drawable.feiwen_5_0); +// }else if (faceId == FACE_ITEM_JUSANG) { +// faceItem.setFaceName(ResUtil.getString(R.string.widget_dynamicface_dynamicfacebuilder_06)); +// faceItem.setFaceResId(R.drawable.jusang_6_0); +// }else if (faceId == FACE_ITEM_WUYAN) { +// faceItem.setFaceName(ResUtil.getString(R.string.widget_dynamicface_dynamicfacebuilder_07)); +// faceItem.setFaceResId(R.drawable.wuyan_7_0); +// }else if (faceId == FACE_ITEM_KAXINTUSHETOU) { +// faceItem.setFaceName(ResUtil.getString(R.string.widget_dynamicface_dynamicfacebuilder_08)); +// faceItem.setFaceResId(R.drawable.kaxintushetou_8_0); +// }else if (faceId == FACE_ITEM_BAIBAI) { +// faceItem.setFaceName(ResUtil.getString(R.string.widget_dynamicface_dynamicfacebuilder_09)); +// faceItem.setFaceResId(R.drawable.baibai_9_0); +// }else if (faceId == FACE_ITEM_BISHI) { +// faceItem.setFaceName(ResUtil.getString(R.string.widget_dynamicface_dynamicfacebuilder_010)); +// faceItem.setFaceResId(R.drawable.bishi_10_0); +// }else if (faceId == FACE_ITEM_EMOHUAIXIAO) { +// faceItem.setFaceName(ResUtil.getString(R.string.widget_dynamicface_dynamicfacebuilder_011)); +// faceItem.setFaceResId(R.drawable.bishi_10_0); +// }else if (faceId == FACE_ITEM_TIANSHIWEIXIAO) { +// }else if (faceId == FACE_ITEM_SHENGQI) { +// }else if (faceId == FACE_ITEM_BAOBAO) { +// }else if (faceId == FACE_ITEM_TINGYINYUE) { +// }else if (faceId == FACE_ITEM_WABIKONG) { +// }else if (faceId == FACE_ITEM_SHAIZI) { +// }else if (faceId == FACE_ITEM_SHITOUJIANDAOBU) { +// }else if (faceId == FACE_ITEM_CHOUQIAN) { +// } +// } +// +// public void createResultItem(int faceId, int resultNumber) { +// FaceResultItem faceResultItem = new FaceResultItem(); +// faceResultItem.setFaceId(faceId); +// faceResultItem.setResultNumber(resultNumber); +// +// if (faceId == FACE_ITEM_DAXIAO) { +// faceResultItem.setResultFace(false); +// faceResultItem.setFaceMoveDuration(3000); +// faceResultItem.setFaceMoveRes(daxiao_res); +// } else if (faceId == FACE_ITEM_LIUHAN) { +// faceResultItem.setResultFace(false); +// faceResultItem.setFaceMoveDuration(3000); +// faceResultItem.setFaceMoveRes(liuhan_res); +// } else if (faceId == FACE_ITEM_SEMIMI) { +// faceResultItem.setResultFace(false); +// faceResultItem.setFaceMoveDuration(3000); +// faceResultItem.setFaceMoveRes(semimi_res); +// }else if (faceId == FACE_ITEM_LIULEI) { +// faceResultItem.setResultFace(false); +// faceResultItem.setFaceMoveDuration(3000); +// faceResultItem.setFaceMoveRes(liulei_res); +// }else if (faceId == FACE_ITEM_FEIWEN) { +// faceResultItem.setResultFace(false); +// faceResultItem.setFaceMoveDuration(3000); +// faceResultItem.setFaceMoveRes(feiwen_res); +// }else if (faceId == FACE_ITEM_JUSANG) { +// faceResultItem.setResultFace(false); +// faceResultItem.setFaceMoveDuration(3000); +// faceResultItem.setFaceMoveRes(jusang_res); +// }else if (faceId == FACE_ITEM_WUYAN) { +// faceResultItem.setResultFace(false); +// faceResultItem.setFaceMoveDuration(3000); +// faceResultItem.setFaceMoveRes(wuyan_res); +// }else if (faceId == FACE_ITEM_KAXINTUSHETOU) { +// faceResultItem.setResultFace(false); +// faceResultItem.setFaceMoveDuration(3000); +// faceResultItem.setFaceMoveRes(kaixintushetou_res); +// }else if (faceId == FACE_ITEM_BAIBAI) { +// faceResultItem.setResultFace(false); +// faceResultItem.setFaceMoveDuration(3000); +// faceResultItem.setFaceMoveRes(baibai_res); +// }else if (faceId == FACE_ITEM_BISHI) { +// faceResultItem.setResultFace(false); +// faceResultItem.setFaceMoveDuration(3000); +// faceResultItem.setFaceMoveRes(bishi_res); +// }else if (faceId == FACE_ITEM_EMOHUAIXIAO) { +// faceResultItem.setResultFace(false); +// faceResultItem.setFaceMoveDuration(3000); +// faceResultItem.setFaceMoveRes(emohuaixiao_res); +// }else if (faceId == FACE_ITEM_TIANSHIWEIXIAO) { +// faceResultItem.setResultFace(false); +// faceResultItem.setFaceMoveDuration(3000); +// faceResultItem.setFaceMoveRes(tianshiweixiao_res); +// }else if (faceId == FACE_ITEM_SHENGQI) { +// faceResultItem.setResultFace(false); +// faceResultItem.setFaceMoveDuration(3000); +// faceResultItem.setFaceMoveRes(shengqi_res); +// }else if (faceId == FACE_ITEM_BAOBAO) { +// faceResultItem.setResultFace(false); +// faceResultItem.setFaceMoveDuration(3000); +// faceResultItem.setFaceMoveRes(baobao_res); +// }else if (faceId == FACE_ITEM_TINGYINYUE) { +// faceResultItem.setResultFace(false); +// faceResultItem.setFaceMoveDuration(3000); +// faceResultItem.setFaceMoveRes(tingyinyue_res); +// }else if (faceId == FACE_ITEM_WABIKONG) { +// faceResultItem.setResultFace(false); +// faceResultItem.setFaceMoveDuration(3000); +// faceResultItem.setFaceMoveRes(wabikong_res); +// }else if (faceId == FACE_ITEM_SHAIZI) { +// faceResultItem.setResultFace(true); +// faceResultItem.setFaceMoveDuration(3000); +// faceResultItem.setFaceMoveRes(shaizi_res); +// faceResultItem.setResultNumber(resultNumber); +// faceResultItem.setFaceResultRes(shaizi_result_res[resultNumber]); +// faceResultItem.setResultDuration(4000); +// }else if (faceId == FACE_ITEM_SHITOUJIANDAOBU) { +// faceResultItem.setResultFace(true); +// faceResultItem.setFaceMoveDuration(3000); +// faceResultItem.setFaceMoveRes(shitoujiandaobu_res); +// faceResultItem.setResultNumber(resultNumber); +// faceResultItem.setFaceResultRes(shaizi_result_res[resultNumber]); +// faceResultItem.setResultDuration(4000); +// }else if (faceId == FACE_ITEM_CHOUQIAN) { +// faceResultItem.setResultFace(true); +// faceResultItem.setFaceMoveDuration(3000); +// faceResultItem.setFaceMoveRes(chouqian_res); +// faceResultItem.setResultNumber(resultNumber); +// faceResultItem.setFaceResultRes(chouqian_result_res[resultNumber]); +// faceResultItem.setResultDuration(4000); +// } +// } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/dynamicface/DynamicFaceDialog.java b/app/src/main/java/com/chwl/app/ui/widget/dynamicface/DynamicFaceDialog.java new file mode 100644 index 0000000..a614eea --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/dynamicface/DynamicFaceDialog.java @@ -0,0 +1,323 @@ +package com.chwl.app.ui.widget.dynamicface; + +import android.util.Log; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.ViewGroup; + +import com.chwl.app.R; +import com.chwl.app.base.BaseDialogFragment; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.app.databinding.DialogBottomFaceBinding; +import com.chwl.app.databinding.TabDynamicFaceBinding; +import com.chwl.app.ui.utils.ImageLoadKt; +import com.chwl.core.bean.response.ServiceResult; +import com.chwl.core.market_verify.MarketVerifyModel; +import com.chwl.core.room.bean.FaceBean; +import com.chwl.core.room.bean.FaceEntity; +import com.chwl.core.room.bean.FaceTabBean; +import com.chwl.core.room.event.FaceIsReadyEvent; +import com.chwl.core.room.face.DynamicFaceModel; +import com.chwl.core.room.face.FaceInfo; +import com.chwl.core.utils.LogUtils; +import com.chwl.core.utils.net.RxHelper; +import com.chwl.core.widget.layoutmanager.pagergridlayoutmanager.PagerGridLayoutManager; +import com.chwl.library.common.util.OtherExtKt; +import com.chwl.library.net.rxnet.RxNet; +import com.chwl.library.utils.ListUtils; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import java.util.ArrayList; +import java.util.List; + +import io.reactivex.Single; +import retrofit2.http.GET; + + +/** + * @author xiaoyu + * @date 2017/12/8 + */ + +public class DynamicFaceDialog extends BaseDialogFragment { + private static final String TAG = "DynamicFaceDialog"; + private static final float IMAGE_COUNT_PER_PAGE = 15f; + private static int USER_SELECTED_POS = -1; + private static int USER_SELECTED_TAB = 0; + private static int TAB_NORMAL_FACE = -1; + private static int TAB_NOBLE_FACE = -2; + private DynamicFaceAdapterNew mAdapter; + private PagerGridLayoutManager mLayoutManger; + private FaceFilter mFaceFilter; + private List mTabBeans; + + + @Override + public int getWidth() { + return ViewGroup.LayoutParams.MATCH_PARENT; + } + + @Override + public int getHeight() { + return ViewGroup.LayoutParams.WRAP_CONTENT; + } + + @Override + public int getGravity() { + return Gravity.BOTTOM; + } + + @Override + public void init() { + EventBus.getDefault().register(this); + initView(); + } + + + + private void initView() { + + + + mAdapter = new DynamicFaceAdapterNew(); + mAdapter.setOnItemClickListener((baseQuickAdapter, view, i) -> { + OtherExtKt.isVerify(mAdapter.getData(), i, faceInfo -> { + if (faceInfo != null && !DynamicFaceModel.get().isShowingFace()) { + boolean canUseNobleFaceOrNot = DynamicFaceModel.get().canUseNobleFaceOrNot(faceInfo); + if (canUseNobleFaceOrNot) { + DynamicFaceModel.get().sendFace(faceInfo); + dismiss(); + } else if (faceInfo.getFaceVipInfo() != null) { + new DialogManager(getContext()).showOkDialog(ResUtil.getString(R.string.widget_dynamicface_dynamicfacedialog_03) + + faceInfo.getCNName() + + ResUtil.getString(R.string.widget_dynamicface_dynamicfacedialog_04) + + faceInfo.getFaceVipInfo().getVipName()); + } + } + return null; + }); + }); + + mLayoutManger = new PagerGridLayoutManager(3, 5, PagerGridLayoutManager.HORIZONTAL, false); + mLayoutManger.setPagerChangedListener(new PagerGridLayoutManager.PagerChangedListener() { + @Override + public void onPagerCountChanged(int pagerCount) { + + } + + @Override + public void onPagerIndexSelected(int prePagerIndex, int currentPagerIndex) { + OtherExtKt.doLog(" 翻页 PagerIndex = " + currentPagerIndex); + getBinding().indicator.setSelectedPage(currentPagerIndex); + } + }); + getBinding().rvList.setAdapter(mAdapter); + getBinding().rvList.setLayoutManager(mLayoutManger); + + getFaceTabNew().compose(bindToLifecycle()).doOnSuccess(this::initTabLayout).doOnError(throwable -> { + initTabLayout(new ArrayList<>());}).subscribe(); + } + + + private void initTabLayout(List faceEntities) { + mTabBeans = new ArrayList<>(); + mTabBeans.add(new FaceTabBean(TAB_NORMAL_FACE,R.drawable.icon_face_ya)); +// mTabBeans.add(new FaceTabBean(TAB_NOBLE_FACE,R.drawable.icon_face_ya)); //贵族注释 + + for (int i = 0; i < faceEntities.size(); i++) { + FaceEntity faceEntity = faceEntities.get(i); + FaceTabBean faceTabBean = new FaceTabBean(faceEntity.tabId,faceEntity.tabUrl,faceEntity); + mTabBeans.add(faceTabBean); + } + + getBinding().tabLayout.setViews(mTabBeans.size(), (container, position, adapter) -> { + TabDynamicFaceBinding tabBinding = TabDynamicFaceBinding.inflate(LayoutInflater.from(container.getContext())); + OtherExtKt.isVerify(mTabBeans, position, faceTabBean -> { + if (OtherExtKt.isVerify(faceTabBean.tabUrl)) { + ImageLoadKt.loadImage(tabBinding.icon,faceTabBean.tabUrl); + } else { + tabBinding.icon.setImageResource(faceTabBean.icon); + } + return null; + }); + return tabBinding.getRoot(); + }); + + getBinding().tabLayout.setOnTabClickListener((position, view) -> { + FaceTabBean faceTabBean = mTabBeans.get(position); + for (int i = 0; i < mTabBeans.size(); i++) { + TabDynamicFaceBinding tabAtView = TabDynamicFaceBinding.bind(getBinding().tabLayout.getTabAt(i)); + tabAtView.icon.setBackgroundResource(R.drawable.transparent_draw); + if (i == position) { + tabAtView.icon.setBackgroundResource(R.drawable.shape_727272_7dp); + } + } + + List faceInfos = null; + if (faceTabBean.id == TAB_NOBLE_FACE) { + faceInfos = getNobleFaceList(); + }else if (faceTabBean.id == TAB_NORMAL_FACE) { + faceInfos = getNormalFaceList(); + }else{ + faceInfos = getFaceInfo(faceTabBean); + } + + if (!OtherExtKt.isVerify(faceInfos)) { + SingleToastUtil.showToastShort(ResUtil.getString(R.string.widget_dynamicface_dynamicfacedialog_02)); + return; + } + + updateFace(faceInfos); + }); + + getBinding().tabLayout.post(() -> { + getBinding().tabLayout.getTabAt(0).performClick(); + }); + } + + private List getFaceInfo(FaceTabBean faceTabBean) { + List infos = new ArrayList<>(); + if (faceTabBean != null && faceTabBean.faceEntity != null && OtherExtKt.isVerify(faceTabBean.faceEntity.faceNewVoList)) { + for (int i = 0; i < faceTabBean.faceEntity.faceNewVoList.size(); i++) { + FaceBean faceBean = faceTabBean.faceEntity.faceNewVoList.get(i); + if (faceBean != null) { + FaceInfo faceInfo = new FaceInfo(); + faceInfo.setFaceType(FaceInfo.TYPE_FACE_NORMAL); + faceInfo.pic = faceBean.faceIndex; + faceInfo.svgaUrl = faceBean.faceUrl; + infos.add(faceInfo); + } + + } + } + return infos; + } + + private void updateFace(List faceInfos) { + if (faceInfos == null) { + LogUtils.d("faceInfos==null"); + } else { + LogUtils.d("faceInfos.size()" + faceInfos.size()); + } + List lists = resolveData(faceInfos); + mAdapter.setNewData(lists); + // 准备indicator + getBinding().indicator.initIndicator((int) Math.ceil((lists.size() / IMAGE_COUNT_PER_PAGE))); + getBinding().indicator.setSelectedPage(0); + } + + private List getNormalFaceList() { + List infos = new ArrayList<>(); + List faceInfos = DynamicFaceModel.get().getFaceInfos(); + + if (ListUtils.isListEmpty(faceInfos)) return infos; + Log.d("getNormalFaceList", faceInfos.size() + "--------"); + for (int i = 0; i < faceInfos.size(); i++) { + if (!faceInfos.get(i).isNobleFace() || faceInfos.get(i).getNobleId() == 0) { + infos.add(faceInfos.get(i)); + } + } + if (mFaceFilter != null) { + return mFaceFilter.onFilter(infos); + } else { + return infos; + } + + } + + private List getNobleFaceList() { + return DynamicFaceModel.get().getVIPFaceInfos(); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onFeceIsReady(FaceIsReadyEvent event) { + initView(); + } + + + @Override + public void onDestroy() { + EventBus.getDefault().unregister(this); + super.onDestroy(); + } + + /** + * 解析数据,决定哪些表情可以出现在表情面板上面 + * + * @param faceInfos 普通表情 / 贵族表情 + * @return 返回格式是 List>, 子元素是一个个的列表,每一个子列表代表的是表情面板上看到的每一页 + */ + private List resolveData(List faceInfos) { + if (ListUtils.isListEmpty(faceInfos)) { + return new ArrayList<>(); + } + List results = new ArrayList<>(); + // 动画完成后直接消失的表情 + List normalFaceList = new ArrayList<>(); + // 动画完成后要停留几秒展示结果的表情 + List luckFaceInfoList = new ArrayList<>(); + boolean marketChecking = MarketVerifyModel.get().isMarketChecking(); + for (FaceInfo faceInfo : faceInfos) { + // 是否需要出现在表情面板上 + if (faceInfo.getFaceType() == FaceInfo.TYPE_FACE_NORMAL) { + // 不需要隐藏的表情直接加入到 list 里 + if (!faceInfo.isLuckFace()) { + // 普通表情还是运气表情 + if (faceInfo.getResultCount() > 0) { + luckFaceInfoList.add(faceInfo); + } else { + normalFaceList.add(faceInfo); + } + } else { + // 如果此时正在审核中,则不将其加入到 list 里 + // 否则就加入到 list 里,出现在表情面板上 + if (!marketChecking) { + // 普通表情还是运气表情 + if (faceInfo.getResultCount() > 0) { + luckFaceInfoList.add(faceInfo); + } else { + normalFaceList.add(faceInfo); + } + } + } + } + } + results.addAll(normalFaceList); + results.addAll(luckFaceInfoList); + return results; + } + + + + public void setmFaceFilter(FaceFilter mFaceFilter) { + this.mFaceFilter = mFaceFilter; + } + + + + public interface FaceFilter { + List onFilter(List faceInfoList); + } + + + + private Single> getFaceTabNew() { + return api.getFaceTabNew() + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()); + } + + Api api = RxNet.create(Api.class); + private interface Api { + @GET("faceTabNew/list") + Single>> getFaceTabNew(); + } + + + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/dynamicface/FaceItem.java b/app/src/main/java/com/chwl/app/ui/widget/dynamicface/FaceItem.java new file mode 100644 index 0000000..aeb7fec --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/dynamicface/FaceItem.java @@ -0,0 +1,39 @@ +package com.chwl.app.ui.widget.dynamicface; + +/** + * Created by chenran on 2017/9/9. + */ + +public class FaceItem { + private int faceId; + private String faceName; + private String faceUrl; + + public String getFaceUrl() { + return faceUrl; + } + + public void setFaceUrl(String faceUrl) { + this.faceUrl = faceUrl; + } + + public FaceItem(int faceId) { + this.faceId = faceId; + } + + public int getFaceId() { + return faceId; + } + + public void setFaceId(int faceId) { + this.faceId = faceId; + } + + public String getFaceName() { + return faceName; + } + + public void setFaceName(String faceName) { + this.faceName = faceName; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/dynamicface/FaceResultItem.java b/app/src/main/java/com/chwl/app/ui/widget/dynamicface/FaceResultItem.java new file mode 100644 index 0000000..b70c85c --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/dynamicface/FaceResultItem.java @@ -0,0 +1,89 @@ +package com.chwl.app.ui.widget.dynamicface; + +/** + * Created by chenran on 2017/9/9. + */ + +public class FaceResultItem { + private int faceId; + private int[] faceMoveRes; + private int faceResultRes; + private boolean isResultFace; + private int resultNumber; + private int faceMoveDuration; + private int resultDuration; + private int faceFrameRate; + private String faceResultName; + + public int getFaceId() { + return faceId; + } + + public void setFaceId(int faceId) { + this.faceId = faceId; + } + + public int[] getFaceMoveRes() { + return faceMoveRes; + } + + public void setFaceMoveRes(int[] faceMoveRes) { + this.faceMoveRes = faceMoveRes; + } + + public int getFaceResultRes() { + return faceResultRes; + } + + public void setFaceResultRes(int faceResultRes) { + this.faceResultRes = faceResultRes; + } + + public boolean isResultFace() { + return isResultFace; + } + + public void setResultFace(boolean resultFace) { + isResultFace = resultFace; + } + + public int getResultNumber() { + return resultNumber; + } + + public void setResultNumber(int resultNumber) { + this.resultNumber = resultNumber; + } + + public int getFaceMoveDuration() { + return faceMoveDuration; + } + + public void setFaceMoveDuration(int faceMoveDuration) { + this.faceMoveDuration = faceMoveDuration; + } + + public int getResultDuration() { + return resultDuration; + } + + public void setResultDuration(int resultDuration) { + this.resultDuration = resultDuration; + } + + public int getFaceFrameRate() { + return faceFrameRate; + } + + public void setFaceFrameRate(int faceFrameRate) { + this.faceFrameRate = faceFrameRate; + } + + public String getFaceResultName() { + return faceResultName; + } + + public void setFaceResultName(String faceResultName) { + this.faceResultName = faceResultName; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/higuide/GuideUtils.java b/app/src/main/java/com/chwl/app/ui/widget/higuide/GuideUtils.java new file mode 100644 index 0000000..c18677b --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/higuide/GuideUtils.java @@ -0,0 +1,93 @@ +package com.chwl.app.ui.widget.higuide; + +import android.content.Context; +import android.graphics.Point; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; + +/** + * Create Zii at 2018/5/4. + */ +public class GuideUtils { + + public static int getScreenWidth(Context context) { + WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + if (wm == null) { + return context.getResources().getDisplayMetrics().widthPixels; + } + Point point = new Point(); + wm.getDefaultDisplay().getRealSize(point); + return point.x; + } + + public static int getScreenHeight(Context context) { + WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + if (wm == null) { + return context.getResources().getDisplayMetrics().heightPixels; + } + Point point = new Point(); + wm.getDefaultDisplay().getRealSize(point); + return point.y; + } + + public static int[] getScreenSize(Context context) { + int[] sizes = new int[2]; + WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + if (wm == null) { + sizes[0] = context.getResources().getDisplayMetrics().widthPixels; + sizes[1] = context.getResources().getDisplayMetrics().heightPixels; + return sizes; + } + Point point = new Point(); + wm.getDefaultDisplay().getRealSize(point); + sizes[0] = point.x; + sizes[1] = point.y; + return sizes; + } + + public static float dp2px(Context context, final float dpValue) { + final float scale = context.getResources().getDisplayMetrics().density; + return dpValue * scale + 0.5f; + } + + public static int getMeasuredWidth(final View view) { + return measureView(view)[0]; + } + + public static int getMeasuredHeight(final View view) { + return measureView(view)[1]; + } + + public static int[] measureView(final View view) { + ViewGroup.LayoutParams lp = view.getLayoutParams(); + if (lp == null) { + lp = new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT + ); + } + int widthSpec = ViewGroup.getChildMeasureSpec(0, 0, lp.width); + int lpHeight = lp.height; + int heightSpec; + if (lpHeight > 0) { + heightSpec = View.MeasureSpec.makeMeasureSpec(lpHeight, View.MeasureSpec.EXACTLY); + } else { + heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); + } + view.measure(widthSpec, heightSpec); + return new int[]{view.getMeasuredWidth(), view.getMeasuredHeight()}; + } + + + public static boolean isSameLocation(int[] last, int[] now) { + try { + return last[0] == now[0] && last[1] == now[1]; + } catch (Exception ex) { + ex.printStackTrace(); + } + return false; + } + + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/higuide/GuideView.java b/app/src/main/java/com/chwl/app/ui/widget/higuide/GuideView.java new file mode 100644 index 0000000..6bc10d6 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/higuide/GuideView.java @@ -0,0 +1,201 @@ +package com.chwl.app.ui.widget.higuide; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.RectF; +import android.os.Build; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.RelativeLayout; + +import com.chwl.app.ui.widget.higuide.Overlay.HightLight; +import com.chwl.app.ui.widget.higuide.Overlay.Tips; +import com.chwl.app.ui.widget.higuide.Overlay.Tips.Margin; + +/** + * Create By Zii at 2018/5/3. + */ +class GuideView extends FrameLayout { + + private Overlay mOverlay; + private Paint mPaint; + private Path mBgPath; + private Path mShapePath; + private RemoveCallback mRemoveCallback; + + public GuideView(Context context, Overlay overlay) { + super(context); + mOverlay = overlay; + init(); + } + + private void init() { + final int bgColor = mOverlay.getColorBg(); + + mBgPath = new Path(); + mShapePath = new Path(); + + mPaint = new Paint(); + mPaint.setColor(bgColor); + mPaint.setDither(true); + mPaint.setAntiAlias(true); + + setWillNotDraw(false); + } + + @Override + protected void onDraw(Canvas canvas) { + mBgPath.reset(); + mShapePath.reset(); + + mBgPath.addRect(0, 0, getWidth(), getHeight(), Path.Direction.CW); + + for (HightLight hightLight : mOverlay.getHightLightList()) { + Path shapePath = calcHightLightShapePath(hightLight, mShapePath); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + mBgPath.op(shapePath, Path.Op.XOR); + } + } + + canvas.drawPath(mBgPath, mPaint); + } + + private Path calcHightLightShapePath(HightLight hightLight, Path shapePath) { + shapePath.reset(); + switch (hightLight.getShape()) { + case HiGuide.SHAPE_CIRCLE: + shapePath.addCircle(hightLight.getRectF().centerX(), + hightLight.getRectF().centerY(), + hightLight.getRadius(), Path.Direction.CW); + break; + case HiGuide.SHAPE_OVAL: + shapePath.addOval(hightLight.getRectF(), Path.Direction.CW); + break; + case HiGuide.SHAPE_RECT: + shapePath.addRect(hightLight.getRectF(), Path.Direction.CW); + break; + default: + break; + } + return shapePath; + } + + public void addTipsViews() { + for (HightLight hightLight : mOverlay.getHightLightList()) { + + if (hightLight != null + && hightLight.getTips() != null + && hightLight.getTips().layoutRes != -1) { + + addTipsView(hightLight.getTips(), hightLight.getRectF()); + } + } + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_UP) { + //点击高亮 + if (mOverlay.getOnClickHightLightListener() != null) { + float x = event.getX(); + float y = event.getY(); + for (RectF rectF : mOverlay.getHightLightAreas()) { + if (rectF.contains(x, y)) { + mOverlay.getOnClickHightLightListener().onClick(this); + remove(); + return super.onTouchEvent(event); //点击高亮后不做其他的处理了,直接返回 + } + } + } + //全局点击 + if (mOverlay.getOnClickGuideViewListener() != null) { + mOverlay.getOnClickGuideViewListener().onClick(this); + } + if (mOverlay.isTouchDismiss()) { + remove(); + } + } + + return true; + } + + private void remove() { + ViewGroup parent = (ViewGroup) getParent(); + if (parent instanceof RelativeLayout || parent instanceof FrameLayout) { + parent.removeView(this); + } else { + parent.removeView(this); + View origin = parent.getChildAt(0); + ViewGroup graParent = (ViewGroup) parent.getParent(); + graParent.removeView(parent); + graParent.addView(origin, parent.getLayoutParams()); + } + + if (mRemoveCallback != null) { + mRemoveCallback.callback(); + } + } + + public void addTipsView(Tips tips, RectF hlRectF) { + View tipsView = LayoutInflater.from(getContext()).inflate(tips.layoutRes, this, false); + int tipsWidth = GuideUtils.getMeasuredWidth(tipsView); + Margin margin = tips.margin == null ? new Margin(0, 0, 0, 0) : tips.margin; + + LayoutParams lp = (LayoutParams) tipsView.getLayoutParams(); + + switch (tips.to) { + case Tips.TO_LEFT_OF: + lp.leftMargin = (int) (hlRectF.left - tipsWidth - margin.right); + switch (tips.align) { + case Tips.ALIGN_BOTTOM: + lp.topMargin = (int) (hlRectF.bottom + margin.top); + break; + case Tips.ALIGN_TOP: + lp.topMargin = (int) (hlRectF.top + margin.top); + break; + default: + lp.topMargin = margin.top; + break; + } + break; + case Tips.TO_RIGHT_OF: + lp.leftMargin = (int) (hlRectF.right + margin.left); + switch (tips.align) { + case Tips.ALIGN_BOTTOM: + lp.topMargin = (int) (hlRectF.bottom + margin.top); + break; + case Tips.ALIGN_TOP: + lp.topMargin = (int) (hlRectF.top + margin.top); + break; + default: + lp.topMargin = margin.top; + break; + } + break; + default: + lp.leftMargin = margin.left; + lp.topMargin = margin.top; + lp.rightMargin = margin.right; + lp.bottomMargin = margin.bottom; + break; + } + + tipsView.setLayoutParams(lp); + + addView(tipsView, lp); + } + + public void setRemoveCallback(RemoveCallback removeCallback) { + mRemoveCallback = removeCallback; + } + + public interface RemoveCallback { + + void callback(); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/higuide/HiGuide.java b/app/src/main/java/com/chwl/app/ui/widget/higuide/HiGuide.java new file mode 100644 index 0000000..c031f55 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/higuide/HiGuide.java @@ -0,0 +1,126 @@ +package com.chwl.app.ui.widget.higuide; + +import android.app.Activity; +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import androidx.annotation.IntDef; + +import com.chwl.app.R; +import com.chwl.app.ui.widget.higuide.GuideView.RemoveCallback; +import com.chwl.app.ui.widget.higuide.Overlay.Tips; + +import java.util.ArrayList; +import java.util.List; + +/** + * Create Zii at 2018/5/3. + */ +public class HiGuide { + + private Context mContext; + private ViewGroup mRootView; + private GuideView mGuideView; + private List mOverlays; + private Overlay mDefaultOverlay; + private boolean mIsOpenNext; + + public HiGuide(Context context) { + mContext = context; + + init(); + } + + private void init() { + mRootView = (ViewGroup) ((Activity) mContext).getWindow().getDecorView(); + mOverlays = new ArrayList<>(); + mDefaultOverlay = new Overlay(); + mOverlays.add(mDefaultOverlay); + } + + public HiGuide touchDismiss(boolean isDismiss) { + mDefaultOverlay.touchDismiss(isDismiss); + return this; + } + + public HiGuide bgColor(int color) { + mDefaultOverlay.bgColor(color); + return this; + } + + public HiGuide addHightLightClickListener(View.OnClickListener listener) { + mDefaultOverlay.addHightLightClickListener(listener); + return this; + } + + public HiGuide addGuideViewClickListener(View.OnClickListener listener) { + mDefaultOverlay.addGuideViewClickListener(listener); + return this; + } + + public HiGuide addHightLight(View view, int[] expand, @Shape int shape, Tips tips) { + mDefaultOverlay.addHightLight(view, expand, shape, tips); + return this; + } + + public HiGuide nextOverLay(Overlay overlay) { + mOverlays.add(overlay); + return this; + } + + public void show() { + mIsOpenNext = mOverlays.size() > 1; + + final Overlay overlay = mOverlays.get(0); + mGuideView = new GuideView(mContext, overlay); + mGuideView.setId(R.id.guide_view); + if (mRootView instanceof FrameLayout) { + ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT); + mRootView.addView(mGuideView, mRootView.getChildCount(), lp); + } else { + FrameLayout frameLayout = new FrameLayout(mContext); + ViewGroup parent = (ViewGroup) mRootView.getParent(); + parent.removeView(mRootView); + parent.addView(frameLayout, mRootView.getLayoutParams()); + ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + frameLayout.addView(mRootView, lp); + } + mGuideView.addTipsViews(); + mGuideView.setRemoveCallback(new RemoveCallback() { + @Override + public void callback() { + mGuideView = null; + if (mIsOpenNext) { + mOverlays.remove(0); + show(); + } + } + }); + } + + public void dismiss() { + if (mGuideView != null && mGuideView.getParent() instanceof ViewGroup && mGuideView.getParent() == mRootView) { + mRootView.removeView(mGuideView); + } + } + + public GuideView getGuideView() { + if (mGuideView != null) { + return mGuideView; + } + return ((Activity) mContext).findViewById(R.id.guide_view); + } + + public static final int SHAPE_CIRCLE = 0x21; + public static final int SHAPE_OVAL = 0x22; + public static final int SHAPE_RECT = 0x23; + + @IntDef({SHAPE_CIRCLE, SHAPE_OVAL, SHAPE_RECT}) + @interface Shape { + + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/higuide/HiLightInfo.java b/app/src/main/java/com/chwl/app/ui/widget/higuide/HiLightInfo.java new file mode 100644 index 0000000..c1d8f36 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/higuide/HiLightInfo.java @@ -0,0 +1,45 @@ +package com.chwl.app.ui.widget.higuide; + +import android.graphics.RectF; + +import lombok.Data; + +/** + * create by lvzebiao @2019/5/21 + */ +@Data +public class HiLightInfo { + + public final static int ROUND_RECT = 1; + + public final static int NORMAL_RECT = 2; + + private int centerX; + + private int centerY; + + private RectF rectF; + + /** + * 如{x1,y1,x2,y2,x3,y3,x4,y4} + * 左上,右上,右下,左下 + */ + private float[] radis; + + private int ShapeType; + + public float[] getRadis() { + if (radis == null) { + radis = new float[]{}; + } + return radis; + } + + public RectF getRectF() { + if (rectF == null) { + rectF = new RectF(0, 0, 0, 0); + } + return rectF; + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/higuide/LightConfig.java b/app/src/main/java/com/chwl/app/ui/widget/higuide/LightConfig.java new file mode 100644 index 0000000..d5cf3b5 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/higuide/LightConfig.java @@ -0,0 +1,49 @@ +package com.chwl.app.ui.widget.higuide; + +import android.view.View; + +import lombok.Data; + +/** + * 这个类用于保存高亮的信息配置, + * 比如padding扩充多少,圆角信息等 + * create by lvzebiao @2019/5/21 + */ +@Data +public class LightConfig { + //高亮的view 需要等view位置确定后,再传入, + //如果=null则表示不需要高亮 + private View view; + + public LightConfig(View view) { + this.view = view; + } + + //水平padding + private int hPadding; + //垂直padding + private int vPadding; + + private float[] radius; + + private int leftPadding; + + private int rightPadding; + + private int topPadding; + + private int bottomPadding; + + public void setHPadding(int hPadding) { + this.hPadding = hPadding; + this.leftPadding = hPadding; + this.rightPadding = hPadding; + } + + public void setVPadding(int vPadding) { + this.vPadding = vPadding; + this.topPadding = vPadding; + this.bottomPadding = vPadding; + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/higuide/OverLayer.java b/app/src/main/java/com/chwl/app/ui/widget/higuide/OverLayer.java new file mode 100644 index 0000000..9f4d489 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/higuide/OverLayer.java @@ -0,0 +1,54 @@ +package com.chwl.app.ui.widget.higuide; + +import android.view.View; +import android.view.ViewGroup; + +import java.util.ArrayList; +import java.util.List; + +/** + * create by lvzebiao @2019/5/21 + */ +public class OverLayer { + + public List tipsViewList; + + public boolean needSkip; + + public ViewGroup.LayoutParams knowedParams; + + public ViewGroup.LayoutParams nextParams; + + public List hiLightInfoList; + + public OverLayer() { + tipsViewList = new ArrayList<>(); + hiLightInfoList = new ArrayList<>(); + } + + public OverLayer setNeedSkip(boolean needSkip) { + this.needSkip = needSkip; + return this; + } + + public OverLayer setNextParams(ViewGroup.LayoutParams nextParams) { + this.nextParams = nextParams; + return this; + } + + public OverLayer setKnowedParams(ViewGroup.LayoutParams knowedParams) { + this.knowedParams = knowedParams; + return this; + } + + public OverLayer addTipsView(View tipsView) { + tipsViewList.add(tipsView); + return this; + } + + public OverLayer addHiLightInfo(List hiLightInfoList) { + this.hiLightInfoList = hiLightInfoList; + return this; + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/higuide/Overlay.java b/app/src/main/java/com/chwl/app/ui/widget/higuide/Overlay.java new file mode 100644 index 0000000..a8b988a --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/higuide/Overlay.java @@ -0,0 +1,211 @@ +package com.chwl.app.ui.widget.higuide; + +import android.graphics.Color; +import android.graphics.RectF; +import android.view.View; + +import androidx.annotation.IntDef; +import androidx.annotation.LayoutRes; +import androidx.annotation.Nullable; + +import java.util.ArrayList; +import java.util.List; + +/** + * Create by Zii at 2018/5/4. + */ +public class Overlay { + + private List mHightLightList; + private int mColorBg; + private boolean mIsTouchDismiss; + private View.OnClickListener mOnClickGuideViewListener; + private View.OnClickListener mOnClickHightLightListener; + private List mHightLightAreas; + + public Overlay() { + mHightLightList = new ArrayList<>(); + mColorBg = Color.parseColor("#80000000"); + mIsTouchDismiss = true; + mHightLightAreas = new ArrayList<>(); + } + + public Overlay touchDismiss(boolean isDismiss) { + mIsTouchDismiss = isDismiss; + return this; + } + + public Overlay bgColor(int color) { + mColorBg = color; + return this; + } + + public Overlay addHightLight(View view, int[] expand, @HiGuide.Shape int shape, Tips tips) { + HightLight hightLight = new HightLight(view, expand, shape, tips); + mHightLightList.add(hightLight); + addHightLightArea(hightLight); + return this; + } + + private void addHightLightArea(HightLight info) { + RectF rectF = info.getRectF(); + if (info.getShape() != HiGuide.SHAPE_CIRCLE) { + mHightLightAreas.add(rectF); + } else { + mHightLightAreas.add(new RectF(rectF.left, rectF.centerY() - info.getRadius(), + rectF.right, rectF.centerY() + info.getRadius())); + } + } + + public Overlay addHightLightClickListener(View.OnClickListener listener) { + mOnClickHightLightListener = listener; + return this; + } + + public boolean isTouchDismiss() { + return mIsTouchDismiss; + } + + public Overlay addGuideViewClickListener(View.OnClickListener listener) { + mOnClickGuideViewListener = listener; + return this; + } + + public List getHightLightAreas() { + return mHightLightAreas; + } + + public List getHightLightList() { + return mHightLightList; + } + + public int getColorBg() { + return mColorBg; + } + + public View.OnClickListener getOnClickGuideViewListener() { + return mOnClickGuideViewListener; + } + + public View.OnClickListener getOnClickHightLightListener() { + return mOnClickHightLightListener; + } + + public static class HightLight { + + private View mView; + private RectF mRectF; + @HiGuide.Shape + private int mShape; + private float mRadius; + private Tips mTips; + + HightLight(View view, int[] expand, @HiGuide.Shape int shape, Tips tips) { + mView = view; + mShape = shape; + + mRectF = new RectF(); + int[] location = new int[2]; + final int[] size = GuideUtils.measureView(mView); + view.getLocationOnScreen(location); + if (expand == null) { + expand = new int[2]; + } + mRectF.left = location[0] - expand[0]; + mRectF.top = location[1] - expand[1]; + mRectF.right = location[0] + size[0] + expand[0]; + mRectF.bottom = location[1] + size[1] + expand[1]; + + mRadius = Math.max((mRectF.right - mRectF.left) / 2, (mRectF.bottom - mRectF.top) / 2); + + mTips = tips; + } + + public Tips getTips() { + return mTips; + } + + public float getRadius() { + return mRadius; + } + + public View getView() { + return mView; + } + + public RectF getRectF() { + return mRectF; + } + + @HiGuide.Shape + public int getShape() { + return mShape; + } + + } + + public static class Tips { + + public static final int TO_RIGHT_OF = 1; + public static final int TO_LEFT_OF = 2; + public static final int ALIGN_TOP = 3; + public static final int ALIGN_BOTTOM = 4; + + @IntDef({TO_RIGHT_OF, TO_LEFT_OF}) + @interface To { + + } + + @IntDef({ALIGN_TOP, ALIGN_BOTTOM}) + @interface Align { + + } + + public static class Margin { + + public int left; + public int top; + public int bottom; + public int right; + + public Margin(int left, int top, int bottom, int right) { + this.left = left; + this.top = top; + this.bottom = bottom; + this.right = right; + } + } + + @LayoutRes + public int layoutRes = -1; + @To + public int to; + @Align + public int align; + public Margin margin; + + public Tips(int layoutRes) { + this.layoutRes = layoutRes; + } + + public Tips(@LayoutRes int layoutRes, @Nullable Margin margin) { + this.layoutRes = layoutRes; + this.margin = margin; + } + + public Tips(@LayoutRes int layoutRes, @To int to, @Align int align) { + this.layoutRes = layoutRes; + this.to = to; + this.align = align; + } + + public Tips(@LayoutRes int layoutRes, @To int to, @Align int align, @Nullable Margin margin) { + this.layoutRes = layoutRes; + this.to = to; + this.align = align; + this.margin = margin; + } + + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/higuide/TuTuGuideHelper.java b/app/src/main/java/com/chwl/app/ui/widget/higuide/TuTuGuideHelper.java new file mode 100644 index 0000000..7485958 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/higuide/TuTuGuideHelper.java @@ -0,0 +1,768 @@ +package com.chwl.app.ui.widget.higuide; + +import android.app.Activity; +import android.app.Dialog; +import android.content.Context; +import android.graphics.RectF; +import android.text.TextUtils; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import com.chwl.app.R; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.core.utils.ActivityUtil; +import com.chwl.core.utils.SharedPreferenceUtils; +import com.chwl.library.utils.ListUtils; + +import java.util.ArrayList; +import java.util.List; + + +/** + * create by lvzebiao @2019/5/21 + */ +public class TuTuGuideHelper { + + /** + * 是否需要显示礼物面板的引导 + */ + public final static String KEY_GUIDE_GIFT_DIALOG = "key_guide_gift_dialog"; + + /** + * 是否需要显示房间的引导 + */ + public final static String KEY_GUIDE_FIRST_ROOM = "key_guide_first_room"; + + /** + * 房间首页tab引导 + */ + public final static String KEY_GUIDE_MAIN_TAB = "key_guide_main_tab"; + + /** + * 消息tab引导 + */ + public final static String KEY_GUIDE_MSG_TAB = "key_guide_msg_tab"; + + /** + * 我的tab引导 + */ + public final static String KEY_GUIDE_ME_TAB = "key_guide_me_tab"; + public final static String KEY_GUIDE_CHATTER_BOX = "key_guide_chatter_box"; + + /** + * 是否需要显示声音匹配的引导 + */ + public final static String KEY_GUIDE_VOICE_MATCH = "key_guide_voice_match"; + + /** + * 是否需要显示声音匹配私聊页面的打招呼指引 + */ + public final static String KEY_GUIDE_VOICE_MATCH_SAY_HI = "key_guide_voice_match_say_hi"; + /** + * 首页女神页面的引导 + */ + public final static String KEY_GUIDE_MAIN_HOME = "key_guide_me_tab"; + /** + * 话题首页引导 + */ + public final static String KEY_GUIDE_MINI_WORLD_MAIN = "key_guide_mini_world_main"; + /** + * 话题客态页引导-未加入世界 + */ + public final static String KEY_GUIDE_MINI_WORLD_DETAIL_GUEST = "key_guide_mini_world_detail_guest"; + /** + * 话题客态页引导-已加入世界 + */ + public final static String KEY_GUIDE_MINI_WORLD_DETAIL_MEMBER = "key_guide_mini_world_detail_member"; + + private ViewGroup mRootView; + + private TuTuGuideView guideParent; + + private Context context; + + public TuTuGuideHelper(Context context) { + this.context = context; + if (!ActivityUtil.isValidContext(context)) { + return; + } + View contentView = ((Activity) context).findViewById(android.R.id.content); + if (contentView instanceof ViewGroup) { + mRootView = (ViewGroup) contentView; + } + } + + public TuTuGuideHelper(Context context, Dialog dialog) { + this.context = context; + if (!ActivityUtil.isValidContext(context)) { + return; + } + if (dialog == null || dialog.getWindow() == null) { + return; + } + View contentView = dialog.getWindow().getDecorView(); + if (contentView instanceof ViewGroup) { + mRootView = (ViewGroup) contentView; + } + } + + /** + * 创建高亮引导的通用入口 + */ + public void createHiGuide(IGuideLayoutListener listener) { + createHiGuide(listener, null); + } + + public void createHiGuide(IGuideLayoutListener listener, TuTuGuideView.IGuideShowFinishListener showFinishListener) { + try { + if (mRootView == null) { + return; + } + guideParent = new TuTuGuideView(context); + mRootView.addView(guideParent, createLayoutParams()); + mRootView.post(() -> { + try { + if (listener == null) { + return; + } + List list = listener.onCreateList(); + if (ListUtils.isListEmpty(list)) { + return; + } + for (OverLayer overLayer : list) { + guideParent.addOverLayer(overLayer); + } + start(); + } catch (Exception ex) { + ex.printStackTrace(); + } + }); + if (showFinishListener != null) { + guideParent.setShowFinishListener(showFinishListener); + } + } catch (Exception ex) { + ex.printStackTrace(); + } + + } + + public interface IGuideLayoutListener { + List onCreateList(); + } + + public List createMainTabOverLayer(View top) { + List list = new ArrayList<>(); + if (top == null) { + return list; + } + OverLayer overLayer = new OverLayer(); + list.add(overLayer); + + LightConfig lightConfig = new LightConfig(top); + int dp_24 = UIUtil.dip2px(context, 24); + lightConfig.setRadius(new float[]{0, 0, dp_24, dp_24, dp_24, dp_24, 0, 0}); + lightConfig.setHPadding(UIUtil.dip2px(context, 5)); + HiLightInfo info = calcHiLightInfo(lightConfig); + if (info == null) { + return list; + } + List hiLightInfoList = new ArrayList<>(); + hiLightInfoList.add(info); + overLayer.addHiLightInfo(hiLightInfoList); + + ImageView imageView = new ImageView(context); + imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); + imageView.setImageResource(R.drawable.icon_guide_main_top_tips); + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( + UIUtil.dip2px(context, 278.6f), UIUtil.dip2px(context, 92.6f) + ); + params.leftMargin = UIUtil.dip2px(context, 30.6f); + params.topMargin = UIUtil.dip2px(context, 20) + (int) info.getRectF().bottom; + imageView.setLayoutParams(params); + overLayer.addTipsView(imageView); + + params = createKnowedParams(context); + params.leftMargin = UIUtil.dip2px(context, 252); + params.topMargin = UIUtil.dip2px(context, 139) + (int) info.getRectF().bottom; + overLayer.setKnowedParams(params); + + return list; + } + + public List createMeTabOverLayer(View radishItem) { + List list = new ArrayList<>(); + if (radishItem == null) { + return list; + } + OverLayer overLayer = new OverLayer(); + list.add(overLayer); + + LightConfig lightConfig = new LightConfig(radishItem); + int dp_9 = UIUtil.dip2px(context, 9); + lightConfig.setRadius(new float[]{dp_9, dp_9, dp_9, dp_9, dp_9, dp_9, dp_9, dp_9}); + lightConfig.setHPadding(-UIUtil.dip2px(context, 12)); + HiLightInfo info = calcHiLightInfo(lightConfig); + if (info == null) { + return list; + } + List hiLightInfoList = new ArrayList<>(); + hiLightInfoList.add(info); + overLayer.addHiLightInfo(hiLightInfoList); + + ImageView imageView = new ImageView(context); + imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); + imageView.setImageResource(R.drawable.icon_guide_me_enter_tips); + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( + UIUtil.dip2px(context, 295.3f), UIUtil.dip2px(context, 92) + ); + params.leftMargin = UIUtil.dip2px(context, 30.3f); + params.topMargin = (int) info.getRectF().top - UIUtil.dip2px(context, 92) - UIUtil.dip2px(context, 20); + imageView.setLayoutParams(params); + overLayer.addTipsView(imageView); + + params = createKnowedParams(context); + params.leftMargin = UIUtil.dip2px(context, 259); + params.topMargin = (int) info.getRectF().top - UIUtil.dip2px(context, 140) - UIUtil.dip2px(context, 34); + overLayer.setKnowedParams(params); + + return list; + } + + + public List createMsgTabOverLayer() { + List list = new ArrayList<>(); + //第一层 + OverLayer overLayer = new OverLayer(); + View view = View.inflate(context, R.layout.home_guide_for_enter, null); + view.setLayoutParams(createLayoutParams()); + ImageView iv_enter_text = view.findViewById(R.id.iv_enter_text); + if (iv_enter_text != null) { + iv_enter_text.setImageResource(R.drawable.icon_guide_msg_enter_tips); + } + overLayer.addTipsView(view); + + FrameLayout.LayoutParams params = createKnowedParams(context); + params.gravity = Gravity.BOTTOM | Gravity.END; + params.rightMargin = UIUtil.dip2px(context, 52f); + params.bottomMargin = UIUtil.dip2px(context, 99); + overLayer.setKnowedParams(params); + list.add(overLayer); + + return list; + } + + + public List createRoomGuide(View micView, View sendGift) { + List list = new ArrayList<>(); + if (micView == null) { + return list; + } + //8号麦位高亮 + OverLayer overLayer = new OverLayer(); + list.add(overLayer); + + LightConfig lightConfig; + lightConfig = new LightConfig(micView); + int radiu = UIUtil.dip2px(context, 1) + micView.getWidth() / 2; + lightConfig.setRadius(new float[]{radiu, radiu, radiu, radiu, radiu, radiu, radiu, radiu}); + lightConfig.setHPadding(UIUtil.dip2px(context, 1)); + lightConfig.setVPadding(UIUtil.dip2px(context, 1)); + HiLightInfo info; + info = calcHiLightInfo(lightConfig); + if (info == null) { + return list; + } + List hiLightInfoList; + hiLightInfoList = new ArrayList<>(); + hiLightInfoList.add(info); + overLayer.addHiLightInfo(hiLightInfoList); + + ImageView imageView; + imageView = new ImageView(context); + imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); + imageView.setImageResource(R.drawable.icon_guide_to_up_mic_tips); + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( + UIUtil.dip2px(context, 209), UIUtil.dip2px(context, 66) + ); + params.gravity = Gravity.END; + params.rightMargin = UIUtil.dip2px(context, 51); + params.topMargin = (int) info.getRectF().bottom + UIUtil.dip2px(context, 14); + imageView.setLayoutParams(params); + overLayer.addTipsView(imageView); + + params = createNextParams(context); + params.gravity = Gravity.END; + params.rightMargin = UIUtil.dip2px(context, 51); + params.topMargin = (int) info.getRectF().bottom + UIUtil.dip2px(context, 101); + overLayer.setNextParams(params); + + overLayer.setNeedSkip(true); + //送礼按钮高亮 + if (sendGift == null) { + return list; + } + overLayer = new OverLayer(); + list.add(overLayer); + + lightConfig = new LightConfig(sendGift); + radiu = UIUtil.dip2px(context, 24); + lightConfig.setRadius(new float[]{radiu, radiu, 0, 0, 0, 0, radiu, radiu}); + lightConfig.setRightPadding(UIUtil.dip2px(context, 15)); + lightConfig.setLeftPadding(UIUtil.dip2px(context, 6.5f)); + lightConfig.setVPadding(UIUtil.dip2px(context, 6.5f)); + info = calcHiLightInfo(lightConfig); + if (info == null) { + return list; + } + hiLightInfoList = new ArrayList<>(); + hiLightInfoList.add(info); + overLayer.addHiLightInfo(hiLightInfoList); + + imageView = new ImageView(context); + imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); + imageView.setImageResource(R.drawable.icon_guide_room_send_gift_tips); + params = new FrameLayout.LayoutParams( + UIUtil.dip2px(context, 156), UIUtil.dip2px(context, 66) + ); + params.gravity = Gravity.END; + params.rightMargin = UIUtil.dip2px(context, 36); + params.topMargin = (int) info.getRectF().top - UIUtil.dip2px(context, 66) - UIUtil.dip2px(context, 21); + imageView.setLayoutParams(params); + overLayer.addTipsView(imageView); + + params = createKnowedParams(context); + params.gravity = Gravity.END; + params.rightMargin = UIUtil.dip2px(context, 36); + params.topMargin = (int) info.getRectF().top - UIUtil.dip2px(context, 107) - UIUtil.dip2px(context, 34); + overLayer.setKnowedParams(params); + + return list; + } + + public List createVoiceMatchGuide(View likeButtonView, View myVoiceView) { + List list = new ArrayList<>(); + if (likeButtonView == null) { + return list; + } + // 喜欢按钮 高亮 + OverLayer overLayer = new OverLayer(); + list.add(overLayer); + + LightConfig lightConfig; + lightConfig = new LightConfig(likeButtonView); + int radius = UIUtil.dip2px(context, 1) + likeButtonView.getWidth() / 2; + lightConfig.setRadius(new float[]{radius, radius, radius, radius, radius, radius, radius, radius}); + lightConfig.setHPadding(UIUtil.dip2px(context, 1)); + lightConfig.setVPadding(UIUtil.dip2px(context, 1)); + HiLightInfo info; + info = calcHiLightInfo(lightConfig); + if (info == null) { + return list; + } + List hiLightInfoList; + hiLightInfoList = new ArrayList<>(); + hiLightInfoList.add(info); + overLayer.addHiLightInfo(hiLightInfoList); + + ImageView imageView; + imageView = new ImageView(context); + imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); + imageView.setImageResource(R.drawable.icon_guide_to_like_voice_tips); + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( + UIUtil.dip2px(context, 216), UIUtil.dip2px(context, 96) + ); + params.gravity = Gravity.END; + params.rightMargin = UIUtil.dip2px(context, 60); + params.topMargin = (int) info.getRectF().top - UIUtil.dip2px(context, 21) - UIUtil.dip2px(context, 96); + imageView.setLayoutParams(params); + overLayer.addTipsView(imageView); + + params = createNextParams(context); + params.gravity = Gravity.END; + params.rightMargin = UIUtil.dip2px(context, 60); + params.topMargin = (int) info.getRectF().top - UIUtil.dip2px(context, 138) - UIUtil.dip2px(context, 34); + overLayer.setNextParams(params); + + overLayer.setNeedSkip(true); + // 我的声音入口 高亮 + if (myVoiceView == null) { + return list; + } + overLayer = new OverLayer(); + list.add(overLayer); + + lightConfig = new LightConfig(myVoiceView); + radius = UIUtil.dip2px(context, 25); + lightConfig.setRadius(new float[]{radius, radius, 0, 0, 0, 0, radius, radius}); + float leftPadding = myVoiceView.getWidth() / 3 * 1.8f; + lightConfig.setLeftPadding((int) -leftPadding); + info = calcHiLightInfo(lightConfig); + if (info == null) { + return list; + } + hiLightInfoList = new ArrayList<>(); + hiLightInfoList.add(info); + overLayer.addHiLightInfo(hiLightInfoList); + + imageView = new ImageView(context); + imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); + imageView.setImageResource(R.drawable.icon_guide_to_record_voice_tips); + params = new FrameLayout.LayoutParams( + UIUtil.dip2px(context, 190), UIUtil.dip2px(context, 97) + ); + params.gravity = Gravity.END; + params.rightMargin = UIUtil.dip2px(context, 36); + params.topMargin = (int) info.getRectF().bottom + UIUtil.dip2px(context, 21); + imageView.setLayoutParams(params); + overLayer.addTipsView(imageView); + + params = createKnowedParams(context); + params.gravity = Gravity.END; + params.rightMargin = UIUtil.dip2px(context, 36); + params.topMargin = (int) info.getRectF().bottom + UIUtil.dip2px(context, 139); + overLayer.setKnowedParams(params); + + return list; + } + + public List createMiniWorldGuestPageGuestGuide(View addWorldLayout) { + List list = new ArrayList<>(); + if (addWorldLayout == null) { + return list; + } + // 底部布局 高亮 + OverLayer overLayer = new OverLayer(); + list.add(overLayer); + + LightConfig lightConfig; + lightConfig = new LightConfig(addWorldLayout); + int radius = UIUtil.dip2px(context, 5) + addWorldLayout.getWidth() / 2; + lightConfig.setRadius(new float[]{radius, radius, radius, radius, radius, radius, radius, radius}); + lightConfig.setHPadding(UIUtil.dip2px(context, 5)); + lightConfig.setVPadding(UIUtil.dip2px(context, 5)); + HiLightInfo info = calcHiLightInfo(lightConfig); + if (info == null) { + return list; + } + List hiLightInfoList = new ArrayList<>(); + hiLightInfoList.add(info); + overLayer.addHiLightInfo(hiLightInfoList); + + ImageView imageView; + imageView = new ImageView(context); + imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); +// imageView.setImageResource(R.drawable.icon_guide_to_add_world_tips); + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( + UIUtil.dip2px(context, 277), UIUtil.dip2px(context, 115) + ); + params.gravity = Gravity.END; + params.rightMargin = UIUtil.dip2px(context, 60); + params.topMargin = (int) info.getRectF().top - UIUtil.dip2px(context, 25) - UIUtil.dip2px(context, 115); + imageView.setLayoutParams(params); + overLayer.addTipsView(imageView); + + params = createKnowedParams(context); + params.gravity = Gravity.END; + params.rightMargin = UIUtil.dip2px(context, 60); + params.topMargin = (int) info.getRectF().top - UIUtil.dip2px(context, 45) - UIUtil.dip2px(context, 34); + overLayer.setKnowedParams(params); + return list; + } + + public List createMiniWorldGuestPageMemberGuide(View memberChatLayout) { + List list = new ArrayList<>(); + if (memberChatLayout == null) { + return list; + } + // 底部布局 高亮 + OverLayer overLayer = new OverLayer(); + list.add(overLayer); + + LightConfig lightConfig; + lightConfig = new LightConfig(memberChatLayout); + int radius = UIUtil.dip2px(context, 5) + memberChatLayout.getWidth() / 2; + lightConfig.setRadius(new float[]{radius, radius, radius, radius, radius, radius, radius, radius}); + lightConfig.setHPadding(UIUtil.dip2px(context, 30)); + lightConfig.setVPadding(UIUtil.dip2px(context, 5)); + HiLightInfo info = calcHiLightInfo(lightConfig); + if (info == null) { + return list; + } + List hiLightInfoList = new ArrayList<>(); + hiLightInfoList.add(info); + overLayer.addHiLightInfo(hiLightInfoList); + + ImageView imageView; + imageView = new ImageView(context); + imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); + imageView.setImageResource(R.drawable.icon_guide_to_chat_in_world_tips); + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( + UIUtil.dip2px(context, 278), UIUtil.dip2px(context, 114) + ); + params.gravity = Gravity.END; + params.rightMargin = UIUtil.dip2px(context, 60); + params.topMargin = (int) info.getRectF().top - UIUtil.dip2px(context, 25) - UIUtil.dip2px(context, 114); + imageView.setLayoutParams(params); + overLayer.addTipsView(imageView); + + params = createKnowedParams(context); + params.gravity = Gravity.END; + params.rightMargin = UIUtil.dip2px(context, 60); + params.topMargin = (int) info.getRectF().top - UIUtil.dip2px(context, 45) - UIUtil.dip2px(context, 34); + overLayer.setKnowedParams(params); + return list; + } + + + public List createGiftDialogOverLayer(View avatar) { + List list = new ArrayList<>(); + if (avatar == null) { + return list; + } + OverLayer overLayer = new OverLayer(); + list.add(overLayer); + + LightConfig lightConfig = new LightConfig(avatar); + int dp_9 = UIUtil.dip2px(context, 9); + lightConfig.setRadius(new float[]{dp_9, dp_9, dp_9, dp_9, dp_9, dp_9, dp_9, dp_9}); + lightConfig.setVPadding(UIUtil.dip2px(context, 8.5f)); + HiLightInfo info = calcHiLightInfo(lightConfig); + if (info == null) { + return list; + } + List hiLightInfoList = new ArrayList<>(); + hiLightInfoList.add(info); + overLayer.addHiLightInfo(hiLightInfoList); + + ImageView imageView = new ImageView(context); + imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); + imageView.setImageResource(R.drawable.icon_guide_giftdialog_tips); + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( + UIUtil.dip2px(context, 315), UIUtil.dip2px(context, 66) + ); + params.leftMargin = UIUtil.dip2px(context, 31); + params.topMargin = (int) info.getRectF().top - UIUtil.dip2px(context, 66) - UIUtil.dip2px(context, 21); + imageView.setLayoutParams(params); + overLayer.addTipsView(imageView); + + params = createKnowedParams(context); + params.leftMargin = UIUtil.dip2px(context, 272); + params.topMargin = (int) info.getRectF().top - UIUtil.dip2px(context, 107) - UIUtil.dip2px(context, 34); + overLayer.setKnowedParams(params); + + return list; + } + + /** + * 高亮首页 + * + * @param views banner + * @param view item + * @return + */ + public List createMainHomeGuide(List views, View view) { + List list = new ArrayList<>(); + + OverLayer overLayer = new OverLayer(); + list.add(overLayer); + List hiLightInfoList = new ArrayList<>(); + for (View v : views) { + LightConfig lightConfig; + lightConfig = new LightConfig(v); + HiLightInfo info; + info = calcHiLightInfo(lightConfig); + if (info == null) { + continue; + } + hiLightInfoList.add(info); + + } + HiLightInfo info = hiLightInfoList.get(0); + + + overLayer.addHiLightInfo(hiLightInfoList); + + ImageView imageView; + //文案 + imageView = new ImageView(context); + imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); + imageView.setImageResource(R.drawable.icon_guide_main_home_copywriting_1); + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( + UIUtil.dip2px(context, 278.6f), UIUtil.dip2px(context, 92.6f) + ); + params.gravity = Gravity.END; + params.rightMargin = UIUtil.dip2px(context, 51); + params.topMargin = (int) info.getRectF().bottom + UIUtil.dip2px(context, 14); + imageView.setLayoutParams(params); + overLayer.addTipsView(imageView); +// + //下面的logo + imageView = new ImageView(context); + imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); + imageView.setImageResource(R.drawable.icon_guide_logo_left_center); + params = new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT + ); + params.gravity = Gravity.LEFT | Gravity.BOTTOM; +// params.rightMargin = UIUtil.dip2px(context, 51); +// params.topMargin = (int) info.getRectF().top; + imageView.setLayoutParams(params); + overLayer.addTipsView(imageView); + + params = createNextParams(context); + params.gravity = Gravity.END; + params.rightMargin = UIUtil.dip2px(context, 51); + params.topMargin = (int) info.getRectF().bottom + UIUtil.dip2px(context, 101); + overLayer.setNextParams(params); + + overLayer.setNeedSkip(true); +// + overLayer = new OverLayer(); + list.add(overLayer); + + LightConfig lightConfig = new LightConfig(view); + int radiu = UIUtil.dip2px(context, 24); + lightConfig.setRadius(new float[]{radiu, radiu, radiu, radiu, radiu, radiu, radiu, radiu}); + lightConfig.setRightPadding(UIUtil.dip2px(context, 15)); + lightConfig.setLeftPadding(UIUtil.dip2px(context, 6.5f)); + lightConfig.setVPadding(UIUtil.dip2px(context, 6.5f)); + info = calcHiLightInfo(lightConfig); + if (info == null) { + return list; + } + hiLightInfoList = new ArrayList<>(); + hiLightInfoList.add(info); + overLayer.addHiLightInfo(hiLightInfoList); + + imageView = new ImageView(context); + imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); + imageView.setImageResource(R.drawable.icon_guide_main_home_copywriting_2); + params = new FrameLayout.LayoutParams( + UIUtil.dip2px(context, 278.6f), UIUtil.dip2px(context, 92.6f) + ); + params.gravity = Gravity.LEFT; + params.leftMargin = UIUtil.dip2px(context, 54); + params.topMargin = (int) info.getRectF().top - UIUtil.dip2px(context, 66) - UIUtil.dip2px(context, 21) - UIUtil.dip2px(context, 21); + imageView.setLayoutParams(params); + overLayer.addTipsView(imageView); + + imageView = new ImageView(context); + imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); + imageView.setImageResource(R.drawable.icon_guide_logo_right_bottom); + params = new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT + ); + params.gravity = Gravity.END | Gravity.BOTTOM; +// + imageView.setLayoutParams(params); + overLayer.addTipsView(imageView); + + params = createKnowedParams(context); + params.gravity = Gravity.END; + params.rightMargin = UIUtil.dip2px(context, 36); + params.topMargin = (int) info.getRectF().top - UIUtil.dip2px(context, 107) - UIUtil.dip2px(context, 34); + overLayer.setKnowedParams(params); + + return list; + } + + + /** + * 根据需要的配置,计算好高亮的区域信息 + * + * @param lightConfig + * @return + */ + private HiLightInfo calcHiLightInfo(LightConfig lightConfig) { + if (lightConfig == null || lightConfig.getView() == null) { + return null; + } + View hiLightView = lightConfig.getView(); + int[] parentLoca = new int[2]; + guideParent.getLocationOnScreen(parentLoca); + int[] lightLoca = new int[2]; + hiLightView.getLocationOnScreen(lightLoca); + HiLightInfo info = new HiLightInfo(); + int top = lightLoca[1] - parentLoca[1] - lightConfig.getTopPadding(); + int left = lightLoca[0] - parentLoca[0] - lightConfig.getLeftPadding(); + int bottom = top + hiLightView.getHeight() + lightConfig.getTopPadding() + lightConfig.getBottomPadding(); + int right = left + lightConfig.getLeftPadding() + lightConfig.getRightPadding() + hiLightView.getWidth(); + RectF rectF = new RectF(left, top, right, bottom); + info.setRectF(rectF); + if (lightConfig.getRadius() != null) { + info.setRadis(lightConfig.getRadius()); + info.setShapeType(HiLightInfo.ROUND_RECT); + } else { + info.setShapeType(HiLightInfo.NORMAL_RECT); + } + return info; + } + + public List createDiceOverLayer() { + List list = new ArrayList<>(); + //第一层 + OverLayer overLayer = new OverLayer(); + View view = View.inflate(context, R.layout.layout_dice_guide, null); + view.setLayoutParams(createLayoutParams()); + overLayer.addTipsView(view); + + list.add(overLayer); + + return list; + } + + public static ViewGroup.LayoutParams createLayoutParams() { + return new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT); + } + + public static FrameLayout.LayoutParams createSkipParams(Context context) { + return new FrameLayout.LayoutParams( + UIUtil.dip2px(context, 46), UIUtil.dip2px(context, 25) + ); + } + + public static FrameLayout.LayoutParams createKnowedParams(Context context) { + return new FrameLayout.LayoutParams( + UIUtil.dip2px(context, 76), UIUtil.dip2px(context, 34) + ); + } + + public static FrameLayout.LayoutParams createNextParams(Context context) { + return new FrameLayout.LayoutParams( + UIUtil.dip2px(context, 76), UIUtil.dip2px(context, 34) + ); + } + + public void start() { + if (mRootView == null || guideParent == null) { + return; + } + guideParent.next(); + } + + + public static boolean isNeedHiGuide(String type) { + boolean result = true; + if (TextUtils.isEmpty(type)) { + return false; + } + Boolean cache = (Boolean) SharedPreferenceUtils.get(type, true); + if (cache != null) { + result = cache; + } +// return result; + return false;// 20190727 所有新手引导去掉 + } + + public static void setNoNeedHiGuide(String type) { + if (TextUtils.isEmpty(type)) { + return; + } + SharedPreferenceUtils.put(type, false); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/higuide/TuTuGuideView.java b/app/src/main/java/com/chwl/app/ui/widget/higuide/TuTuGuideView.java new file mode 100644 index 0000000..10eec0a --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/higuide/TuTuGuideView.java @@ -0,0 +1,170 @@ +package com.chwl.app.ui.widget.higuide; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; + +import com.chwl.app.R; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; + +import java.util.ArrayList; +import java.util.List; + +/** + * create by lvzebiao @2019/5/21 + */ +public class TuTuGuideView extends FrameLayout { + + private int currentPage; + + private Path lightPath; + + private Path bgPath; + + private Paint paint; + + private Context context; + + public TuTuGuideView(@NonNull Context context) { + super(context); + this.context = context; + lightPath = new Path(); + lightPath.addRect(0, 0, 0, 0, Path.Direction.CW); + + bgPath = new Path(); + //init Paint + paint = new Paint(); + paint.setColor(context.getResources().getColor(R.color.black_transparent_65)); + paint.setAntiAlias(true); + paint.setDither(true); + setWillNotDraw(false); + + lightList = new ArrayList<>(); + layerList = new ArrayList<>(); + setOnClickListener(v -> next()); + + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + bgPath.reset(); + bgPath.addRect(0, 0, getWidth(), getHeight(), Path.Direction.CW); + + //添加高亮 + if (lightList != null) { + for (HiLightInfo info : lightList) { + lightPath.reset(); + if (info.getShapeType() == HiLightInfo.ROUND_RECT) { + lightPath.addRoundRect(info.getRectF(), info.getRadis(), Path.Direction.CW); + } else { + lightPath.addRect(info.getRectF(), Path.Direction.CW); + } + bgPath.op(lightPath, Path.Op.XOR); + } + } + canvas.drawPath(bgPath, paint); + } + + public void addOverLayer(OverLayer overLayer) { + layerList.add(overLayer); + } + + public void remove() { + ViewGroup parent = (ViewGroup) getParent(); + if (parent != null) { + parent.removeView(TuTuGuideView.this); + } + } + + public void show() { + invalidate(); + } + + private List lightList; + + private List layerList; + + public void next() { + removeAllViews(); + if (currentPage < layerList.size()) { + OverLayer overLayer = layerList.get(currentPage); + + lightList = overLayer.hiLightInfoList; + for (View index : overLayer.tipsViewList) { + addView(index); + } + if (overLayer.needSkip) { + TextView textView = new TextView(context); + textView.setText(R.string.skip_guide); + int padding = UIUtil.dip2px(context, 5); + textView.setPadding(padding, padding, padding, padding); + textView.setGravity(Gravity.CENTER); + textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 13); + textView.setTextColor(context.getResources().getColor(R.color.white_transparent_30)); + textView.setOnClickListener(v -> { + remove();// 跳过 + if (showFinishListener != null) { + showFinishListener.onSkip(); + } + }); + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT); + params.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; + params.bottomMargin = UIUtil.dip2px(context, 60); + addView(textView, params); + } + if (overLayer.knowedParams != null) { + ImageView imageView = new ImageView(context); + imageView.setImageResource(R.drawable.icon_guide_knowed); + imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); + addView(imageView, overLayer.knowedParams); + } + if (overLayer.nextParams != null) { + ImageView imageView = new ImageView(context); + imageView.setImageResource(R.drawable.icon_guide_next); + imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); + addView(imageView, overLayer.nextParams); + } + invalidate(); + currentPage++; + } else { + remove();// 全部展示完毕 + if (showFinishListener != null) { + showFinishListener.onGuideFinish(); + } + } + + } + + private IGuideShowFinishListener showFinishListener; + + public void setShowFinishListener(IGuideShowFinishListener showFinishListener) { + this.showFinishListener = showFinishListener; + } + + public interface IGuideShowFinishListener { + /** + * 跳过 + */ + void onSkip(); + + /** + * 引导图已经全部展示完毕 + */ + default void onGuideFinish() { + + } + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/interfacex/MicListItem.java b/app/src/main/java/com/chwl/app/ui/widget/interfacex/MicListItem.java new file mode 100644 index 0000000..1cf5e6b --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/interfacex/MicListItem.java @@ -0,0 +1,23 @@ +package com.chwl.app.ui.widget.interfacex; + +import com.chwl.core.user.bean.UserInfo; + +/** + * Created by zhouxiangfeng on 2017/6/15. + */ + +public interface MicListItem { + void initiate(UserInfo userInfo); + + UserInfo getUserInfo(); + + void setRoomOwner(boolean isOwner); + + void setSpeeking(boolean isSpeeking); + + void setAuctionRole(boolean isAuction); + + boolean isAuction(); + + boolean isOwner(); +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/magicindicator/FragmentContainerHelper.java b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/FragmentContainerHelper.java new file mode 100644 index 0000000..a05d063 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/FragmentContainerHelper.java @@ -0,0 +1,162 @@ +package com.chwl.app.ui.widget.magicindicator; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.annotation.TargetApi; +import android.os.Build; +import android.view.animation.AccelerateDecelerateInterpolator; +import android.view.animation.Interpolator; + +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.model.PositionData; + +import java.util.ArrayList; +import java.util.List; + + +/** + * 使得MagicIndicator在FragmentContainer中使用 + * Created by hackware on 2016/9/4. + */ + +@TargetApi(Build.VERSION_CODES.HONEYCOMB) +public class FragmentContainerHelper { + private List mMagicIndicators = new ArrayList(); + private ValueAnimator mScrollAnimator; + private int mLastSelectedIndex; + private int mDuration = 150; + private Interpolator mInterpolator = new AccelerateDecelerateInterpolator(); + + private Animator.AnimatorListener mAnimatorListener = new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + dispatchPageScrollStateChanged(ScrollState.SCROLL_STATE_IDLE); + mScrollAnimator = null; + } + }; + + private ValueAnimator.AnimatorUpdateListener mAnimatorUpdateListener = new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + float positionOffsetSum = (Float) animation.getAnimatedValue(); + int position = (int) positionOffsetSum; + float positionOffset = positionOffsetSum - position; + if (positionOffsetSum < 0) { + position = position - 1; + positionOffset = 1.0f + positionOffset; + } + dispatchPageScrolled(position, positionOffset, 0); + } + }; + + public FragmentContainerHelper() { + } + + public FragmentContainerHelper(MagicIndicator magicIndicator) { + mMagicIndicators.add(magicIndicator); + } + + /** + * IPagerIndicator支持弹性效果的辅助方法 + * + * @param positionDataList + * @param index + * @return + */ + public static PositionData getImitativePositionData(List positionDataList, int index) { + if (index >= 0 && index <= positionDataList.size() - 1) { // 越界后,返回假的PositionData + return positionDataList.get(index); + } else { + PositionData result = new PositionData(); + PositionData referenceData; + int offset; + if (index < 0) { + offset = index; + referenceData = positionDataList.get(0); + } else { + offset = index - positionDataList.size() + 1; + referenceData = positionDataList.get(positionDataList.size() - 1); + } + result.mLeft = referenceData.mLeft + offset * referenceData.width(); + result.mTop = referenceData.mTop; + result.mRight = referenceData.mRight + offset * referenceData.width(); + result.mBottom = referenceData.mBottom; + result.mContentLeft = referenceData.mContentLeft + offset * referenceData.width(); + result.mContentTop = referenceData.mContentTop; + result.mContentRight = referenceData.mContentRight + offset * referenceData.width(); + result.mContentBottom = referenceData.mContentBottom; + return result; + } + } + + public void handlePageSelected(int selectedIndex) { + handlePageSelected(selectedIndex, true); + } + + public void handlePageSelected(int selectedIndex, boolean smooth) { + if (mLastSelectedIndex == selectedIndex) { + return; + } + if (smooth) { + if (mScrollAnimator == null || !mScrollAnimator.isRunning()) { + dispatchPageScrollStateChanged(ScrollState.SCROLL_STATE_SETTLING); + } + dispatchPageSelected(selectedIndex); + float currentPositionOffsetSum = mLastSelectedIndex; + if (mScrollAnimator != null) { + currentPositionOffsetSum = (Float) mScrollAnimator.getAnimatedValue(); + mScrollAnimator.cancel(); + mScrollAnimator = null; + } + mScrollAnimator = new ValueAnimator(); + mScrollAnimator.setFloatValues(currentPositionOffsetSum, selectedIndex); // position = selectedIndex, positionOffset = 0.0f + mScrollAnimator.addUpdateListener(mAnimatorUpdateListener); + mScrollAnimator.addListener(mAnimatorListener); + mScrollAnimator.setInterpolator(mInterpolator); + mScrollAnimator.setDuration(mDuration); + mScrollAnimator.start(); + } else { + dispatchPageSelected(selectedIndex); + if (mScrollAnimator != null && mScrollAnimator.isRunning()) { + dispatchPageScrolled(mLastSelectedIndex, 0.0f, 0); + } + dispatchPageScrollStateChanged(ScrollState.SCROLL_STATE_IDLE); + dispatchPageScrolled(selectedIndex, 0.0f, 0); + } + mLastSelectedIndex = selectedIndex; + } + + public void setDuration(int duration) { + mDuration = duration; + } + + public void setInterpolator(Interpolator interpolator) { + if (interpolator == null) { + mInterpolator = new AccelerateDecelerateInterpolator(); + } else { + mInterpolator = interpolator; + } + } + + public void attachMagicIndicator(MagicIndicator magicIndicator) { + mMagicIndicators.add(magicIndicator); + } + + private void dispatchPageSelected(int pageIndex) { + for (MagicIndicator magicIndicator : mMagicIndicators) { + magicIndicator.onPageSelected(pageIndex); + } + } + + private void dispatchPageScrollStateChanged(int state) { + for (MagicIndicator magicIndicator : mMagicIndicators) { + magicIndicator.onPageScrollStateChanged(state); + } + } + + private void dispatchPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + for (MagicIndicator magicIndicator : mMagicIndicators) { + magicIndicator.onPageScrolled(position, positionOffset, positionOffsetPixels); + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/magicindicator/GiftIndicator.java b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/GiftIndicator.java new file mode 100644 index 0000000..3f7f67e --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/GiftIndicator.java @@ -0,0 +1,186 @@ +package com.chwl.app.ui.widget.magicindicator; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.HorizontalScrollView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.Nullable; + +import com.chwl.app.R; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.core.gift.bean.GiftTab; + +import java.util.ArrayList; +import java.util.List; + +import io.reactivex.Observable; +import lombok.Getter; + +/** + *

公共多个滑动tab样式

+ * + * @author Administrator + * @date 2017/11/15 + */ +public class GiftIndicator extends LinearLayout { + + /** + * 普通礼物 + */ + public static final int TYPE_NORMAL = 0; + + /** + * 星球礼物 + */ + public static final int TYPE_LUCKY = 1; + + /** + * 贵族礼物 + */ + public static final int TYPE_NOBLE = 2; + + + /** + * 周星礼物 + */ + public static final int TYPE_WEEK = 3; + + /** + * 涂鸦礼物 + */ + public static final int TYPE_DRAW_GIFT = 4; + + /** + * 背包礼物 + */ + public static final int TYPE_KNAP = 5; + + + /** + * 个播人气礼物 + */ + public static final int TYPE_SING_ROOM = 6; + + /** + * 国家礼物 + */ + public static final int TYPE_COUNTRY = 7; + + /** + * 超级幸运礼物 + */ + public static final int TYPE_SUPER_LUCKY = 8; + /** + * 超级幸运24礼物 + */ + public static final int TYPE_SUPER_LUCKY_24 = 9; + /** + * cp礼物 + */ + public static final int TYPE_CP = 10; + /** + * 定制礼物 + */ + public static final int TYPE_CUSTOM = 11; + /** + * 超级幸运礼物礼物 + */ + public static final int TYPE_BRAVO = 12; + + private List tabList = new ArrayList<>(); + + @Getter + private int currrentType = TYPE_NORMAL; + + private int mFalseColor; + private int mTrueColor; + private LinearLayout tabLayout; + private View knapView; + private HorizontalScrollView scrollView; + + public GiftIndicator(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + LayoutInflater.from(context).inflate(R.layout.gift_dialog_tab_indicator, this, true); + setOrientation(LinearLayout.HORIZONTAL); + setGravity(Gravity.CENTER_VERTICAL); + scrollView = findViewById(R.id.scroll_view); + tabLayout = findViewById(R.id.layout_tab); + knapView = findViewById(R.id.iv_knap); + } + + public void initTab(List list, int falseColor, int trueColor) { + for (int i = 0; i < list.size(); i++) { + GiftTab tab = list.get(i); + View view = inflate(GiftIndicator.this.getContext(), R.layout.layout_gift_indicator_item, null); + tab.setItemView(view); + tabLayout.addView(view, new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, + UIUtil.dip2px(getContext(), 26))); + TextView tvTitle = view.findViewById(R.id.tv_title); + tvTitle.setText(tab.getUnSelectedTitle()); + } + tabList = list; + mFalseColor = falseColor; + mTrueColor = trueColor; + setPosition(TYPE_NORMAL); + } + + public Observable addClick() { + return Observable.create(emitter -> { + for (int i = 0; i < tabList.size(); i++) { + final GiftTab index = tabList.get(i); + index.getItemView().setOnClickListener(v -> { + setPosition(index.getType()); + emitter.onNext(index.getType()); + }); + } + knapView.setOnClickListener(v -> { + setPosition(TYPE_KNAP); + emitter.onNext(TYPE_KNAP); + }); + }); + } + + public void setPosition(int type) { + currrentType = type; + for (int i = 0; i < tabList.size(); i++) { + GiftTab tab = tabList.get(i); + View view = tab.getItemView(); + TextView tvTitle = view.findViewById(R.id.tv_title); + if (tab.getType() == currrentType) { + tvTitle.setTextColor(mTrueColor); + tvTitle.setText(tab.getSelectedTitle()); + } else { + tvTitle.setTextColor(mFalseColor); + tvTitle.setText(tab.getUnSelectedTitle()); + } + } + } + + public void hidePosition(int type) { + for (GiftTab tab : tabList) { + if (tab.getType() == type) { + tab.getItemView().setVisibility(GONE); + break; + } + } + } + + public void showPosition(int type) { + for (GiftTab tab : tabList) { + if (tab.getType() == type) { + tab.getItemView().setVisibility(VISIBLE); + break; + } + } + } + + public void fullScroll(int direction) { + scrollView.fullScroll(direction); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/magicindicator/MagicIndicator.java b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/MagicIndicator.java new file mode 100644 index 0000000..7cd2e5f --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/MagicIndicator.java @@ -0,0 +1,63 @@ +package com.chwl.app.ui.widget.magicindicator; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.widget.FrameLayout; + +import com.chwl.app.ui.widget.magicindicator.abs.IPagerNavigator; + +/** + * 整个框架的入口,核心 + * 博客: http://hackware.lucode.net + * Created by hackware on 2016/6/26. + */ +public class MagicIndicator extends FrameLayout { + private IPagerNavigator mNavigator; + + public MagicIndicator(Context context) { + super(context); + } + + public MagicIndicator(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + if (mNavigator != null) { + mNavigator.onPageScrolled(position, positionOffset, positionOffsetPixels); + } + } + + public void onPageSelected(int position) { + if (mNavigator != null) { + mNavigator.onPageSelected(position); + } + } + + public void onPageScrollStateChanged(int state) { + if (mNavigator != null) { + mNavigator.onPageScrollStateChanged(state); + } + } + + public IPagerNavigator getNavigator() { + return mNavigator; + } + + public void setNavigator(IPagerNavigator navigator) { + if (mNavigator == navigator) { + return; + } + if (mNavigator != null) { + mNavigator.onDetachFromMagicIndicator(); + } + mNavigator = navigator; + removeAllViews(); + if (mNavigator instanceof View) { + LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); + addView((View) mNavigator, lp); + mNavigator.onAttachToMagicIndicator(); + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/magicindicator/NavigatorHelper.java b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/NavigatorHelper.java new file mode 100644 index 0000000..f15149e --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/NavigatorHelper.java @@ -0,0 +1,171 @@ +package com.chwl.app.ui.widget.magicindicator; + +import android.util.SparseArray; +import android.util.SparseBooleanArray; + + +/** + * 方便扩展IPagerNavigator的帮助类,将ViewPager的3个回调方法转换成 + * onSelected、onDeselected、onEnter等回调,方便扩展 + * 博客: http://hackware.lucode.net + * Created by hackware on 2016/6/26. + */ +public class NavigatorHelper { + private SparseBooleanArray mDeselectedItems = new SparseBooleanArray(); + private SparseArray mLeavedPercents = new SparseArray(); + + private int mTotalCount; + private int mCurrentIndex; + private int mLastIndex; + private float mLastPositionOffsetSum; + private int mScrollState; + + private boolean mSkimOver; + private NavigatorHelper.OnNavigatorScrollListener mNavigatorScrollListener; + + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + float currentPositionOffsetSum = position + positionOffset; + boolean leftToRight = false; + if (mLastPositionOffsetSum <= currentPositionOffsetSum) { + leftToRight = true; + } + if (mScrollState != ScrollState.SCROLL_STATE_IDLE) { + if (currentPositionOffsetSum == mLastPositionOffsetSum) { + return; + } + int nextPosition = position + 1; + boolean normalDispatch = true; + if (positionOffset == 0.0f) { + if (leftToRight) { + nextPosition = position - 1; + normalDispatch = false; + } + } + for (int i = 0; i < mTotalCount; i++) { + if (i == position || i == nextPosition) { + continue; + } + Float leavedPercent = mLeavedPercents.get(i, 0.0f); + if (leavedPercent != 1.0f) { + dispatchOnLeave(i, 1.0f, leftToRight, true); + } + } + if (normalDispatch) { + if (leftToRight) { + dispatchOnLeave(position, positionOffset, true, false); + dispatchOnEnter(nextPosition, positionOffset, true, false); + } else { + dispatchOnLeave(nextPosition, 1.0f - positionOffset, false, false); + dispatchOnEnter(position, 1.0f - positionOffset, false, false); + } + } else { + dispatchOnLeave(nextPosition, 1.0f - positionOffset, true, false); + dispatchOnEnter(position, 1.0f - positionOffset, true, false); + } + } else { + for (int i = 0; i < mTotalCount; i++) { + if (i == mCurrentIndex) { + continue; + } + boolean deselected = mDeselectedItems.get(i); + if (!deselected) { + dispatchOnDeselected(i); + } + Float leavedPercent = mLeavedPercents.get(i, 0.0f); + if (leavedPercent != 1.0f) { + dispatchOnLeave(i, 1.0f, false, true); + } + } + dispatchOnEnter(mCurrentIndex, 1.0f, false, true); + dispatchOnSelected(mCurrentIndex); + } + mLastPositionOffsetSum = currentPositionOffsetSum; + } + + private void dispatchOnEnter(int index, float enterPercent, boolean leftToRight, boolean force) { + if (mSkimOver || index == mCurrentIndex || mScrollState == ScrollState.SCROLL_STATE_DRAGGING || force) { + if (mNavigatorScrollListener != null) { + mNavigatorScrollListener.onEnter(index, mTotalCount, enterPercent, leftToRight); + } + mLeavedPercents.put(index, 1.0f - enterPercent); + } + } + + private void dispatchOnLeave(int index, float leavePercent, boolean leftToRight, boolean force) { + if (mSkimOver || index == mLastIndex || mScrollState == ScrollState.SCROLL_STATE_DRAGGING || ((index == mCurrentIndex - 1 || index == mCurrentIndex + 1) && mLeavedPercents.get(index, 0.0f) != 1.0f) || force) { + if (mNavigatorScrollListener != null) { + mNavigatorScrollListener.onLeave(index, mTotalCount, leavePercent, leftToRight); + } + mLeavedPercents.put(index, leavePercent); + } + } + + private void dispatchOnSelected(int index) { + if (mNavigatorScrollListener != null) { + mNavigatorScrollListener.onSelected(index, mTotalCount); + } + mDeselectedItems.put(index, false); + } + + private void dispatchOnDeselected(int index) { + if (mNavigatorScrollListener != null) { + mNavigatorScrollListener.onDeselected(index, mTotalCount); + } + mDeselectedItems.put(index, true); + } + + public void onPageSelected(int position) { + mLastIndex = mCurrentIndex; + mCurrentIndex = position; + dispatchOnSelected(mCurrentIndex); + for (int i = 0; i < mTotalCount; i++) { + if (i == mCurrentIndex) { + continue; + } + boolean deselected = mDeselectedItems.get(i); + if (!deselected) { + dispatchOnDeselected(i); + } + } + } + + public void onPageScrollStateChanged(int state) { + mScrollState = state; + } + + public void setNavigatorScrollListener(NavigatorHelper.OnNavigatorScrollListener navigatorScrollListener) { + mNavigatorScrollListener = navigatorScrollListener; + } + + public void setSkimOver(boolean skimOver) { + mSkimOver = skimOver; + } + + public int getTotalCount() { + return mTotalCount; + } + + public void setTotalCount(int totalCount) { + mTotalCount = totalCount; + mDeselectedItems.clear(); + mLeavedPercents.clear(); + } + + public int getCurrentIndex() { + return mCurrentIndex; + } + + public int getScrollState() { + return mScrollState; + } + + public interface OnNavigatorScrollListener { + void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight); + + void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight); + + void onSelected(int index, int totalCount); + + void onDeselected(int index, int totalCount); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/magicindicator/ScrollState.java b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/ScrollState.java new file mode 100644 index 0000000..df196ed --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/ScrollState.java @@ -0,0 +1,12 @@ +package com.chwl.app.ui.widget.magicindicator; + +/** + * 自定义滚动状态,消除对ViewPager的依赖 + * Created by hackware on 2016/8/27. + */ + +public interface ScrollState { + int SCROLL_STATE_IDLE = 0; + int SCROLL_STATE_DRAGGING = 1; + int SCROLL_STATE_SETTLING = 2; +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/magicindicator/ViewPagerHelper.java b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/ViewPagerHelper.java new file mode 100644 index 0000000..eade653 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/ViewPagerHelper.java @@ -0,0 +1,62 @@ +package com.chwl.app.ui.widget.magicindicator; + +import androidx.viewpager.widget.ViewPager; +import androidx.viewpager2.widget.ViewPager2; + + +/** + * 简化和ViewPager绑定 + * Created by hackware on 2016/8/17. + */ + +public class ViewPagerHelper { + + public static void bind(final MagicIndicator magicIndicator, ViewPager2 viewPager) { + if (viewPager == null) { + return; + } + viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() { + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + if (magicIndicator != null) { + magicIndicator.onPageScrolled(position, positionOffset, positionOffsetPixels); + } + } + + @Override + public void onPageSelected(int position) { + if (magicIndicator != null) { + magicIndicator.onPageSelected(position); + } + } + + @Override + public void onPageScrollStateChanged(int state) { + if (magicIndicator != null) { + magicIndicator.onPageScrollStateChanged(state); + } + } + }); + } + + public static void bind(final MagicIndicator magicIndicator, ViewPager viewPager) { + viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + magicIndicator.onPageScrolled(position, positionOffset, positionOffsetPixels); + } + + @Override + public void onPageSelected(int position) { + magicIndicator.onPageSelected(position); + } + + @Override + public void onPageScrollStateChanged(int state) { + magicIndicator.onPageScrollStateChanged(state); + } + }); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/magicindicator/abs/IPagerNavigator.java b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/abs/IPagerNavigator.java new file mode 100644 index 0000000..c29f3d9 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/abs/IPagerNavigator.java @@ -0,0 +1,34 @@ +package com.chwl.app.ui.widget.magicindicator.abs; + +/** + * 抽象的ViewPager导航器 + * 博客: http://hackware.lucode.net + * Created by hackware on 2016/6/26. + */ +public interface IPagerNavigator { + + ///////////////////////// ViewPager的3个回调 + void onPageScrolled(int position, float positionOffset, int positionOffsetPixels); + + void onPageSelected(int position); + + void onPageScrollStateChanged(int state); + ///////////////////////// + + /** + * 当IPagerNavigator被添加到MagicIndicator时调用 + */ + void onAttachToMagicIndicator(); + + /** + * 当IPagerNavigator从MagicIndicator上移除时调用 + */ + void onDetachFromMagicIndicator(); + + /** + * ViewPager内容改变时需要先调用此方法,自定义的IPagerNavigator应当遵守此约定 + */ + void notifyDataSetChanged(); + + int getCurrentIndex(); +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/ArgbEvaluatorHolder.java b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/ArgbEvaluatorHolder.java new file mode 100644 index 0000000..885b27b --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/ArgbEvaluatorHolder.java @@ -0,0 +1,28 @@ +package com.chwl.app.ui.widget.magicindicator.buildins; + + +/** + * 实现颜色渐变,考虑到兼容性,不使用内置的ArgbEvaluator + * 博客: http://hackware.lucode.net + * Created by hackware on 2016/6/26. + */ +public class ArgbEvaluatorHolder { + public static int eval(float fraction, int startValue, int endValue) { + int startA = (startValue >> 24) & 0xff; + int startR = (startValue >> 16) & 0xff; + int startG = (startValue >> 8) & 0xff; + int startB = startValue & 0xff; + + int endA = (endValue >> 24) & 0xff; + int endR = (endValue >> 16) & 0xff; + int endG = (endValue >> 8) & 0xff; + int endB = endValue & 0xff; + + int currentA = (startA + (int) (fraction * (endA - startA))) << 24; + int currentR = (startR + (int) (fraction * (endR - startR))) << 16; + int currentG = (startG + (int) (fraction * (endG - startG))) << 8; + int currentB = startB + (int) (fraction * (endB - startB)); + + return currentA | currentR | currentG | currentB; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/UIUtil.java b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/UIUtil.java new file mode 100644 index 0000000..a92ae4f --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/UIUtil.java @@ -0,0 +1,23 @@ +package com.chwl.app.ui.widget.magicindicator.buildins; + +import android.content.Context; + +/** + * 博客: http://hackware.lucode.net + * Created by hackware on 2016/6/26. + */ +public final class UIUtil { + + public static int dip2px(Context context, double dpValue) { + float density = context.getResources().getDisplayMetrics().density; + return (int) (dpValue * density + 0.5); + } + + public static int getScreenWidth(Context context) { + return context.getResources().getDisplayMetrics().widthPixels; + } + + public static int getScreenHeight(Context context) { + return context.getResources().getDisplayMetrics().heightPixels; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/circlenavigator/CircleNavigator.java b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/circlenavigator/CircleNavigator.java new file mode 100644 index 0000000..85a947d --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/circlenavigator/CircleNavigator.java @@ -0,0 +1,314 @@ +package com.chwl.app.ui.widget.magicindicator.buildins.circlenavigator; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PointF; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.animation.Interpolator; +import android.view.animation.LinearInterpolator; + +import com.chwl.app.ui.widget.magicindicator.abs.IPagerNavigator; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; + +import java.util.ArrayList; +import java.util.List; + +/** + * 圆圈式的指示器 + * 博客: http://hackware.lucode.net + * Created by hackware on 2016/6/26. + */ +public class CircleNavigator extends View implements IPagerNavigator { + private int mRadius; + private int mCircleColor; + private int mStrokeWidth; + private int mCircleSpacing; + private int mCurrentIndex; + private int mTotalCount; + private Interpolator mStartInterpolator = new LinearInterpolator(); + + private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private List mCirclePoints = new ArrayList(); + private float mIndicatorX; + + // 事件回调 + private boolean mTouchable; + private OnCircleClickListener mCircleClickListener; + private float mDownX; + private float mDownY; + private int mTouchSlop; + + private boolean mFollowTouch = true; // 是否跟随手指滑动 + + public CircleNavigator(Context context) { + super(context); + init(context); + } + + private void init(Context context) { + mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); + mRadius = UIUtil.dip2px(context, 3); + mCircleSpacing = UIUtil.dip2px(context, 8); + mStrokeWidth = UIUtil.dip2px(context, 1); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec)); + } + + private int measureWidth(int widthMeasureSpec) { + int mode = MeasureSpec.getMode(widthMeasureSpec); + int width = MeasureSpec.getSize(widthMeasureSpec); + int result = 0; + switch (mode) { + case MeasureSpec.EXACTLY: + result = width; + break; + case MeasureSpec.AT_MOST: + case MeasureSpec.UNSPECIFIED: + result = mTotalCount * mRadius * 2 + (mTotalCount - 1) * mCircleSpacing + getPaddingLeft() + getPaddingRight() + mStrokeWidth * 2; + break; + default: + break; + } + return result; + } + + private int measureHeight(int heightMeasureSpec) { + int mode = MeasureSpec.getMode(heightMeasureSpec); + int height = MeasureSpec.getSize(heightMeasureSpec); + int result = 0; + switch (mode) { + case MeasureSpec.EXACTLY: + result = height; + break; + case MeasureSpec.AT_MOST: + case MeasureSpec.UNSPECIFIED: + result = mRadius * 2 + mStrokeWidth * 2 + getPaddingTop() + getPaddingBottom(); + break; + default: + break; + } + return result; + } + + @Override + protected void onDraw(Canvas canvas) { + mPaint.setColor(mCircleColor); + drawCircles(canvas); + drawIndicator(canvas); + } + + private void drawCircles(Canvas canvas) { + mPaint.setStyle(Paint.Style.STROKE); + mPaint.setStrokeWidth(mStrokeWidth); + for (int i = 0, j = mCirclePoints.size(); i < j; i++) { + PointF pointF = mCirclePoints.get(i); + canvas.drawCircle(pointF.x, pointF.y, mRadius, mPaint); + } + } + + private void drawIndicator(Canvas canvas) { + mPaint.setStyle(Paint.Style.FILL); + if (mCirclePoints.size() > 0) { + canvas.drawCircle(mIndicatorX, (int) (getHeight() / 2.0f + 0.5f), mRadius, mPaint); + } + } + + private void prepareCirclePoints() { + mCirclePoints.clear(); + if (mTotalCount > 0) { + int y = (int) (getHeight() / 2.0f + 0.5f); + int centerSpacing = mRadius * 2 + mCircleSpacing; + int startX = mRadius + (int) (mStrokeWidth / 2.0f + 0.5f) + getPaddingLeft(); + for (int i = 0; i < mTotalCount; i++) { + PointF pointF = new PointF(startX, y); + mCirclePoints.add(pointF); + startX += centerSpacing; + } + mIndicatorX = mCirclePoints.get(mCurrentIndex).x; + } + } + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + if (mFollowTouch) { + if (mCirclePoints.isEmpty()) { + return; + } + + int currentPosition = Math.min(mCirclePoints.size() - 1, position); + int nextPosition = Math.min(mCirclePoints.size() - 1, position + 1); + PointF current = mCirclePoints.get(currentPosition); + PointF next = mCirclePoints.get(nextPosition); + + mIndicatorX = current.x + (next.x - current.x) * mStartInterpolator.getInterpolation(positionOffset); + + invalidate(); + } + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + float x = event.getX(); + float y = event.getY(); + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + if (mTouchable) { + mDownX = x; + mDownY = y; + return true; + } + break; + case MotionEvent.ACTION_UP: + if (mCircleClickListener != null) { + if (Math.abs(x - mDownX) <= mTouchSlop && Math.abs(y - mDownY) <= mTouchSlop) { + float max = Float.MAX_VALUE; + int index = 0; + for (int i = 0; i < mCirclePoints.size(); i++) { + PointF pointF = mCirclePoints.get(i); + float offset = Math.abs(pointF.x - x); + if (offset < max) { + max = offset; + index = i; + } + } + mCircleClickListener.onClick(index); + } + } + break; + default: + break; + } + return super.onTouchEvent(event); + } + + @Override + public void onPageSelected(int position) { + mCurrentIndex = position; + if (!mFollowTouch) { + mIndicatorX = mCirclePoints.get(mCurrentIndex).x; + invalidate(); + } + } + + @Override + public void onPageScrollStateChanged(int state) { + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + prepareCirclePoints(); + } + + @Override + public void onAttachToMagicIndicator() { + } + + @Override + public void notifyDataSetChanged() { + prepareCirclePoints(); + invalidate(); + } + + @Override + public void onDetachFromMagicIndicator() { + } + + public int getRadius() { + return mRadius; + } + + public void setRadius(int radius) { + mRadius = radius; + prepareCirclePoints(); + invalidate(); + } + + public int getCircleColor() { + return mCircleColor; + } + + public void setCircleColor(int circleColor) { + mCircleColor = circleColor; + invalidate(); + } + + public int getStrokeWidth() { + return mStrokeWidth; + } + + public void setStrokeWidth(int strokeWidth) { + mStrokeWidth = strokeWidth; + invalidate(); + } + + public int getCircleSpacing() { + return mCircleSpacing; + } + + public void setCircleSpacing(int circleSpacing) { + mCircleSpacing = circleSpacing; + prepareCirclePoints(); + invalidate(); + } + + public Interpolator getStartInterpolator() { + return mStartInterpolator; + } + + public void setStartInterpolator(Interpolator startInterpolator) { + mStartInterpolator = startInterpolator; + if (mStartInterpolator == null) { + mStartInterpolator = new LinearInterpolator(); + } + } + + public int getCircleCount() { + return mTotalCount; + } + + public void setCircleCount(int count) { + mTotalCount = count; // 此处不调用invalidate,让外部调用notifyDataSetChanged + } + + public boolean isTouchable() { + return mTouchable; + } + + public void setTouchable(boolean touchable) { + mTouchable = touchable; + } + + public boolean isFollowTouch() { + return mFollowTouch; + } + + public void setFollowTouch(boolean followTouch) { + mFollowTouch = followTouch; + } + + public OnCircleClickListener getCircleClickListener() { + return mCircleClickListener; + } + + public void setCircleClickListener(OnCircleClickListener circleClickListener) { + if (!mTouchable) { + mTouchable = true; + } + mCircleClickListener = circleClickListener; + } + + @Override + public int getCurrentIndex() { + return mCurrentIndex; + } + + public interface OnCircleClickListener { + void onClick(int index); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/CommonNavigator.java b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/CommonNavigator.java new file mode 100644 index 0000000..e6ed7d9 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/CommonNavigator.java @@ -0,0 +1,494 @@ +package com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator; + +import android.content.Context; +import android.database.DataSetObserver; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.HorizontalScrollView; +import android.widget.LinearLayout; + +import com.chwl.app.R; +import com.chwl.app.ui.widget.magicindicator.NavigatorHelper; +import com.chwl.app.ui.widget.magicindicator.ScrollState; +import com.chwl.app.ui.widget.magicindicator.abs.IPagerNavigator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.CommonNavigatorAdapter; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IMeasurablePagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.model.PositionData; + +import java.util.ArrayList; +import java.util.List; + +/** + * 通用的ViewPager指示器,包含PagerTitle和PagerIndicator + * 博客: http://hackware.lucode.net + * Created by hackware on 2016/6/26. + */ +public class CommonNavigator extends FrameLayout implements IPagerNavigator, NavigatorHelper.OnNavigatorScrollListener { + private HorizontalScrollView mScrollView; + private LinearLayout mTitleContainer; + private LinearLayout mIndicatorContainer; + private IPagerIndicator mIndicator; + + private CommonNavigatorAdapter mAdapter; + private NavigatorHelper mNavigatorHelper; + + + /** + * 提供给外部的参数配置 + */ + /****************************************************/ + private boolean mTitleWrapContent; // 标题包裹内容,不MATCH_PARENT + private boolean mAdjustMode; // 自适应模式,适用于数目固定的、少量的title + private boolean mEnablePivotScroll; // 启动中心点滚动 + private float mScrollPivotX = 0.5f; // 滚动中心点 0.0f - 1.0f + private boolean mSmoothScroll = true; // 是否平滑滚动,适用于 !mAdjustMode && !mFollowTouch + private boolean mFollowTouch = true; // 是否手指跟随滚动 + private int mRightPadding; + private int mLeftPadding; + private boolean mIndicatorOnTop; // 指示器是否在title上层,默认为下层 + private boolean mSkimOver; // 跨多页切换时,中间页是否显示 ResUtil.getString(R.string.buildins_commonnavigator_commonnavigator_01) 效果 + private boolean mReselectWhenLayout = true; // PositionData准备好时,是否重新选中当前页,为true可保证在极端情况下指示器状态正确 + private int titleMargin; + private int titleGravity; + /****************************************************/ + + // 保存每个title的位置信息,为扩展indicator提供保障 + private List mPositionDataList = new ArrayList<>(); + private int fadingLength; + private DataSetObserver mObserver = new DataSetObserver() { + + @Override + public void onChanged() { + mNavigatorHelper.setTotalCount(mAdapter.getCount()); // 如果使用helper,应始终保证helper中的totalCount为最新 + init(); + } + + @Override + public void onInvalidated() { + // 没什么用,暂不做处理 + } + }; + private NavigatorSelectedListener mNavigatorSelectedListener; + + public CommonNavigator(Context context) { + this(context, 0); + } + + public CommonNavigator(Context context, int fadingLength) { + super(context); + mNavigatorHelper = new NavigatorHelper(); + mNavigatorHelper.setNavigatorScrollListener(this); + this.fadingLength = fadingLength; + } + + @Override + public void notifyDataSetChanged() { + if (mAdapter != null) { + mAdapter.notifyDataSetChanged(); + } + } + + public boolean isAdjustMode() { + return mAdjustMode; + } + + public void setAdjustMode(boolean is) { + mAdjustMode = is; + } + + public void setTitleWrapContent(boolean is) { + mTitleWrapContent = is; + } + + public void setTitleGravity(int gravity) { + this.titleGravity = gravity; + } + + public CommonNavigatorAdapter getAdapter() { + return mAdapter; + } + + public void setAdapter(CommonNavigatorAdapter adapter) { + if (mAdapter == adapter) { + return; + } + if (mAdapter != null) { + mAdapter.unregisterDataSetObserver(mObserver); + } + mAdapter = adapter; + if (mAdapter != null) { + mAdapter.registerDataSetObserver(mObserver); + mNavigatorHelper.setTotalCount(mAdapter.getCount()); + if (mTitleContainer != null) { // adapter改变时,应该重新init,但是第一次设置adapter不用,onAttachToMagicIndicator中有init + mAdapter.notifyDataSetChanged(); + } + } else { + mNavigatorHelper.setTotalCount(0); + init(); + } + } + + private void init() { + removeAllViews(); + + View root; + if (mAdjustMode) { + root = LayoutInflater.from(getContext()).inflate(R.layout.pager_navigator_layout_no_scroll, this); + } else { + root = LayoutInflater.from(getContext()).inflate(R.layout.pager_navigator_layout, this); + } + + mScrollView = (HorizontalScrollView) root.findViewById(R.id.scroll_view); + // mAdjustMode为true时,mScrollView为null + setFadingEdge(); + + mTitleContainer = (LinearLayout) root.findViewById(R.id.title_container); + mTitleContainer.setPadding(mLeftPadding, 0, mRightPadding, 0); + + mIndicatorContainer = (LinearLayout) root.findViewById(R.id.indicator_container); + if (mIndicatorOnTop) { + mIndicatorContainer.getParent().bringChildToFront(mIndicatorContainer); + } + + initTitlesAndIndicator(); + } + + /** + * 初始化title和indicator + */ + private void initTitlesAndIndicator() { + for (int i = 0, j = mNavigatorHelper.getTotalCount(); i < j; i++) { + IPagerTitleView v = mAdapter.getTitleView(getContext(), i); + if (v instanceof View) { + View view = (View) v; + LinearLayout.LayoutParams lp; + if (mAdjustMode) { + lp = new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT); + lp.weight = mAdapter.getTitleWeight(getContext(), i); + } else if (mTitleWrapContent) { + lp = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + } else { + lp = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); + } + lp.setMargins(titleMargin, 0, titleMargin, 0); + if (titleGravity != 0) { + lp.gravity = titleGravity; + } + mTitleContainer.addView(view, lp); + } + } + if (mAdapter != null) { + mIndicator = mAdapter.getIndicator(getContext()); + if (mIndicator instanceof View) { + LayoutParams lp = (LayoutParams) ((View) mIndicator).getLayoutParams(); + if (lp == null) { + lp = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + } + mIndicatorContainer.addView((View) mIndicator, lp); + } + } + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + if (mAdapter != null) { + preparePositionData(); + if (mIndicator != null) { + mIndicator.onPositionDataProvide(mPositionDataList); + } + if (mReselectWhenLayout && mNavigatorHelper.getScrollState() == ScrollState.SCROLL_STATE_IDLE) { + onPageSelected(mNavigatorHelper.getCurrentIndex()); + onPageScrolled(mNavigatorHelper.getCurrentIndex(), 0.0f, 0); + } + } + } + + /** + * 获取title的位置信息,为打造不同的指示器、各种效果提供可能 + */ + private void preparePositionData() { + mPositionDataList.clear(); + for (int i = 0, j = mNavigatorHelper.getTotalCount(); i < j; i++) { + PositionData data = new PositionData(); + View v = mTitleContainer.getChildAt(i); + if (v != null) { + //这里是更改是缩放中心 + v.setPivotX(v.getWidth() / 2f); + v.setPivotY(v.getHeight()); + data.mLeft = v.getLeft(); + data.mTop = v.getTop(); + data.mRight = v.getRight(); + data.mBottom = v.getBottom(); + if (v instanceof IMeasurablePagerTitleView) { + IMeasurablePagerTitleView view = (IMeasurablePagerTitleView) v; + data.mContentLeft = view.getContentLeft(); + data.mContentTop = view.getContentTop(); + data.mContentRight = view.getContentRight(); + data.mContentBottom = view.getContentBottom(); + } else { + data.mContentLeft = data.mLeft; + data.mContentTop = data.mTop; + data.mContentRight = data.mRight; + data.mContentBottom = data.mBottom; + } + } + mPositionDataList.add(data); + } + } + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + if (mAdapter != null) { + + mNavigatorHelper.onPageScrolled(position, positionOffset, positionOffsetPixels); + if (mIndicator != null) { + mIndicator.onPageScrolled(position, positionOffset, positionOffsetPixels); + } + + // 手指跟随滚动 + if (mScrollView != null && mPositionDataList.size() > 0 && position >= 0 && position < mPositionDataList.size()) { + if (mFollowTouch) { + int currentPosition = Math.min(mPositionDataList.size() - 1, position); + int nextPosition = Math.min(mPositionDataList.size() - 1, position + 1); + PositionData current = mPositionDataList.get(currentPosition); + PositionData next = mPositionDataList.get(nextPosition); + float scrollTo = current.horizontalCenter() - mScrollView.getWidth() * mScrollPivotX; + float nextScrollTo = next.horizontalCenter() - mScrollView.getWidth() * mScrollPivotX; + mScrollView.scrollTo((int) (scrollTo + (nextScrollTo - scrollTo) * positionOffset), 0); + } else if (!mEnablePivotScroll) { + // TODO 实现待选中项完全显示出来 + } + } + } + } + + public float getScrollPivotX() { + return mScrollPivotX; + } + + public void setScrollPivotX(float scrollPivotX) { + mScrollPivotX = scrollPivotX; + } + + @Override + public void onPageSelected(int position) { + if (mAdapter != null) { + mNavigatorHelper.onPageSelected(position); + if (mIndicator != null) { + mIndicator.onPageSelected(position); + } + } + } + + @Override + public void onPageScrollStateChanged(int state) { + if (mAdapter != null) { + mNavigatorHelper.onPageScrollStateChanged(state); + if (mIndicator != null) { + mIndicator.onPageScrollStateChanged(state); + } + } + } + + @Override + public void onAttachToMagicIndicator() { + init(); // 将初始化延迟到这里 + } + + @Override + public void onDetachFromMagicIndicator() { + } + + public IPagerIndicator getPagerIndicator() { + return mIndicator; + } + + public boolean isEnablePivotScroll() { + return mEnablePivotScroll; + } + + public void setEnablePivotScroll(boolean is) { + mEnablePivotScroll = is; + } + + @Override + public void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight) { + if (mTitleContainer == null) { + return; + } + View v = mTitleContainer.getChildAt(index); + if (v instanceof IPagerTitleView) { + ((IPagerTitleView) v).onEnter(index, totalCount, enterPercent, leftToRight); + } + } + + @Override + public void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight) { + if (mTitleContainer == null) { + return; + } + View v = mTitleContainer.getChildAt(index); + if (v instanceof IPagerTitleView) { + ((IPagerTitleView) v).onLeave(index, totalCount, leavePercent, leftToRight); + } + } + + public boolean isSmoothScroll() { + return mSmoothScroll; + } + + public void setSmoothScroll(boolean smoothScroll) { + mSmoothScroll = smoothScroll; + } + + public boolean isFollowTouch() { + return mFollowTouch; + } + + public void setFollowTouch(boolean followTouch) { + mFollowTouch = followTouch; + } + + public boolean isSkimOver() { + return mSkimOver; + } + + public void setSkimOver(boolean skimOver) { + mSkimOver = skimOver; + mNavigatorHelper.setSkimOver(skimOver); + } + + @Override + public void onSelected(int index, int totalCount) { + if (mTitleContainer == null) { + return; + } + View v = mTitleContainer.getChildAt(index); + if (v instanceof IPagerTitleView) { + ((IPagerTitleView) v).onSelected(index, totalCount); + } + + // 外部监听 + if (mNavigatorSelectedListener != null) + mNavigatorSelectedListener.navigatorSelected(index); + + if (!mAdjustMode && !mFollowTouch && mScrollView != null && mPositionDataList.size() > 0) { + int currentIndex = Math.min(mPositionDataList.size() - 1, index); + PositionData current = mPositionDataList.get(currentIndex); + if (mEnablePivotScroll) { + float scrollTo = current.horizontalCenter() - mScrollView.getWidth() * mScrollPivotX; + if (mSmoothScroll) { + mScrollView.smoothScrollTo((int) (scrollTo), 0); + } else { + mScrollView.scrollTo((int) (scrollTo), 0); + } + } else { + // 如果当前项被部分遮挡,则滚动显示完全 + if (mScrollView.getScrollX() > current.mLeft) { + if (mSmoothScroll) { + mScrollView.smoothScrollTo(current.mLeft, 0); + } else { + mScrollView.scrollTo(current.mLeft, 0); + } + } else if (mScrollView.getScrollX() + getWidth() < current.mRight) { + if (mSmoothScroll) { + mScrollView.smoothScrollTo(current.mRight - getWidth(), 0); + } else { + mScrollView.scrollTo(current.mRight - getWidth(), 0); + } + } + } + } + } + + @Override + public void onDeselected(int index, int totalCount) { + if (mTitleContainer == null) { + return; + } + View v = mTitleContainer.getChildAt(index); + if (v instanceof IPagerTitleView) { + ((IPagerTitleView) v).onDeselected(index, totalCount); + } + } + + public IPagerTitleView getPagerTitleView(int index) { + if (mTitleContainer == null) { + return null; + } + return (IPagerTitleView) mTitleContainer.getChildAt(index); + } + + public LinearLayout getTitleContainer() { + return mTitleContainer; + } + + public int getRightPadding() { + return mRightPadding; + } + + public void setRightPadding(int rightPadding) { + mRightPadding = rightPadding; + } + + public int getLeftPadding() { + return mLeftPadding; + } + + public void setLeftPadding(int leftPadding) { + mLeftPadding = leftPadding; + } + + public boolean isIndicatorOnTop() { + return mIndicatorOnTop; + } + + public void setIndicatorOnTop(boolean indicatorOnTop) { + mIndicatorOnTop = indicatorOnTop; + } + + public boolean isReselectWhenLayout() { + return mReselectWhenLayout; + } + + public void setReselectWhenLayout(boolean reselectWhenLayout) { + mReselectWhenLayout = reselectWhenLayout; + } + + public int getTitleMargin() { + return titleMargin; + } + + public void setTitleMargin(int titleMargin) { + this.titleMargin = titleMargin; + } + + public void setmNavigatorSelectedListener(NavigatorSelectedListener navigatorSelectedListener) { + this.mNavigatorSelectedListener = navigatorSelectedListener; + } + + public void setFadingEdge() { + if (mScrollView == null) { + return; + } + if (fadingLength <= 0) { + return; + } + mScrollView.setHorizontalFadingEdgeEnabled(true); + mScrollView.setFadingEdgeLength(fadingLength); + } + + @Override + public int getCurrentIndex() { + return mNavigatorHelper.getCurrentIndex(); + } + + public interface NavigatorSelectedListener { + void navigatorSelected(int position); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/abs/CommonNavigatorAdapter.java b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/abs/CommonNavigatorAdapter.java new file mode 100644 index 0000000..258b310 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/abs/CommonNavigatorAdapter.java @@ -0,0 +1,41 @@ +package com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs; + +import android.content.Context; +import android.database.DataSetObservable; +import android.database.DataSetObserver; + +/** + * CommonNavigator适配器,通过它可轻松切换不同的指示器样式 + * 博客: http://hackware.lucode.net + * Created by hackware on 2016/6/26. + */ +public abstract class CommonNavigatorAdapter { + + private final DataSetObservable mDataSetObservable = new DataSetObservable(); + + public abstract int getCount(); + + public abstract IPagerTitleView getTitleView(Context context, int index); + + public abstract IPagerIndicator getIndicator(Context context); + + public float getTitleWeight(Context context, int index) { + return 1; + } + + public final void registerDataSetObserver(DataSetObserver observer) { + mDataSetObservable.registerObserver(observer); + } + + public final void unregisterDataSetObserver(DataSetObserver observer) { + mDataSetObservable.unregisterObserver(observer); + } + + public final void notifyDataSetChanged() { + mDataSetObservable.notifyChanged(); + } + + public final void notifyDataSetInvalidated() { + mDataSetObservable.notifyInvalidated(); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/abs/IMeasurablePagerTitleView.java b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/abs/IMeasurablePagerTitleView.java new file mode 100644 index 0000000..6d70a59 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/abs/IMeasurablePagerTitleView.java @@ -0,0 +1,17 @@ +package com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs; + + +/** + * 可测量内容区域的指示器标题 + * 博客: http://hackware.lucode.net + * Created by hackware on 2016/6/26. + */ +public interface IMeasurablePagerTitleView extends IPagerTitleView { + int getContentLeft(); + + int getContentTop(); + + int getContentRight(); + + int getContentBottom(); +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/abs/IPagerIndicator.java b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/abs/IPagerIndicator.java new file mode 100644 index 0000000..1b7b39d --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/abs/IPagerIndicator.java @@ -0,0 +1,21 @@ +package com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs; + + +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.model.PositionData; + +import java.util.List; + +/** + * 抽象的viewpager指示器,适用于CommonNavigator + * 博客: http://hackware.lucode.net + * Created by hackware on 2016/6/26. + */ +public interface IPagerIndicator { + void onPageScrolled(int position, float positionOffset, int positionOffsetPixels); + + void onPageSelected(int position); + + void onPageScrollStateChanged(int state); + + void onPositionDataProvide(List dataList); +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/abs/IPagerTitleView.java b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/abs/IPagerTitleView.java new file mode 100644 index 0000000..813a950 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/abs/IPagerTitleView.java @@ -0,0 +1,34 @@ +package com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs; + +/** + * 抽象的指示器标题,适用于CommonNavigator + * 博客: http://hackware.lucode.net + * Created by hackware on 2016/6/26. + */ +public interface IPagerTitleView { + /** + * 被选中 + */ + void onSelected(int index, int totalCount); + + /** + * 未被选中 + */ + void onDeselected(int index, int totalCount); + + /** + * 离开 + * + * @param leavePercent 离开的百分比, 0.0f - 1.0f + * @param leftToRight 从左至右离开 + */ + void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight); + + /** + * 进入 + * + * @param enterPercent 进入的百分比, 0.0f - 1.0f + * @param leftToRight 从左至右离开 + */ + void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight); +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/indicators/BezierPagerIndicator.java b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/indicators/BezierPagerIndicator.java new file mode 100644 index 0000000..250a108 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/indicators/BezierPagerIndicator.java @@ -0,0 +1,165 @@ +package com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.indicators; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.view.View; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.Interpolator; + +import com.chwl.app.ui.widget.magicindicator.FragmentContainerHelper; +import com.chwl.app.ui.widget.magicindicator.buildins.ArgbEvaluatorHolder; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.model.PositionData; + +import java.util.Arrays; +import java.util.List; + +/** + * 贝塞尔曲线ViewPager指示器,带颜色渐变 + * 博客: http://hackware.lucode.net + * Created by hackware on 2016/6/26. + */ +public class BezierPagerIndicator extends View implements IPagerIndicator { + private List mPositionDataList; + + private float mLeftCircleRadius; + private float mLeftCircleX; + private float mRightCircleRadius; + private float mRightCircleX; + + private float mYOffset; + private float mMaxCircleRadius; + private float mMinCircleRadius; + + private Paint mPaint; + private Path mPath = new Path(); + + private List mColors; + private Interpolator mStartInterpolator = new AccelerateInterpolator(); + private Interpolator mEndInterpolator = new DecelerateInterpolator(); + + public BezierPagerIndicator(Context context) { + super(context); + init(context); + } + + private void init(Context context) { + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mPaint.setStyle(Paint.Style.FILL); + mMaxCircleRadius = UIUtil.dip2px(context, 3.5); + mMinCircleRadius = UIUtil.dip2px(context, 2); + mYOffset = UIUtil.dip2px(context, 1.5); + } + + @Override + protected void onDraw(Canvas canvas) { + canvas.drawCircle(mLeftCircleX, getHeight() - mYOffset - mMaxCircleRadius, mLeftCircleRadius, mPaint); + canvas.drawCircle(mRightCircleX, getHeight() - mYOffset - mMaxCircleRadius, mRightCircleRadius, mPaint); + drawBezierCurve(canvas); + } + + /** + * 绘制贝塞尔曲线 + * + * @param canvas + */ + private void drawBezierCurve(Canvas canvas) { + mPath.reset(); + float y = getHeight() - mYOffset - mMaxCircleRadius; + mPath.moveTo(mRightCircleX, y); + mPath.lineTo(mRightCircleX, y - mRightCircleRadius); + mPath.quadTo(mRightCircleX + (mLeftCircleX - mRightCircleX) / 2.0f, y, mLeftCircleX, y - mLeftCircleRadius); + mPath.lineTo(mLeftCircleX, y + mLeftCircleRadius); + mPath.quadTo(mRightCircleX + (mLeftCircleX - mRightCircleX) / 2.0f, y, mRightCircleX, y + mRightCircleRadius); + mPath.close(); // 闭合 + canvas.drawPath(mPath, mPaint); + } + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + if (mPositionDataList == null || mPositionDataList.isEmpty()) { + return; + } + + // 计算颜色 + if (mColors != null && mColors.size() > 0) { + int currentColor = mColors.get(Math.abs(position) % mColors.size()); + int nextColor = mColors.get(Math.abs(position + 1) % mColors.size()); + int color = ArgbEvaluatorHolder.eval(positionOffset, currentColor, nextColor); + mPaint.setColor(color); + } + + // 计算锚点位置 + PositionData current = FragmentContainerHelper.getImitativePositionData(mPositionDataList, position); + PositionData next = FragmentContainerHelper.getImitativePositionData(mPositionDataList, position + 1); + + float leftX = current.mLeft + (current.mRight - current.mLeft) / 2; + float rightX = next.mLeft + (next.mRight - next.mLeft) / 2; + + mLeftCircleX = leftX + (rightX - leftX) * mStartInterpolator.getInterpolation(positionOffset); + mRightCircleX = leftX + (rightX - leftX) * mEndInterpolator.getInterpolation(positionOffset); + mLeftCircleRadius = mMaxCircleRadius + (mMinCircleRadius - mMaxCircleRadius) * mEndInterpolator.getInterpolation(positionOffset); + mRightCircleRadius = mMinCircleRadius + (mMaxCircleRadius - mMinCircleRadius) * mStartInterpolator.getInterpolation(positionOffset); + + invalidate(); + } + + @Override + public void onPageSelected(int position) { + } + + @Override + public void onPageScrollStateChanged(int state) { + } + + @Override + public void onPositionDataProvide(List dataList) { + mPositionDataList = dataList; + } + + public float getMaxCircleRadius() { + return mMaxCircleRadius; + } + + public void setMaxCircleRadius(float maxCircleRadius) { + mMaxCircleRadius = maxCircleRadius; + } + + public float getMinCircleRadius() { + return mMinCircleRadius; + } + + public void setMinCircleRadius(float minCircleRadius) { + mMinCircleRadius = minCircleRadius; + } + + public float getYOffset() { + return mYOffset; + } + + public void setYOffset(float yOffset) { + mYOffset = yOffset; + } + + public void setColors(Integer... colors) { + mColors = Arrays.asList(colors); + } + + public void setStartInterpolator(Interpolator startInterpolator) { + mStartInterpolator = startInterpolator; + if (mStartInterpolator == null) { + mStartInterpolator = new AccelerateInterpolator(); + } + } + + public void setEndInterpolator(Interpolator endInterpolator) { + mEndInterpolator = endInterpolator; + if (mEndInterpolator == null) { + mEndInterpolator = new DecelerateInterpolator(); + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/indicators/GradientLinePagerIndicator.java b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/indicators/GradientLinePagerIndicator.java new file mode 100644 index 0000000..c08b079 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/indicators/GradientLinePagerIndicator.java @@ -0,0 +1,23 @@ +package com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.indicators; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.LinearGradient; + +/** + * 实现渐变指示器帮助类 + */ +public class GradientLinePagerIndicator extends LinePagerIndicator { + + public GradientLinePagerIndicator(Context context) { + super(context); + } + + @Override + protected void onDraw(Canvas canvas) { + LinearGradient lg = new LinearGradient(getLineRect().left, getLineRect().top, getLineRect().right, getLineRect().bottom, new int[]{0xFF70E9FF, 0xFFAE87FF,0xFFFF5CE1}, null, LinearGradient.TileMode.CLAMP); + getPaint().setShader(lg); + canvas.drawOval(getLineRect(), getPaint()); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/indicators/GradientLineRoundPagerIndicator.java b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/indicators/GradientLineRoundPagerIndicator.java new file mode 100644 index 0000000..cd99eba --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/indicators/GradientLineRoundPagerIndicator.java @@ -0,0 +1,28 @@ +package com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.indicators; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.LinearGradient; + +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; + +/** + * 实现渐变指示器帮助类 + */ +public class GradientLineRoundPagerIndicator extends LinePagerIndicator { + + private Context mContext; + + public GradientLineRoundPagerIndicator(Context context) { + super(context); + mContext = context; + } + + @Override + protected void onDraw(Canvas canvas) { + LinearGradient lg = new LinearGradient(getLineRect().left, getLineRect().top, getLineRect().right, getLineRect().bottom, new int[]{0xFF70E9FF, 0xFFAE87FF,0xFFFF5CE1}, null, LinearGradient.TileMode.CLAMP); + getPaint().setShader(lg); + canvas.drawRoundRect(getLineRect(), UIUtil.dip2px(mContext, 2), UIUtil.dip2px(mContext, 2), getPaint()); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/indicators/LinePagerIndicator.java b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/indicators/LinePagerIndicator.java new file mode 100644 index 0000000..77e623a --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/indicators/LinePagerIndicator.java @@ -0,0 +1,220 @@ +package com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.indicators; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.RectF; +import android.view.View; +import android.view.animation.Interpolator; +import android.view.animation.LinearInterpolator; + +import com.chwl.app.ui.widget.magicindicator.FragmentContainerHelper; +import com.chwl.app.ui.widget.magicindicator.buildins.ArgbEvaluatorHolder; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.model.PositionData; + +import java.util.Arrays; +import java.util.List; + +/** + * 直线viewpager指示器,带颜色渐变 + * 博客: http://hackware.lucode.net + * Created by hackware on 2016/6/26. + */ +public class LinePagerIndicator extends View implements IPagerIndicator { + public static final int MODE_MATCH_EDGE = 0; // 直线宽度 == title宽度 - 2 * mXOffset + public static final int MODE_WRAP_CONTENT = 1; // 直线宽度 == title内容宽度 - 2 * mXOffset + public static final int MODE_EXACTLY = 2; // 直线宽度 == mLineWidth + + private int mMode; // 默认为MODE_MATCH_EDGE模式 + + // 控制动画 + private Interpolator mStartInterpolator = new LinearInterpolator(); + private Interpolator mEndInterpolator = new LinearInterpolator(); + + private float mYOffset; // 相对于底部的偏移量,如果你想让直线位于title上方,设置它即可 + private float mLineHeight; + private float mXOffset; + private float mLineWidth; + private float mRoundRadius; + + private Paint mPaint; + private List mPositionDataList; + private List mColors; + + private RectF mLineRect = new RectF(); + + public LinePagerIndicator(Context context) { + super(context); + init(context); + } + + private void init(Context context) { + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mPaint.setStyle(Paint.Style.FILL); + mLineHeight = UIUtil.dip2px(context, 3); + mLineWidth = UIUtil.dip2px(context, 15); + } + + @Override + protected void onDraw(Canvas canvas) { + canvas.drawRoundRect(mLineRect, mRoundRadius, mRoundRadius, mPaint); + } + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + if (mPositionDataList == null || mPositionDataList.isEmpty()) { + return; + } + + // 计算颜色 + if (mColors != null && mColors.size() > 0) { + int currentColor = mColors.get(Math.abs(position) % mColors.size()); + int nextColor = mColors.get(Math.abs(position + 1) % mColors.size()); + int color = ArgbEvaluatorHolder.eval(positionOffset, currentColor, nextColor); + mPaint.setColor(color); + } + + // 计算锚点位置 + PositionData current = FragmentContainerHelper.getImitativePositionData(mPositionDataList, position); + PositionData next = FragmentContainerHelper.getImitativePositionData(mPositionDataList, position + 1); + + float leftX; + float nextLeftX; + float rightX; + float nextRightX; + if (mMode == MODE_MATCH_EDGE) { + leftX = current.mLeft + mXOffset; + nextLeftX = next.mLeft + mXOffset; + rightX = current.mRight - mXOffset; + nextRightX = next.mRight - mXOffset; + } else if (mMode == MODE_WRAP_CONTENT) { + leftX = current.mContentLeft + mXOffset; + nextLeftX = next.mContentLeft + mXOffset; + rightX = current.mContentRight - mXOffset; + nextRightX = next.mContentRight - mXOffset; + } else { // MODE_EXACTLY + leftX = current.mLeft + (current.width() - mLineWidth) / 2; + nextLeftX = next.mLeft + (next.width() - mLineWidth) / 2; + rightX = current.mLeft + (current.width() + mLineWidth) / 2; + nextRightX = next.mLeft + (next.width() + mLineWidth) / 2; + } + + mLineRect.left = leftX + (nextLeftX - leftX) * mStartInterpolator.getInterpolation(positionOffset); + mLineRect.right = rightX + (nextRightX - rightX) * mEndInterpolator.getInterpolation(positionOffset); + mLineRect.top = getHeight() - mLineHeight - mYOffset; + mLineRect.bottom = getHeight() - mYOffset; + + invalidate(); + } + + @Override + public void onPageSelected(int position) { + onPageScrolled(position,0,0); + } + + @Override + public void onPageScrollStateChanged(int state) { + } + + @Override + public void onPositionDataProvide(List dataList) { + mPositionDataList = dataList; + } + + public float getYOffset() { + return mYOffset; + } + + public void setYOffset(float yOffset) { + mYOffset = yOffset; + } + + public float getXOffset() { + return mXOffset; + } + + public void setXOffset(float xOffset) { + mXOffset = xOffset; + } + + public float getLineHeight() { + return mLineHeight; + } + + public void setLineHeight(float lineHeight) { + mLineHeight = lineHeight; + } + + public float getLineWidth() { + return mLineWidth; + } + + public void setLineWidth(float lineWidth) { + mLineWidth = lineWidth; + } + + public float getRoundRadius() { + return mRoundRadius; + } + + public void setRoundRadius(float roundRadius) { + mRoundRadius = roundRadius; + } + + public int getMode() { + return mMode; + } + + public void setMode(int mode) { + if (mode == MODE_EXACTLY || mode == MODE_MATCH_EDGE || mode == MODE_WRAP_CONTENT) { + mMode = mode; + } else { + throw new IllegalArgumentException("mode " + mode + " not supported."); + } + } + + public Paint getPaint() { + return mPaint; + } + + /** + * 返回底部画线的RectF mLineRect。 + * + * @return + */ + public RectF getLineRect() { + return mLineRect; + } + + public List getColors() { + return mColors; + } + + public void setColors(Integer... colors) { + mColors = Arrays.asList(colors); + } + + public Interpolator getStartInterpolator() { + return mStartInterpolator; + } + + public void setStartInterpolator(Interpolator startInterpolator) { + mStartInterpolator = startInterpolator; + if (mStartInterpolator == null) { + mStartInterpolator = new LinearInterpolator(); + } + } + + public Interpolator getEndInterpolator() { + return mEndInterpolator; + } + + public void setEndInterpolator(Interpolator endInterpolator) { + mEndInterpolator = endInterpolator; + if (mEndInterpolator == null) { + mEndInterpolator = new LinearInterpolator(); + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/indicators/TestPagerIndicator.java b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/indicators/TestPagerIndicator.java new file mode 100644 index 0000000..086ba1e --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/indicators/TestPagerIndicator.java @@ -0,0 +1,102 @@ +package com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.indicators; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.RectF; +import android.view.View; + +import com.chwl.app.ui.widget.magicindicator.FragmentContainerHelper; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.model.PositionData; + +import java.util.List; + + +/** + * 用于测试的指示器,可用来检测自定义的IMeasurablePagerTitleView是否正确测量内容区域 + * 博客: http://hackware.lucode.net + * Created by hackware on 2016/6/26. + */ +public class TestPagerIndicator extends View implements IPagerIndicator { + private Paint mPaint; + private int mOutRectColor; + private int mInnerRectColor; + private RectF mOutRect = new RectF(); + private RectF mInnerRect = new RectF(); + + private List mPositionDataList; + + public TestPagerIndicator(Context context) { + super(context); + init(context); + } + + private void init(Context context) { + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mPaint.setStyle(Paint.Style.STROKE); + mOutRectColor = Color.RED; + mInnerRectColor = Color.GREEN; + } + + @Override + protected void onDraw(Canvas canvas) { + mPaint.setColor(mOutRectColor); + canvas.drawRect(mOutRect, mPaint); + mPaint.setColor(mInnerRectColor); + canvas.drawRect(mInnerRect, mPaint); + } + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + if (mPositionDataList == null || mPositionDataList.isEmpty()) { + return; + } + + // 计算锚点位置 + PositionData current = FragmentContainerHelper.getImitativePositionData(mPositionDataList, position); + PositionData next = FragmentContainerHelper.getImitativePositionData(mPositionDataList, position + 1); + + mOutRect.left = current.mLeft + (next.mLeft - current.mLeft) * positionOffset; + mOutRect.top = current.mTop + (next.mTop - current.mTop) * positionOffset; + mOutRect.right = current.mRight + (next.mRight - current.mRight) * positionOffset; + mOutRect.bottom = current.mBottom + (next.mBottom - current.mBottom) * positionOffset; + + mInnerRect.left = current.mContentLeft + (next.mContentLeft - current.mContentLeft) * positionOffset; + mInnerRect.top = current.mContentTop + (next.mContentTop - current.mContentTop) * positionOffset; + mInnerRect.right = current.mContentRight + (next.mContentRight - current.mContentRight) * positionOffset; + mInnerRect.bottom = current.mContentBottom + (next.mContentBottom - current.mContentBottom) * positionOffset; + + invalidate(); + } + + @Override + public void onPageSelected(int position) { + } + + @Override + public void onPageScrollStateChanged(int state) { + } + + @Override + public void onPositionDataProvide(List dataList) { + mPositionDataList = dataList; + } + + public int getOutRectColor() { + return mOutRectColor; + } + + public void setOutRectColor(int outRectColor) { + mOutRectColor = outRectColor; + } + + public int getInnerRectColor() { + return mInnerRectColor; + } + + public void setInnerRectColor(int innerRectColor) { + mInnerRectColor = innerRectColor; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/indicators/TriangularPagerIndicator.java b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/indicators/TriangularPagerIndicator.java new file mode 100644 index 0000000..a9d603a --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/indicators/TriangularPagerIndicator.java @@ -0,0 +1,161 @@ +package com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.indicators; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.view.View; +import android.view.animation.Interpolator; +import android.view.animation.LinearInterpolator; + +import com.chwl.app.ui.widget.magicindicator.FragmentContainerHelper; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.model.PositionData; + +import java.util.List; + +/** + * 带有小尖角的直线指示器 + * 博客: http://hackware.lucode.net + * Created by hackware on 2016/6/26. + */ +public class TriangularPagerIndicator extends View implements IPagerIndicator { + private List mPositionDataList; + private Paint mPaint; + private int mLineHeight; + private int mLineColor; + private int mTriangleHeight; + private int mTriangleWidth; + private boolean mReverse; + private float mYOffset; + + private Path mPath = new Path(); + private Interpolator mStartInterpolator = new LinearInterpolator(); + private float mAnchorX; + + public TriangularPagerIndicator(Context context) { + super(context); + init(context); + } + + private void init(Context context) { + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mPaint.setStyle(Paint.Style.FILL); + mLineHeight = UIUtil.dip2px(context, 3); + mTriangleWidth = UIUtil.dip2px(context, 14); + mTriangleHeight = UIUtil.dip2px(context, 8); + } + + @Override + protected void onDraw(Canvas canvas) { + mPaint.setColor(mLineColor); + if (mReverse) { + canvas.drawRect(0, getHeight() - mYOffset - mTriangleHeight, getWidth(), getHeight() - mYOffset - mTriangleHeight + mLineHeight, mPaint); + } else { + canvas.drawRect(0, getHeight() - mLineHeight - mYOffset, getWidth(), getHeight() - mYOffset, mPaint); + } + mPath.reset(); + if (mReverse) { + mPath.moveTo(mAnchorX - mTriangleWidth / 2, getHeight() - mYOffset - mTriangleHeight); + mPath.lineTo(mAnchorX, getHeight() - mYOffset); + mPath.lineTo(mAnchorX + mTriangleWidth / 2, getHeight() - mYOffset - mTriangleHeight); + } else { + mPath.moveTo(mAnchorX - mTriangleWidth / 2, getHeight() - mYOffset); + mPath.lineTo(mAnchorX, getHeight() - mTriangleHeight - mYOffset); + mPath.lineTo(mAnchorX + mTriangleWidth / 2, getHeight() - mYOffset); + } + mPath.close(); + canvas.drawPath(mPath, mPaint); + } + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + if (mPositionDataList == null || mPositionDataList.isEmpty()) { + return; + } + + // 计算锚点位置 + PositionData current = FragmentContainerHelper.getImitativePositionData(mPositionDataList, position); + PositionData next = FragmentContainerHelper.getImitativePositionData(mPositionDataList, position + 1); + + float leftX = current.mLeft + (current.mRight - current.mLeft) / 2; + float rightX = next.mLeft + (next.mRight - next.mLeft) / 2; + + mAnchorX = leftX + (rightX - leftX) * mStartInterpolator.getInterpolation(positionOffset); + + invalidate(); + } + + @Override + public void onPageSelected(int position) { + } + + @Override + public void onPageScrollStateChanged(int state) { + } + + @Override + public void onPositionDataProvide(List dataList) { + mPositionDataList = dataList; + } + + public int getLineHeight() { + return mLineHeight; + } + + public void setLineHeight(int lineHeight) { + mLineHeight = lineHeight; + } + + public int getLineColor() { + return mLineColor; + } + + public void setLineColor(int lineColor) { + mLineColor = lineColor; + } + + public int getTriangleHeight() { + return mTriangleHeight; + } + + public void setTriangleHeight(int triangleHeight) { + mTriangleHeight = triangleHeight; + } + + public int getTriangleWidth() { + return mTriangleWidth; + } + + public void setTriangleWidth(int triangleWidth) { + mTriangleWidth = triangleWidth; + } + + public Interpolator getStartInterpolator() { + return mStartInterpolator; + } + + public void setStartInterpolator(Interpolator startInterpolator) { + mStartInterpolator = startInterpolator; + if (mStartInterpolator == null) { + mStartInterpolator = new LinearInterpolator(); + } + } + + public boolean isReverse() { + return mReverse; + } + + public void setReverse(boolean reverse) { + mReverse = reverse; + } + + public float getYOffset() { + return mYOffset; + } + + public void setYOffset(float yOffset) { + mYOffset = yOffset; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/indicators/WrapPagerIndicator.kt b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/indicators/WrapPagerIndicator.kt new file mode 100644 index 0000000..ec82602 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/indicators/WrapPagerIndicator.kt @@ -0,0 +1,121 @@ +package com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.indicators + +import android.content.Context +import android.graphics.* +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerIndicator +import android.view.animation.LinearInterpolator +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.model.PositionData +import android.view.View +import android.view.animation.Interpolator +import com.chwl.app.R +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil +import com.chwl.app.ui.widget.magicindicator.FragmentContainerHelper + +/** + * 包裹住内容区域的指示器,类似天天快报的切换效果,需要和IMeasurablePagerTitleView配合使用 + * 博客: http://hackware.lucode.net + * Created by hackware on 2016/6/26. + */ +class WrapPagerIndicator(context: Context) : View(context), IPagerIndicator { + private val mGradientColors = intArrayOf(-0xec1d0b, -0x339901) + + //渐变位置 + private val mGradientPosition = floatArrayOf(0f, 1f) + var verticalPadding = 0 + var horizontalPadding = 0 + var fillColor = 0 + private var mRoundRadius = 0f + private var mStartInterpolator: Interpolator? = LinearInterpolator() + private var mEndInterpolator: Interpolator? = LinearInterpolator() + private var mPositionDataList: List? = null + var paint: Paint? = null + private set + private val mRect = RectF() + private var mRoundRadiusSet = false + + init { + init(context) + } + + private fun init(context: Context) { + paint = Paint(Paint.ANTI_ALIAS_FLAG) + paint!!.style = Paint.Style.FILL + horizontalPadding = UIUtil.dip2px(context, 10.0) + verticalPadding = UIUtil.dip2px(context, 2.0) + } + + private val mIndicatorBmp: Bitmap by lazy { + BitmapFactory.decodeResource( + context.resources, + R.drawable.bg_home_tab + ) + } + + override fun onDraw(canvas: Canvas) { + //mPaint.setColor(mFillColor); + canvas.drawBitmap(mIndicatorBmp, null, mRect, paint!!) +// canvas.drawRoundRect(mRect, mRoundRadius, mRoundRadius, paint!!) + } + + override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) { + if (mPositionDataList == null || mPositionDataList!!.isEmpty()) { + return + } + + // 计算锚点位置 + val current = FragmentContainerHelper.getImitativePositionData(mPositionDataList, position) + val next = FragmentContainerHelper.getImitativePositionData(mPositionDataList, position + 1) + mRect.left = + current.mContentLeft - horizontalPadding + (next.mContentLeft - current.mContentLeft) * mEndInterpolator!!.getInterpolation( + positionOffset + ) + mRect.top = (current.mContentTop - verticalPadding).toFloat() + mRect.right = + current.mContentRight + horizontalPadding + (next.mContentRight - current.mContentRight) * mStartInterpolator!!.getInterpolation( + positionOffset + ) + mRect.bottom = (current.mContentBottom + verticalPadding).toFloat() + paint!!.shader = LinearGradient( + mRect.left, + mRect.top, + mRect.right, + mRect.bottom, + mGradientColors, + mGradientPosition, + Shader.TileMode.CLAMP + ) + if (!mRoundRadiusSet) { + mRoundRadius = mRect.height() / 2 + } + invalidate() + } + + override fun onPageSelected(position: Int) {} + override fun onPageScrollStateChanged(state: Int) {} + override fun onPositionDataProvide(dataList: List) { + mPositionDataList = dataList + } + + var roundRadius: Float + get() = mRoundRadius + set(roundRadius) { + mRoundRadius = roundRadius + mRoundRadiusSet = true + } + var startInterpolator: Interpolator? + get() = mStartInterpolator + set(startInterpolator) { + mStartInterpolator = startInterpolator + if (mStartInterpolator == null) { + mStartInterpolator = LinearInterpolator() + } + } + var endInterpolator: Interpolator? + get() = mEndInterpolator + set(endInterpolator) { + mEndInterpolator = endInterpolator + if (mEndInterpolator == null) { + mEndInterpolator = LinearInterpolator() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/model/PositionData.java b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/model/PositionData.java new file mode 100644 index 0000000..2a7deef --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/model/PositionData.java @@ -0,0 +1,41 @@ +package com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.model; + +/** + * 保存指示器标题的坐标 + * 博客: http://hackware.lucode.net + * Created by hackware on 2016/6/26. + */ +public class PositionData { + public int mLeft; + public int mTop; + public int mRight; + public int mBottom; + public int mContentLeft; + public int mContentTop; + public int mContentRight; + public int mContentBottom; + + public int width() { + return mRight - mLeft; + } + + public int height() { + return mBottom - mTop; + } + + public int contentWidth() { + return mContentRight - mContentLeft; + } + + public int contentHeight() { + return mContentBottom - mContentTop; + } + + public int horizontalCenter() { + return mLeft + width() / 2; + } + + public int verticalCenter() { + return mTop + height() / 2; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/titles/ClipPagerTitleView.java b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/titles/ClipPagerTitleView.java new file mode 100644 index 0000000..7f06da0 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/titles/ClipPagerTitleView.java @@ -0,0 +1,192 @@ +package com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.titles; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.view.View; + +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IMeasurablePagerTitleView; + + +/** + * 类似今日头条切换效果的指示器标题 + * 博客: http://hackware.lucode.net + * Created by hackware on 2016/6/26. + */ +public class ClipPagerTitleView extends View implements IMeasurablePagerTitleView { + private String mText; + private int mTextColor; + private int mClipColor; + private boolean mLeftToRight; + private float mClipPercent; + + private Paint mPaint; + private Rect mTextBounds = new Rect(); + + public ClipPagerTitleView(Context context) { + super(context); + init(context); + } + + private void init(Context context) { + int textSize = UIUtil.dip2px(context, 16); + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mPaint.setTextSize(textSize); + int padding = UIUtil.dip2px(context, 10); + setPadding(padding, 0, padding, 0); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + measureTextBounds(); + setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec)); + } + + private int measureWidth(int widthMeasureSpec) { + int mode = MeasureSpec.getMode(widthMeasureSpec); + int size = MeasureSpec.getSize(widthMeasureSpec); + int result = size; + switch (mode) { + case MeasureSpec.AT_MOST: + int width = mTextBounds.width() + getPaddingLeft() + getPaddingRight(); + result = Math.min(width, size); + break; + case MeasureSpec.UNSPECIFIED: + result = mTextBounds.width() + getPaddingLeft() + getPaddingRight(); + break; + default: + break; + } + return result; + } + + private int measureHeight(int heightMeasureSpec) { + int mode = MeasureSpec.getMode(heightMeasureSpec); + int size = MeasureSpec.getSize(heightMeasureSpec); + int result = size; + switch (mode) { + case MeasureSpec.AT_MOST: + int height = mTextBounds.height() + getPaddingTop() + getPaddingBottom(); + result = Math.min(height, size); + break; + case MeasureSpec.UNSPECIFIED: + result = mTextBounds.height() + getPaddingTop() + getPaddingBottom(); + break; + default: + break; + } + return result; + } + + @Override + protected void onDraw(Canvas canvas) { + int x = (getWidth() - mTextBounds.width()) / 2; + Paint.FontMetrics fontMetrics = mPaint.getFontMetrics(); + int y = (int) ((getHeight() - fontMetrics.bottom - fontMetrics.top) / 2); + + // 画底层 + mPaint.setColor(mTextColor); + canvas.drawText(mText, x, y, mPaint); + + // 画clip层 + canvas.save(); + if (mLeftToRight) { + canvas.clipRect(0, 0, getWidth() * mClipPercent, getHeight()); + } else { + canvas.clipRect(getWidth() * (1 - mClipPercent), 0, getWidth(), getHeight()); + } + mPaint.setColor(mClipColor); + canvas.drawText(mText, x, y, mPaint); + canvas.restore(); + } + + @Override + public void onSelected(int index, int totalCount) { + } + + @Override + public void onDeselected(int index, int totalCount) { + } + + @Override + public void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight) { + mLeftToRight = !leftToRight; + mClipPercent = 1.0f - leavePercent; + invalidate(); + } + + @Override + public void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight) { + mLeftToRight = leftToRight; + mClipPercent = enterPercent; + invalidate(); + } + + private void measureTextBounds() { + mPaint.getTextBounds(mText, 0, mText == null ? 0 : mText.length(), mTextBounds); + } + + public String getText() { + return mText; + } + + public void setText(String text) { + mText = text; + requestLayout(); + } + + public float getTextSize() { + return mPaint.getTextSize(); + } + + public void setTextSize(float textSize) { + mPaint.setTextSize(textSize); + requestLayout(); + } + + public int getTextColor() { + return mTextColor; + } + + public void setTextColor(int textColor) { + mTextColor = textColor; + invalidate(); + } + + public int getClipColor() { + return mClipColor; + } + + public void setClipColor(int clipColor) { + mClipColor = clipColor; + invalidate(); + } + + @Override + public int getContentLeft() { + int contentWidth = mTextBounds.width(); + return getLeft() + getWidth() / 2 - contentWidth / 2; + } + + @Override + public int getContentTop() { + Paint.FontMetrics metrics = mPaint.getFontMetrics(); + float contentHeight = metrics.bottom - metrics.top; + return (int) (getHeight() / 2 - contentHeight / 2); + } + + @Override + public int getContentRight() { + int contentWidth = mTextBounds.width(); + return getLeft() + getWidth() / 2 + contentWidth / 2; + } + + @Override + public int getContentBottom() { + Paint.FontMetrics metrics = mPaint.getFontMetrics(); + float contentHeight = metrics.bottom - metrics.top; + return (int) (getHeight() / 2 + contentHeight / 2); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/titles/ColorTransitionPagerTitleView.java b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/titles/ColorTransitionPagerTitleView.java new file mode 100644 index 0000000..c303551 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/titles/ColorTransitionPagerTitleView.java @@ -0,0 +1,40 @@ +package com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.titles; + +import android.content.Context; + +import com.chwl.app.ui.widget.magicindicator.buildins.ArgbEvaluatorHolder; + + +/** + * 两种颜色过渡的指示器标题 + * 博客: http://hackware.lucode.net + * Created by hackware on 2016/6/26. + */ +public class ColorTransitionPagerTitleView extends SimplePagerTitleView { + + public ColorTransitionPagerTitleView(Context context) { + super(context); + } + + @Override + public void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight) { + int color = ArgbEvaluatorHolder.eval(leavePercent, mSelectedColor, mNormalColor); + setTextColor(color); + } + + @Override + public void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight) { + int color = ArgbEvaluatorHolder.eval(enterPercent, mNormalColor, mSelectedColor); + setTextColor(color); + } + + @Override + public void onSelected(int index, int totalCount) { + setTextColor(mSelectedColor); + } + + @Override + public void onDeselected(int index, int totalCount) { + setTextColor(mNormalColor); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/titles/CommonPagerTitleView.java b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/titles/CommonPagerTitleView.java new file mode 100644 index 0000000..96a0eb3 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/titles/CommonPagerTitleView.java @@ -0,0 +1,144 @@ +package com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.titles; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IMeasurablePagerTitleView; + + +/** + * 通用的指示器标题,子元素内容由外部提供,事件回传给外部 + * 博客: http://hackware.lucode.net + * Created by hackware on 2016/7/3. + */ +public class CommonPagerTitleView extends FrameLayout implements IMeasurablePagerTitleView { + private OnPagerTitleChangeListener mOnPagerTitleChangeListener; + private ContentPositionDataProvider mContentPositionDataProvider; + + public CommonPagerTitleView(Context context) { + super(context); + } + + @Override + public void onSelected(int index, int totalCount) { + if (mOnPagerTitleChangeListener != null) { + mOnPagerTitleChangeListener.onSelected(index, totalCount); + } + } + + @Override + public void onDeselected(int index, int totalCount) { + if (mOnPagerTitleChangeListener != null) { + mOnPagerTitleChangeListener.onDeselected(index, totalCount); + } + } + + @Override + public void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight) { + if (mOnPagerTitleChangeListener != null) { + mOnPagerTitleChangeListener.onLeave(index, totalCount, leavePercent, leftToRight); + } + } + + @Override + public void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight) { + if (mOnPagerTitleChangeListener != null) { + mOnPagerTitleChangeListener.onEnter(index, totalCount, enterPercent, leftToRight); + } + } + + @Override + public int getContentLeft() { + if (mContentPositionDataProvider != null) { + return mContentPositionDataProvider.getContentLeft(); + } + return getLeft(); + } + + @Override + public int getContentTop() { + if (mContentPositionDataProvider != null) { + return mContentPositionDataProvider.getContentTop(); + } + return getTop(); + } + + @Override + public int getContentRight() { + if (mContentPositionDataProvider != null) { + return mContentPositionDataProvider.getContentRight(); + } + return getRight(); + } + + @Override + public int getContentBottom() { + if (mContentPositionDataProvider != null) { + return mContentPositionDataProvider.getContentBottom(); + } + return getBottom(); + } + + /** + * 外部直接将布局设置进来 + * + * @param contentView + */ + public void setContentView(View contentView) { + setContentView(contentView, null); + } + + public void setContentView(View contentView, LayoutParams lp) { + removeAllViews(); + if (contentView != null) { + if (lp == null) { + lp = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + } + addView(contentView, lp); + } + } + + public void setContentView(int layoutId) { + View child = LayoutInflater.from(getContext()).inflate(layoutId, null); + setContentView(child, null); + } + + public OnPagerTitleChangeListener getOnPagerTitleChangeListener() { + return mOnPagerTitleChangeListener; + } + + public void setOnPagerTitleChangeListener(OnPagerTitleChangeListener onPagerTitleChangeListener) { + mOnPagerTitleChangeListener = onPagerTitleChangeListener; + } + + public ContentPositionDataProvider getContentPositionDataProvider() { + return mContentPositionDataProvider; + } + + public void setContentPositionDataProvider(ContentPositionDataProvider contentPositionDataProvider) { + mContentPositionDataProvider = contentPositionDataProvider; + } + + public interface OnPagerTitleChangeListener { + void onSelected(int index, int totalCount); + + void onDeselected(int index, int totalCount); + + void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight); + + void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight); + } + + public interface ContentPositionDataProvider { + int getContentLeft(); + + int getContentTop(); + + int getContentRight(); + + int getContentBottom(); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/titles/DummyPagerTitleView.java b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/titles/DummyPagerTitleView.java new file mode 100644 index 0000000..7d4c148 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/titles/DummyPagerTitleView.java @@ -0,0 +1,34 @@ +package com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.titles; + +import android.content.Context; +import android.view.View; + +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerTitleView; + +/** + * 空指示器标题,用于只需要指示器而不需要title的需求 + * 博客: http://hackware.lucode.net + * Created by hackware on 2016/6/26. + */ +public class DummyPagerTitleView extends View implements IPagerTitleView { + + public DummyPagerTitleView(Context context) { + super(context); + } + + @Override + public void onSelected(int index, int totalCount) { + } + + @Override + public void onDeselected(int index, int totalCount) { + } + + @Override + public void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight) { + } + + @Override + public void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight) { + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/titles/SimplePagerTitleView.java b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/titles/SimplePagerTitleView.java new file mode 100644 index 0000000..4eb1f81 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/titles/SimplePagerTitleView.java @@ -0,0 +1,99 @@ +package com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.titles; + +import android.content.Context; +import android.graphics.Paint; +import android.graphics.Rect; +import android.text.TextUtils; +import android.view.Gravity; +import android.widget.TextView; + +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IMeasurablePagerTitleView; + + +/** + * 带文本的指示器标题 + * 博客: http://hackware.lucode.net + * Created by hackware on 2016/6/26. + */ +public class SimplePagerTitleView extends androidx.appcompat.widget.AppCompatTextView implements IMeasurablePagerTitleView { + protected int mSelectedColor; + protected int mNormalColor; + + public SimplePagerTitleView(Context context) { + super(context, null); + init(context); + } + + private void init(Context context) { + setGravity(Gravity.CENTER); + int padding = UIUtil.dip2px(context, 10); + setPadding(padding, 0, padding, 0); + setSingleLine(); + setEllipsize(TextUtils.TruncateAt.END); + } + + @Override + public void onSelected(int index, int totalCount) { + setTextColor(mSelectedColor); + } + + @Override + public void onDeselected(int index, int totalCount) { + setTextColor(mNormalColor); + } + + @Override + public void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight) { + } + + @Override + public void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight) { + } + + @Override + public int getContentLeft() { + Rect bound = new Rect(); + getPaint().getTextBounds(getText().toString(), 0, getText().length(), bound); + int contentWidth = bound.width(); + return getLeft() + getWidth() / 2 - contentWidth / 2; + } + + @Override + public int getContentTop() { + Paint.FontMetrics metrics = getPaint().getFontMetrics(); + float contentHeight = metrics.bottom - metrics.top; + return (int) (getHeight() / 2 - contentHeight / 2); + } + + @Override + public int getContentRight() { + Rect bound = new Rect(); + getPaint().getTextBounds(getText().toString(), 0, getText().length(), bound); + int contentWidth = bound.width(); + return getLeft() + getWidth() / 2 + contentWidth / 2; + } + + @Override + public int getContentBottom() { + Paint.FontMetrics metrics = getPaint().getFontMetrics(); + float contentHeight = metrics.bottom - metrics.top; + return (int) (getHeight() / 2 + contentHeight / 2); + } + + public int getSelectedColor() { + return mSelectedColor; + } + + public void setSelectedColor(int selectedColor) { + mSelectedColor = selectedColor; + } + + public int getNormalColor() { + return mNormalColor; + } + + public void setNormalColor(int normalColor) { + mNormalColor = normalColor; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/titles/badge/BadgeAnchor.java b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/titles/badge/BadgeAnchor.java new file mode 100644 index 0000000..75b4fd9 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/titles/badge/BadgeAnchor.java @@ -0,0 +1,22 @@ +package com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.titles.badge; + +/** + * 角标的锚点 + * Created by hackware on 2016/7/19. + */ +public enum BadgeAnchor { + LEFT, + TOP, + RIGHT, + BOTTOM, + CONTENT_LEFT, + CONTENT_TOP, + CONTENT_RIGHT, + CONTENT_BOTTOM, + CENTER_X, + CENTER_Y, + LEFT_EDGE_CENTER_X, + TOP_EDGE_CENTER_Y, + RIGHT_EDGE_CENTER_X, + BOTTOM_EDGE_CENTER_Y +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/titles/badge/BadgePagerTitleView.java b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/titles/badge/BadgePagerTitleView.java new file mode 100644 index 0000000..121a82d --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/titles/badge/BadgePagerTitleView.java @@ -0,0 +1,222 @@ +package com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.titles.badge; + +import android.content.Context; +import android.view.View; +import android.widget.FrameLayout; + +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IMeasurablePagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerTitleView; + + +/** + * 支持显示角标的title,角标布局可自定义 + * 博客: http://hackware.lucode.net + * Created by hackware on 2016/7/18. + */ +public class BadgePagerTitleView extends FrameLayout implements IMeasurablePagerTitleView { + private IPagerTitleView mInnerPagerTitleView; + private View mBadgeView; + private boolean mAutoCancelBadge = true; + + private BadgeRule mXBadgeRule; + private BadgeRule mYBadgeRule; + + public BadgePagerTitleView(Context context) { + super(context); + } + + @Override + public void onSelected(int index, int totalCount) { + if (mInnerPagerTitleView != null) { + mInnerPagerTitleView.onSelected(index, totalCount); + } + if (mAutoCancelBadge) { + setBadgeView(null); + } + } + + @Override + public void onDeselected(int index, int totalCount) { + if (mInnerPagerTitleView != null) { + mInnerPagerTitleView.onDeselected(index, totalCount); + } + } + + @Override + public void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight) { + if (mInnerPagerTitleView != null) { + mInnerPagerTitleView.onLeave(index, totalCount, leavePercent, leftToRight); + } + } + + @Override + public void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight) { + if (mInnerPagerTitleView != null) { + mInnerPagerTitleView.onEnter(index, totalCount, enterPercent, leftToRight); + } + } + + public IPagerTitleView getInnerPagerTitleView() { + return mInnerPagerTitleView; + } + + public void setInnerPagerTitleView(IPagerTitleView innerPagerTitleView) { + if (mInnerPagerTitleView == innerPagerTitleView) { + return; + } + mInnerPagerTitleView = innerPagerTitleView; + removeAllViews(); + if (mInnerPagerTitleView instanceof View) { + LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); + addView((View) mInnerPagerTitleView, lp); + } + if (mBadgeView != null) { + LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + addView(mBadgeView, lp); + } + } + + public View getBadgeView() { + return mBadgeView; + } + + public void setBadgeView(View badgeView) { + if (mBadgeView == badgeView) { + return; + } + mBadgeView = badgeView; + removeAllViews(); + if (mInnerPagerTitleView instanceof View) { + LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); + addView((View) mInnerPagerTitleView, lp); + } + if (mBadgeView != null) { + LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + addView(mBadgeView, lp); + } + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + if (mInnerPagerTitleView instanceof View && mBadgeView != null) { + int[] position = new int[14]; // 14种角标定位方式 + View v = (View) mInnerPagerTitleView; + position[0] = v.getLeft(); + position[1] = v.getTop(); + position[2] = v.getRight(); + position[3] = v.getBottom(); + if (mInnerPagerTitleView instanceof IMeasurablePagerTitleView) { + IMeasurablePagerTitleView view = (IMeasurablePagerTitleView) mInnerPagerTitleView; + position[4] = view.getContentLeft(); + position[5] = view.getContentTop(); + position[6] = view.getContentRight(); + position[7] = view.getContentBottom(); + } else { + for (int i = 4; i < 8; i++) { + position[i] = position[i - 4]; + } + } + position[8] = v.getWidth() / 2; + position[9] = v.getHeight() / 2; + position[10] = position[4] / 2; + position[11] = position[5] / 2; + position[12] = position[6] + (position[2] - position[6]) / 2; + position[13] = position[7] + (position[3] - position[7]) / 2; + + // 根据设置的BadgeRule调整角标的位置 + if (mXBadgeRule != null) { + int x = position[mXBadgeRule.getAnchor().ordinal()]; + int offset = mXBadgeRule.getOffset(); + int newLeft = x + offset; + mBadgeView.offsetLeftAndRight(newLeft - mBadgeView.getLeft()); + } + if (mYBadgeRule != null) { + int y = position[mYBadgeRule.getAnchor().ordinal()]; + int offset = mYBadgeRule.getOffset(); + int newTop = y + offset; + mBadgeView.offsetTopAndBottom(newTop - mBadgeView.getTop()); + } + } + } + + @Override + public int getContentLeft() { + if (mInnerPagerTitleView instanceof IMeasurablePagerTitleView) { + return getLeft() + ((IMeasurablePagerTitleView) mInnerPagerTitleView).getContentLeft(); + } + return getLeft(); + } + + @Override + public int getContentTop() { + if (mInnerPagerTitleView instanceof IMeasurablePagerTitleView) { + return ((IMeasurablePagerTitleView) mInnerPagerTitleView).getContentTop(); + } + return getTop(); + } + + @Override + public int getContentRight() { + if (mInnerPagerTitleView instanceof IMeasurablePagerTitleView) { + return getLeft() + ((IMeasurablePagerTitleView) mInnerPagerTitleView).getContentRight(); + } + return getRight(); + } + + @Override + public int getContentBottom() { + if (mInnerPagerTitleView instanceof IMeasurablePagerTitleView) { + return ((IMeasurablePagerTitleView) mInnerPagerTitleView).getContentBottom(); + } + return getBottom(); + } + + public BadgeRule getXBadgeRule() { + return mXBadgeRule; + } + + public void setXBadgeRule(BadgeRule badgeRule) { + if (badgeRule != null) { + BadgeAnchor anchor = badgeRule.getAnchor(); + if (anchor != BadgeAnchor.LEFT + && anchor != BadgeAnchor.RIGHT + && anchor != BadgeAnchor.CONTENT_LEFT + && anchor != BadgeAnchor.CONTENT_RIGHT + && anchor != BadgeAnchor.CENTER_X + && anchor != BadgeAnchor.LEFT_EDGE_CENTER_X + && anchor != BadgeAnchor.RIGHT_EDGE_CENTER_X) { + throw new IllegalArgumentException("x badge rule is wrong."); + } + } + mXBadgeRule = badgeRule; + } + + public BadgeRule getYBadgeRule() { + return mYBadgeRule; + } + + public void setYBadgeRule(BadgeRule badgeRule) { + if (badgeRule != null) { + BadgeAnchor anchor = badgeRule.getAnchor(); + if (anchor != BadgeAnchor.TOP + && anchor != BadgeAnchor.BOTTOM + && anchor != BadgeAnchor.CONTENT_TOP + && anchor != BadgeAnchor.CONTENT_BOTTOM + && anchor != BadgeAnchor.CENTER_Y + && anchor != BadgeAnchor.TOP_EDGE_CENTER_Y + && anchor != BadgeAnchor.BOTTOM_EDGE_CENTER_Y) { + throw new IllegalArgumentException("y badge rule is wrong."); + } + } + mYBadgeRule = badgeRule; + } + + public boolean isAutoCancelBadge() { + return mAutoCancelBadge; + } + + public void setAutoCancelBadge(boolean autoCancelBadge) { + mAutoCancelBadge = autoCancelBadge; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/titles/badge/BadgeRule.java b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/titles/badge/BadgeRule.java new file mode 100644 index 0000000..b3eb9a4 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/buildins/commonnavigator/titles/badge/BadgeRule.java @@ -0,0 +1,32 @@ +package com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.titles.badge; + + +/** + * 角标的定位规则 + * Created by hackware on 2016/7/19. + */ +public class BadgeRule { + private BadgeAnchor mAnchor; + private int mOffset; + + public BadgeRule(BadgeAnchor anchor, int offset) { + mAnchor = anchor; + mOffset = offset; + } + + public BadgeAnchor getAnchor() { + return mAnchor; + } + + public void setAnchor(BadgeAnchor anchor) { + mAnchor = anchor; + } + + public int getOffset() { + return mOffset; + } + + public void setOffset(int offset) { + mOffset = offset; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/magicindicator/ext/FontChangePagerTitleView.java b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/ext/FontChangePagerTitleView.java new file mode 100644 index 0000000..06d5176 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/ext/FontChangePagerTitleView.java @@ -0,0 +1,181 @@ +package com.chwl.app.ui.widget.magicindicator.ext; + +import android.content.Context; +import android.graphics.Paint; +import android.graphics.Rect; +import android.text.TextPaint; +import android.view.Gravity; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IMeasurablePagerTitleView; + +/** + * create by lvzebiao @2019/5/5 + */ +public class FontChangePagerTitleView extends LinearLayout implements IMeasurablePagerTitleView { + + protected int mSelectedColor; + protected int mNormalColor; + + protected TextView textView; + + private int padding; + + public FontChangePagerTitleView(Context context) { + this(context, true, 0); + } + + public FontChangePagerTitleView(Context context, boolean selectedBold, float translationY) { + super(context); + this.selectedBold = selectedBold; + this.mTranslationY = translationY; + setGravity(Gravity.CENTER); + padding = UIUtil.dip2px(context, 10); + textView = new TextView(context); + setPadding(padding, 0, padding, 0); + addView(textView); + } + + private float mMinScale = 0.75f; + /** + * 选中是否加粗 + */ + private boolean selectedBold = true; + + /** + * 往y方向平移,设置每个tab文字底部对齐, 0.0不平移 + */ + private float mTranslationY = 0.0f; + + @Override + public void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight) { + if (textView == null) { + return; + } + try { + float scale = mMinScale + (1.0f - mMinScale) * enterPercent;//范围是mMinScale~1.0f + textView.setScaleX(scale); + textView.setScaleY(scale); + textView.setTranslationY(1.0f + (1 - enterPercent) * mTranslationY); + + //缩放后导致视觉padding变大,加上padding的兼容 + float floatPadding = (padding - textView.getWidth() * (1.0f - scale) / 2); + int newPadding = Math.round(floatPadding); + setPadding(newPadding, 0, newPadding, 0); + } catch (Exception ex) { + ex.printStackTrace(); + } + + } + + @Override + public void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight) { + if (textView == null) { + return; + } + try { + float scale = 1.0f + (mMinScale - 1.0f) * leavePercent;//范围是1.0f~mMinScale + textView.setScaleX(scale); + textView.setScaleY(scale); + textView.setTranslationY(1.0f + mTranslationY * leavePercent); + + //缩放后导致视觉padding变大,加上padding的兼容 + float floatPadding = (padding - textView.getWidth() * (1.0f - scale) / 2); + int newPadding = Math.round(floatPadding); + setPadding(newPadding, 0, newPadding, 0); + } catch (Exception ex) { + ex.printStackTrace(); + } + + } + + @Override + public void onSelected(int index, int totalCount) { + if (textView == null) { + return; + } + textView.setTextColor(mSelectedColor); + TextPaint paint = textView.getPaint(); + paint.setFakeBoldText(selectedBold); + textView.invalidate(); + } + + @Override + public void onDeselected(int index, int totalCount) { + if (textView == null) { + return; + } + textView.setTextColor(mNormalColor); + TextPaint paint = textView.getPaint(); + paint.setFakeBoldText(false); + textView.invalidate(); + } + + public float getMinScale() { + return mMinScale; + } + + public void setMinScale(float minScale) { + mMinScale = minScale; + } + + @Override + public int getContentLeft() { + if (textView == null) { + return getLeft(); + } + Rect bound = new Rect(); + textView.getPaint().getTextBounds(textView.getText().toString(), 0, textView.getText().length(), bound); + int contentWidth = bound.width(); + return getLeft() + getWidth() / 2 - contentWidth / 2; + } + + @Override + public int getContentTop() { + if (textView == null) { + return 0; + } + Paint.FontMetrics metrics = textView.getPaint().getFontMetrics(); + float contentHeight = metrics.bottom - metrics.top; + return (int) (getHeight() / 2 - contentHeight / 2); + } + + @Override + public int getContentRight() { + if (textView == null) { + return getRight(); + } + Rect bound = new Rect(); + textView.getPaint().getTextBounds(textView.getText().toString(), 0, textView.getText().length(), bound); + int contentWidth = bound.width(); + return getLeft() + getWidth() / 2 + contentWidth / 2; + } + + @Override + public int getContentBottom() { + if (textView == null) { + return getHeight(); + } + Paint.FontMetrics metrics = textView.getPaint().getFontMetrics(); + float contentHeight = metrics.bottom - metrics.top; + return (int) (getHeight() / 2 + contentHeight / 2); + } + + public int getSelectedColor() { + return mSelectedColor; + } + + public void setSelectedColor(int selectedColor) { + mSelectedColor = selectedColor; + } + + public int getNormalColor() { + return mNormalColor; + } + + public void setNormalColor(int normalColor) { + mNormalColor = normalColor; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/magicindicator/ext/MainCommonNavigatorAdapter.java b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/ext/MainCommonNavigatorAdapter.java new file mode 100644 index 0000000..098c29b --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/magicindicator/ext/MainCommonNavigatorAdapter.java @@ -0,0 +1,67 @@ +package com.chwl.app.ui.widget.magicindicator.ext; + +import android.content.Context; + +import androidx.core.content.ContextCompat; + +import com.chwl.app.R; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.CommonNavigatorAdapter; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerTitleView; + +import java.util.ArrayList; +import java.util.List; + +/** + * create by lvzebiao @2019/5/5 + */ +public class MainCommonNavigatorAdapter extends CommonNavigatorAdapter { + + private Context context; + + private List titleList; + + private OnTabClickListener onTabClickListener; + + public MainCommonNavigatorAdapter(Context context, List titleList) { + this.context = context; + if (titleList == null) { + titleList = new ArrayList<>(); + } + this.titleList = titleList; + } + + @Override + public int getCount() { + return titleList.size(); + } + + @Override + public IPagerTitleView getTitleView(Context context, int index) { + FontChangePagerTitleView commonPagerTitleView = new FontChangePagerTitleView(context, true, 5); + commonPagerTitleView.setNormalColor(ContextCompat.getColor(context, R.color.color_333333)); + commonPagerTitleView.setSelectedColor(ContextCompat.getColor(context, R.color.color_333333)); + commonPagerTitleView.setMinScale(0.8f); + commonPagerTitleView.textView.setTextSize(20); + commonPagerTitleView.textView.setText(titleList.get(index)); + commonPagerTitleView.setOnClickListener(v -> { + if (onTabClickListener != null) { + onTabClickListener.onTabClick(index); + } + }); + return commonPagerTitleView; + } + + @Override + public IPagerIndicator getIndicator(Context context) { + return null; + } + + public interface OnTabClickListener { + void onTabClick(int index); + } + + public void setOnTabClickListener(OnTabClickListener onTabClickListener) { + this.onTabClickListener = onTabClickListener; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/marqueeview/AvRoomNobleWelcomeView.java b/app/src/main/java/com/chwl/app/ui/widget/marqueeview/AvRoomNobleWelcomeView.java new file mode 100644 index 0000000..7888a10 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/marqueeview/AvRoomNobleWelcomeView.java @@ -0,0 +1,130 @@ +package com.chwl.app.ui.widget.marqueeview; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.content.Context; +import android.text.TextPaint; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.view.View; +import android.view.animation.LinearInterpolator; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import androidx.appcompat.widget.AppCompatImageView; + +import com.chwl.app.R; +import com.chwl.core.noble.bean.NobleInfo; +import com.chwl.core.noble.NobleUtil; +import com.chwl.library.utils.ScreenUtils; +import com.chwl.library.utils.SizeUtils; + +/** + *

贵族进入房间欢迎界面 + *

+ * + * @author jiahui + * @date 2018/1/19 + */ +public class AvRoomNobleWelcomeView extends RelativeLayout { + private View mNobleBg; + private AppCompatImageView mIvNobleLevel; + private TextView mTvNobleWelcome; + private Context mContext; + + private AnimatorSet mAnimatorSet; + private int mScreenWidth; + private int mWelcomeViewWidth; + private int mLeftWidth; + + public AvRoomNobleWelcomeView(Context context) { + this(context, null); + } + + public AvRoomNobleWelcomeView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public AvRoomNobleWelcomeView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + mContext = context; + inflate(context, R.layout.avroom_menber_in_room_float_layout, this); + mWelcomeViewWidth = SizeUtils.dp2px(context, 259); + + setHorizontalScrollBarEnabled(false); + mScreenWidth = ScreenUtils.getScreenWidth(context); + mLeftWidth = SizeUtils.dp2px(context, 69); + + mNobleBg = findViewById(R.id.bg_noble_welcome); + mIvNobleLevel = findViewById(R.id.iv_noble_level); + mTvNobleWelcome = findViewById(R.id.tv_noble_welcome); + } + + + public void setData(NobleInfo nobleInfo, String nick) { + if (nobleInfo == null || TextUtils.isEmpty(nick) || + !NobleUtil.canShowEnterRoomWelcome(nobleInfo.getLevel())) return; + setVisibility(VISIBLE); + mTvNobleWelcome.setText(mContext.getString(R.string.noble_welcome_text, nick)); + + NobleUtil.loadResource(NobleUtil.getSmallBadgeByLevel(nobleInfo.getLevel()), mIvNobleLevel); + mNobleBg.setBackground(NobleUtil.getDrawable(mContext, NobleUtil.getBannerByLevel(nobleInfo.getLevel()))); + + TextPaint paint = mTvNobleWelcome.getPaint(); + int len = (int) paint.measureText(mTvNobleWelcome.getText().toString()); + + cancelAnim(); + this.setAlpha(1); + + mAnimatorSet = new AnimatorSet(); + ObjectAnimator inAnimator = ObjectAnimator.ofFloat(this, + "translationX", -mScreenWidth, 0); + inAnimator.setDuration(500); + inAnimator.setInterpolator(new LinearInterpolator()); + + int dis = len - (mWelcomeViewWidth - mLeftWidth); + ObjectAnimator scroll = null; + mTvNobleWelcome.setTranslationX(0); + if (dis > 0) { + scroll = ObjectAnimator.ofFloat(mTvNobleWelcome, "translationX", 0, -dis); + scroll.setStartDelay(800); + scroll.setDuration((long) (len * 0.4) + 2000); + } + + ObjectAnimator alpha = ObjectAnimator.ofFloat(this, "alpha", 1, 0); + long duration = 500; + alpha.setStartDelay(duration); + alpha.setDuration(800); + + if (scroll == null) { + mAnimatorSet.playSequentially(inAnimator, alpha); + } else { + mAnimatorSet.playSequentially(inAnimator, scroll, alpha); + } + + mAnimatorSet.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + setVisibility(GONE); + } + }); + mAnimatorSet.start(); + } + + + @Override + protected void onDetachedFromWindow() { + cancelAnim(); + mAnimatorSet = null; + super.onDetachedFromWindow(); + } + + private void cancelAnim() { + if (mAnimatorSet != null && mAnimatorSet.isRunning()) { + mAnimatorSet.cancel(); + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/marqueeview/BetterMarqueeView.java b/app/src/main/java/com/chwl/app/ui/widget/marqueeview/BetterMarqueeView.java new file mode 100644 index 0000000..d0279f7 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/marqueeview/BetterMarqueeView.java @@ -0,0 +1,146 @@ +package com.chwl.app.ui.widget.marqueeview; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.Animation; + +/** + * @author jack + * @Description + * @Date 2018/5/3 + */ + +public class BetterMarqueeView extends MarqueeView { + private Adapter adapter; + + private final int reuseViewSize = 2; + private boolean isFlipping = false; + + public BetterMarqueeView(Context context) { + this(context, null); + } + + public BetterMarqueeView(Context context, AttributeSet attrs) { + super(context, attrs); + initView(); + } + + private void initView() { + setInAndOutAnimation(inAnimResId, outAnimResId); + getInAnimation().setAnimationListener(new Animation.AnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + } + + @Override + public void onAnimationEnd(Animation animation) { + position++; + if (position >= adapter.getSize()) { + position = 0; + } + View view = getChildAt((getDisplayedChild() + 1) % reuseViewSize); + if (view != null) { + adapter.onBindViewHolder((ViewHolder) view.getTag(), position); + } + } + + @Override + public void onAnimationRepeat(Animation animation) { + } + }); + } + + public void start(){ + if (adapter != null && adapter.getSize() > 1) { + setAutoStart(true); + startFlipping(); + } + isFlipping = true; + } + + public void stop(){ + stopFlipping(); + isFlipping = false; + } + + /** + * 设置适配器 + * @param adapter + */ + public void setAdapter(Adapter adapter){ + this.adapter = adapter; + this.adapter.setBetterMarqueeView(this); + notifyDataSetChange(); + } + + /** + * 刷新 + */ + private void notifyDataSetChange(){ + removeAllViews(); + clearAnimation(); + if (this.adapter.getSize() > 1){ + if (isFlipping) { + startFlipping(); + }else{ + stopFlipping(); + } + for (int i = 0; i < reuseViewSize; i++) { + ViewHolder viewHolder = adapter.onCreateView(this); + viewHolder.itemView.setTag(viewHolder); + addView(viewHolder.itemView); + adapter.onBindViewHolder(viewHolder,i); + position = i; + } + }else if (this.adapter.getSize() > 0){ + stopFlipping(); + ViewHolder viewHolder = adapter.onCreateView(this); + viewHolder.itemView.setTag(viewHolder); + addView(viewHolder.itemView); + adapter.onBindViewHolder(viewHolder,0); + position = 0; + }else{ + stopFlipping(); + } + + } + + + /** + * 适配器,暂时单一类型 子view,之后可以扩展成支持多类型 + * @param + */ + public abstract static class Adapter{ + private BetterMarqueeView betterMarqueeView; + + private void setBetterMarqueeView(BetterMarqueeView view){ + this.betterMarqueeView = view; + } + + public final void notifyDateSetChange(){ + betterMarqueeView.notifyDataSetChange(); + } + + public abstract VH onCreateView(ViewGroup parent); + + public abstract void onBindViewHolder(VH holder, int position); + + public abstract int getSize(); + } + + /** + * View Holder + */ + public static abstract class ViewHolder{ + public View itemView; + + public ViewHolder(View itemView) { + if (itemView == null) { + throw new IllegalArgumentException("itemView may not be null"); + } + this.itemView = itemView; + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/marqueeview/MarqueeView.java b/app/src/main/java/com/chwl/app/ui/widget/marqueeview/MarqueeView.java new file mode 100644 index 0000000..6b6b35d --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/marqueeview/MarqueeView.java @@ -0,0 +1,304 @@ +package com.chwl.app.ui.widget.marqueeview; + +import android.content.Context; +import android.content.res.TypedArray; +import android.os.Build; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.View; +import android.view.ViewTreeObserver; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; +import android.widget.TextView; +import android.widget.ViewFlipper; + +import androidx.annotation.AnimRes; + +import com.chwl.app.R; +import com.chwl.library.common.util.Utils; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by sunfusheng on 16/5/31. + */ +public class MarqueeView extends ViewFlipper { + + private int interval = 3000; + private boolean hasSetAnimDuration = false; + private int animDuration = 1000; + private int textSize = 14; + private int textColor = 0xffffffff; + private boolean singleLine = false; + + private int gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL; + private static final int GRAVITY_LEFT = 0; + private static final int GRAVITY_CENTER = 1; + private static final int GRAVITY_RIGHT = 2; + + private boolean hasSetDirection = false; + private int direction = DIRECTION_BOTTOM_TO_TOP; + private static final int DIRECTION_BOTTOM_TO_TOP = 0; + private static final int DIRECTION_TOP_TO_BOTTOM = 1; + private static final int DIRECTION_RIGHT_TO_LEFT = 2; + private static final int DIRECTION_LEFT_TO_RIGHT = 3; + + @AnimRes + protected int inAnimResId = R.anim.anim_bottom_in; + @AnimRes + protected int outAnimResId = R.anim.anim_top_out; + + protected int position; + private List notices = new ArrayList<>(); + private OnItemClickListener onItemClickListener; + + public MarqueeView(Context context, AttributeSet attrs) { + super(context, attrs); + init(context, attrs, 0); + } + + private void init(Context context, AttributeSet attrs, int defStyleAttr) { + TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MarqueeViewStyle, defStyleAttr, 0); + + interval = typedArray.getInteger(R.styleable.MarqueeViewStyle_mvInterval, interval); + hasSetAnimDuration = typedArray.hasValue(R.styleable.MarqueeViewStyle_mvAnimDuration); + animDuration = typedArray.getInteger(R.styleable.MarqueeViewStyle_mvAnimDuration, animDuration); + singleLine = typedArray.getBoolean(R.styleable.MarqueeViewStyle_mvSingleLine, false); + if (typedArray.hasValue(R.styleable.MarqueeViewStyle_mvTextSize)) { + textSize = (int) typedArray.getDimension(R.styleable.MarqueeViewStyle_mvTextSize, textSize); + textSize = Utils.px2sp(context, textSize); + } + textColor = typedArray.getColor(R.styleable.MarqueeViewStyle_mvTextColor, textColor); + + int gravityType = typedArray.getInt(R.styleable.MarqueeViewStyle_mvGravity, GRAVITY_LEFT); + switch (gravityType) { + case GRAVITY_LEFT: + gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL; + break; + case GRAVITY_CENTER: + gravity = Gravity.CENTER; + break; + case GRAVITY_RIGHT: + gravity = Gravity.RIGHT | Gravity.CENTER_VERTICAL; + break; + } + + hasSetDirection = typedArray.hasValue(R.styleable.MarqueeViewStyle_mvDirection); + direction = typedArray.getInt(R.styleable.MarqueeViewStyle_mvDirection, direction); + if (hasSetDirection) { + switch (direction) { + case DIRECTION_BOTTOM_TO_TOP: + inAnimResId = R.anim.anim_bottom_in; + outAnimResId = R.anim.anim_top_out; + break; + case DIRECTION_TOP_TO_BOTTOM: + inAnimResId = R.anim.anim_top_in; + outAnimResId = R.anim.anim_bottom_out; + break; + case DIRECTION_RIGHT_TO_LEFT: + inAnimResId = R.anim.anim_right_in; + outAnimResId = R.anim.anim_left_out; + break; + case DIRECTION_LEFT_TO_RIGHT: + inAnimResId = R.anim.anim_left_in; + outAnimResId = R.anim.anim_right_out; + break; + } + } else { + inAnimResId = R.anim.anim_bottom_in; + outAnimResId = R.anim.anim_top_out; + } + + typedArray.recycle(); + setFlipInterval(interval); + } + + /** + * 根据字符串,启动翻页公告 + * + * @param notice 字符串 + */ + public void startWithText(String notice) { + startWithText(notice, inAnimResId, outAnimResId); + } + + /** + * 根据字符串,启动翻页公告 + * + * @param notice 字符串 + * @param inAnimResId 进入动画的resID + * @param outAnimResID 离开动画的resID + */ + @SuppressWarnings("deprecation") + public void startWithText(final String notice, final @AnimRes int inAnimResId, final @AnimRes int outAnimResID) { + if (TextUtils.isEmpty(notice)) return; + getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + getViewTreeObserver().removeOnGlobalLayoutListener(this); + } else { + getViewTreeObserver().removeGlobalOnLayoutListener(this); + } + startWithFixedWidth(notice, inAnimResId, outAnimResID); + } + }); + } + + /** + * 根据字符串和宽度,启动翻页公告 + * + * @param notice 字符串 + */ + private void startWithFixedWidth(String notice, @AnimRes int inAnimResId, @AnimRes int outAnimResID) { + int noticeLength = notice.length(); + int width = Utils.px2dip(getContext(), getWidth()); + if (width == 0) { + throw new RuntimeException("Please set the width of MarqueeView !"); + } + int limit = width / textSize; + List list = new ArrayList(); + + if (noticeLength <= limit) { + list.add(notice); + } else { + int size = noticeLength / limit + (noticeLength % limit != 0 ? 1 : 0); + for (int i = 0; i < size; i++) { + int startIndex = i * limit; + int endIndex = ((i + 1) * limit >= noticeLength ? noticeLength : (i + 1) * limit); + list.add(notice.substring(startIndex, endIndex)); + } + } + + if (notices == null) notices = new ArrayList<>(); + notices.clear(); + notices.addAll(list); + start(inAnimResId, outAnimResID); + } + + /** + * 根据字符串列表,启动翻页公告 + * + * @param notices 字符串列表 + */ + public void startWithList(List notices) { + startWithList(notices, inAnimResId, outAnimResId); + } + + /** + * 根据字符串列表,启动翻页公告 + * + * @param notices 字符串列表 + * @param inAnimResId 进入动画的resID + * @param outAnimResID 离开动画的resID + */ + public void startWithList(List notices, @AnimRes int inAnimResId, @AnimRes int outAnimResID) { + if (Utils.isEmpty(notices)) return; + setNotices(notices); + start(inAnimResId, outAnimResID); + } + + protected boolean start(@AnimRes int inAnimResId, @AnimRes int outAnimResID) { + removeAllViews(); + clearAnimation(); + + position = 0; + addView(createTextView(notices.get(position))); + + if (notices.size() > 1) { + setInAndOutAnimation(inAnimResId, outAnimResID); + startFlipping(); + } + + if (getInAnimation() != null) { + getInAnimation().setAnimationListener(new Animation.AnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + } + + @Override + public void onAnimationEnd(Animation animation) { + position++; + if (position >= notices.size()) { + position = 0; + } + View view = createTextView(notices.get(position)); + if (view.getParent() == null) { + addView(view); + } + } + + @Override + public void onAnimationRepeat(Animation animation) { + } + }); + } + return true; + } + + private TextView createTextView(CharSequence text) { + TextView textView = (TextView) getChildAt((getDisplayedChild() + 1) % 3); + if (textView == null) { + textView = new TextView(getContext()); + textView.setGravity(gravity); + textView.setTextColor(textColor); + textView.setTextSize(textSize); + textView.setSingleLine(singleLine); + if (singleLine) { + textView.setEllipsize(TextUtils.TruncateAt.END); + } + } + textView.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (onItemClickListener != null) { + onItemClickListener.onItemClick(getPosition(), (TextView) v); + } + } + }); + textView.setText(text); + textView.setTag(position); + return textView; + } + + + + public int getPosition() { + return (int) getCurrentView().getTag(); + } + + public List getNotices() { + return notices; + } + + public void setNotices(List notices) { + this.notices = notices; + } + + public void setOnItemClickListener(OnItemClickListener onItemClickListener) { + this.onItemClickListener = onItemClickListener; + } + + public interface OnItemClickListener { + void onItemClick(int position, TextView textView); + } + + /** + * 设置进入动画和离开动画 + * + * @param inAnimResId 进入动画的resID + * @param outAnimResID 离开动画的resID + */ + protected void setInAndOutAnimation(@AnimRes int inAnimResId, @AnimRes int outAnimResID) { + Animation inAnim = AnimationUtils.loadAnimation(getContext(), inAnimResId); + if (hasSetAnimDuration) inAnim.setDuration(animDuration); + setInAnimation(inAnim); + + Animation outAnim = AnimationUtils.loadAnimation(getContext(), outAnimResID); + if (hasSetAnimDuration) outAnim.setDuration(animDuration); + setOutAnimation(outAnim); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/password/PassWordFragment.java b/app/src/main/java/com/chwl/app/ui/widget/password/PassWordFragment.java new file mode 100644 index 0000000..f2c2e26 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/password/PassWordFragment.java @@ -0,0 +1,173 @@ +package com.chwl.app.ui.widget.password; + + +import android.app.Activity; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.util.DisplayMetrics; +import android.view.Display; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; + +import androidx.annotation.Nullable; +import androidx.fragment.app.DialogFragment; +import androidx.fragment.app.FragmentManager; + +import com.jungly.gridpasswordview.GridPasswordView; +import com.netease.nim.uikit.common.util.log.LogUtil; +import com.chwl.app.R; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.app.ui.setting.VerifyPhoneActivity; +import com.chwl.library.utils.codec.DESUtils; + +import org.greenrobot.eventbus.EventBus; + +//也可继承design中的BottomSheetDialogFragment +public class PassWordFragment extends DialogFragment { + + private static final String TAG = "PassWordFragment"; + + public final static int TYPE_DEFALUT = 0; + + public final static String EXTRA_TYPE = "extra_type"; + + private PasswordView mPassword; + /**用于标识密码类型*/ + private int type = TYPE_DEFALUT; + + private DialogManager mDialogManager; + + public static PassWordFragment newInstace(long value) { + PassWordFragment passWordFragment = new PassWordFragment(); + Bundle bundle = new Bundle(); + bundle.putLong("values", value); + passWordFragment.setArguments(bundle); + return passWordFragment; + } + + public static PassWordFragment newInstace(long value, int hammerNum) { + PassWordFragment passWordFragment = new PassWordFragment(); + Bundle bundle = new Bundle(); + bundle.putLong("values", value); + bundle.putInt("hammerNum", hammerNum); + passWordFragment.setArguments(bundle); + return passWordFragment; + } + + public static PassWordFragment newInstance(int type) { + PassWordFragment passWordFragment = new PassWordFragment(); + Bundle bundle = new Bundle(); + bundle.putInt(EXTRA_TYPE, type); + passWordFragment.setArguments(bundle); + return passWordFragment; + } + + public static PassWordFragment newInstance() { + return new PassWordFragment(); + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + public void show(FragmentManager fragmentManager) { + this.show(fragmentManager, TAG); + } + + @Override + public void show(FragmentManager manager, String tag) { + if (manager.findFragmentByTag(tag) == null) { + manager.beginTransaction() + .add(this, tag) + .commitAllowingStateLoss(); + } + } + + //继承BottomSheetDialogFragment时onStart()可注释掉 + @Override + public void onStart() { + super.onStart(); + + Window win = getDialog().getWindow(); + win.setBackgroundDrawable(new ColorDrawable(getResources().getColor(R.color.transparent))); + WindowManager.LayoutParams layoutParams = getDialog().getWindow().getAttributes(); + + DisplayMetrics dm = new DisplayMetrics(); + Display d = win.getWindowManager().getDefaultDisplay(); + d.getRealMetrics(dm); + getActivity().getWindowManager().getDefaultDisplay().getMetrics(dm); + layoutParams.width = (int) (dm.widthPixels); +// layoutParams.height = (isFullScreen ? getContext().getResources().getDisplayMetrics().heightPixels : dm.heightPixels) - +// (Utils.hasSoftKeys(getContext()) ? Utils.getNavigationBarHeight(getContext()) : 0); + win.setAttributes(layoutParams); + + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.dialog_password, container); + init(view); + return view; + } + + public DialogManager getDialogManager() { + if (mDialogManager == null) { + mDialogManager = new DialogManager(getContext()); + mDialogManager.setCanceledOnClickOutside(false); + } + return mDialogManager; + } + + private void init(View view) { + if (getArguments() != null) { + type = getArguments().getInt(EXTRA_TYPE, TYPE_DEFALUT); + } + mPassword = (PasswordView) view.findViewById(R.id.view_password); + mPassword.getCloseImageView().setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + dismiss(); + } + }); + + mPassword.getForgetTextView().setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + VerifyPhoneActivity.start(getActivity(), true); + dismiss(); + } + }); + + mPassword.getPswView().setOnPasswordChangedListener(new GridPasswordView.OnPasswordChangedListener() { + @Override + public void onTextChanged(String psw) { + if (mPassword.getPassword().length() == 6) { + dismiss(); + try { + EventBus.getDefault().post(new PasswordEvent().setType(type) + .setPassword( + DESUtils.DESAndBase64Encrypt(mPassword.getPassword()))); + } catch (Exception e) { + e.printStackTrace(); + LogUtil.e(TAG, "onInputFinish: payment password encrypt error", e); + } + } + } + + @Override + public void onInputFinish(String psw) { + + } + }); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/password/PasswordEvent.java b/app/src/main/java/com/chwl/app/ui/widget/password/PasswordEvent.java new file mode 100644 index 0000000..bfaf9a0 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/password/PasswordEvent.java @@ -0,0 +1,25 @@ +package com.chwl.app.ui.widget.password; + +import lombok.Data; + +/** + * Created by MadisonRong on 2019-08-19 + */ +@Data +public class PasswordEvent { + + private String password; + + private int type; + + public PasswordEvent setPassword(String password) { + this.password = password; + return this; + } + + public PasswordEvent setType(int type) { + this.type = type; + return this; + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/password/PasswordKeyboardView.java b/app/src/main/java/com/chwl/app/ui/widget/password/PasswordKeyboardView.java new file mode 100644 index 0000000..337ac7f --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/password/PasswordKeyboardView.java @@ -0,0 +1,230 @@ +package com.chwl.app.ui.widget.password; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Rect; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.inputmethodservice.Keyboard; +import android.inputmethodservice.KeyboardView; +import android.util.AttributeSet; + +import com.chwl.app.R; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * Created by lcw on 2016/11/28. + */ + +public class PasswordKeyboardView extends KeyboardView implements KeyboardView.OnKeyboardActionListener{ + + // 用于区分左下角空白的按键 + private static final int KEYCODE_EMPTY = -10; + + private int mDeleteBackgroundColor; + private Rect mDeleteDrawRect; + private Drawable mDeleteDrawable; + + private IOnKeyboardListener mOnKeyboardListener; + + // 0-9 的数字 + private final List keyCodes = Arrays.asList( + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); + + public PasswordKeyboardView(Context context, AttributeSet attrs) { + super(context, attrs); + init(context, attrs, 0); + } + + public PasswordKeyboardView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context, attrs, defStyleAttr); + } + + private void init(Context context, AttributeSet attrs, + int defStyleAttr) { + TypedArray a = context.obtainStyledAttributes(attrs, + R.styleable.PasswordKeyboardView, defStyleAttr, 0); + mDeleteDrawable = a.getDrawable( + R.styleable.PasswordKeyboardView_pkvDeleteDrawable); + mDeleteBackgroundColor = a.getColor( + R.styleable.PasswordKeyboardView_pkvDeleteBackgroundColor, + Color.parseColor("#f0f0f0")); + a.recycle(); + + // 设置软键盘按键的布局 + Keyboard keyboard = new Keyboard(context, + R.xml.keyboard_number_password); + setKeyboard(keyboard); + + setEnabled(true); + setPreviewEnabled(false); + setOnKeyboardActionListener(this); + } + + @Override + public void onDraw(Canvas canvas) { + super.onDraw(canvas); + + // 遍历所有的按键 + List keys = getKeyboard().getKeys(); + for (Keyboard.Key key : keys) { + // 如果是左下角空白的按键,重画按键的背景 + if (key.codes[0] == KEYCODE_EMPTY) { + drawKeyBackground(key, canvas, mDeleteBackgroundColor); + } + // 如果是右下角的删除按键,重画背景,并且绘制删除的图标 + else if (key.codes[0] == Keyboard.KEYCODE_DELETE) { + drawKeyBackground(key, canvas, mDeleteBackgroundColor); + drawDeleteButton(key, canvas); + } + } + } + + // 绘制按键的背景 + private void drawKeyBackground(Keyboard.Key key, Canvas canvas, + int color) { + ColorDrawable drawable = new ColorDrawable(color); + drawable.setBounds(key.x, key.y, + key.x + key.width, key.y + key.height); + drawable.draw(canvas); + } + + // 绘制删除按键 + private void drawDeleteButton(Keyboard.Key key, Canvas canvas) { + if (mDeleteDrawable == null) + return; + + // 计算删除图标绘制的坐标 + if (mDeleteDrawRect == null || mDeleteDrawRect.isEmpty()) { + int intrinsicWidth = mDeleteDrawable.getIntrinsicWidth(); + int intrinsicHeight = mDeleteDrawable.getIntrinsicHeight(); + int drawWidth = intrinsicWidth; + int drawHeight = intrinsicHeight; + + // 限制图标的大小,防止图标超出按键 + if (drawWidth > key.width) { + drawWidth = key.width; + drawHeight = drawWidth * intrinsicHeight / intrinsicWidth; + } + if (drawHeight > key.height) { + drawHeight = key.height; + drawWidth = drawHeight * intrinsicWidth / intrinsicHeight; + } + + // 获取删除图标绘制的坐标 + int left = key.x + (key.width - drawWidth) / 2; + int top = key.y + (key.height - drawHeight) / 2; + mDeleteDrawRect = new Rect(left, top, + left + drawWidth, top + drawHeight); + } + + // 绘制删除的图标 + if (mDeleteDrawRect != null && !mDeleteDrawRect.isEmpty()) { + mDeleteDrawable.setBounds(mDeleteDrawRect.left, + mDeleteDrawRect.top, mDeleteDrawRect.right, + mDeleteDrawRect.bottom); + mDeleteDrawable.draw(canvas); + } + } + + + @Override + public void onPress(int i) { + + } + + @Override + public void onRelease(int i) { + + } + + @Override + public void onKey(int i, int[] ints) { + // 处理按键的点击事件 + // 点击删除按键 + if (i == Keyboard.KEYCODE_DELETE) { + if (mOnKeyboardListener != null) { + mOnKeyboardListener.onDeleteKeyEvent(); + } + } + // 点击了非左下角按键的其他按键 + else if (i != KEYCODE_EMPTY) { + if (mOnKeyboardListener != null) { + mOnKeyboardListener.onInsertKeyEvent( + Character.toString((char) i)); + } + } + } + + @Override + public void onText(CharSequence charSequence) { + + } + + @Override + public void swipeLeft() { + } + + @Override + public void swipeUp() { + } + + @Override + public void swipeRight() { + } + + @Override + public void swipeDown() { + } + + /** + * 设置键盘的监听事件。 + * + * @param listener + * 监听事件 + */ + public void setIOnKeyboardListener(IOnKeyboardListener listener) { + this.mOnKeyboardListener = listener; + } + + public interface IOnKeyboardListener { + + void onInsertKeyEvent(String text); + + void onDeleteKeyEvent(); + } + + /** + * 随机打乱数字键盘上显示的数字顺序。 + */ + public void shuffleKeyboard() { + Keyboard keyboard = getKeyboard(); + if (keyboard != null && keyboard.getKeys() != null + && keyboard.getKeys().size() > 0) { + // 随机排序数字 + Collections.shuffle(keyCodes); + + // 遍历所有的按键 + List keys = getKeyboard().getKeys(); + int index = 0; + for (Keyboard.Key key : keys) { + // 如果按键是数字 + if (key.codes[0] != KEYCODE_EMPTY + && key.codes[0] != Keyboard.KEYCODE_DELETE) { + char code = keyCodes.get(index++); + key.codes[0] = code; + key.label = Character.toString(code); + } + } + // 更新键盘 + setKeyboard(keyboard); + } + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/password/PasswordView.java b/app/src/main/java/com/chwl/app/ui/widget/password/PasswordView.java new file mode 100644 index 0000000..0261be3 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/password/PasswordView.java @@ -0,0 +1,113 @@ +package com.chwl.app.ui.widget.password; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.jungly.gridpasswordview.GridPasswordView; +import com.chwl.app.R; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by lcw on 2016/11/28. + */ + +public class PasswordView extends RelativeLayout { + + private View mView; + private ImageView mClose; + private TextView mTitle; + private TextView mForgetPwd; + private GridPasswordView mPassword; + private PasswordKeyboardView mKeyboard; + private List passwordList;//记录键盘输入的值 + private StringBuilder mValue;//最后保存的密码 + + public PasswordView(Context context) { + this(context, null); + } + + public PasswordView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public PasswordView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + mView = View.inflate(context, R.layout.view_password, null); + + initView(); + initEvent(); + + addView(mView); + } + + private void initView(){ + mPassword = (GridPasswordView) mView.findViewById(R.id.view_password); + mClose = (ImageView) mView.findViewById(R.id.img_close); + mTitle = (TextView) mView.findViewById(R.id.tv_title); + mForgetPwd = (TextView) mView.findViewById(R.id.tv_forgetPwd); + mKeyboard = (PasswordKeyboardView) mView.findViewById(R.id.view_keyboard); + //打乱数字的位置 + //mKeyboard.shuffleKeyboard(); + } + + private void initEvent(){ + mValue = new StringBuilder(); + passwordList = new ArrayList<>(); + mKeyboard.setIOnKeyboardListener(new PasswordKeyboardView.IOnKeyboardListener() { + + @Override + public void onInsertKeyEvent(String text) { + mValue.setLength(0); + passwordList.add(text); + for (int i = 0; i < passwordList.size(); i++) { + mValue.append(passwordList.get(i)); + } + mPassword.setPassword(mValue.toString()); + } + + @Override + public void onDeleteKeyEvent() { + mValue.setLength(0); + if(passwordList.size() != 0){ + passwordList.remove(passwordList.size()-1); + for (int i = 0; i < passwordList.size(); i++) { + mValue.append(passwordList.get(i)); + } + mPassword.setPassword(mValue.toString()); + } + } + }); + } + + //获取输入的密码 + public String getPassword(){ + return mValue.toString(); + } + + //取消 + public ImageView getCloseImageView(){ + return mClose; + } + + //标题 + public TextView getTitleTextView(){ + return mTitle; + } + + //忘记密码 + public TextView getForgetTextView() { + return mForgetPwd; + } + + //输入密码控件 + public GridPasswordView getPswView(){ + return mPassword; + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/ColorDecoration.java b/app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/ColorDecoration.java new file mode 100644 index 0000000..3245545 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/ColorDecoration.java @@ -0,0 +1,229 @@ +package com.chwl.app.ui.widget.recyclerview.decoration; + +import android.graphics.Canvas; +import android.graphics.Rect; +import android.view.View; + +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.StaggeredGridLayoutManager; + +/** + * @author jack + * @Description + * @Date 2018/4/19 + */ +public class ColorDecoration extends RecyclerView.ItemDecoration { + private int mHorizontalSpacing; + private int mVerticalSpacing; + private boolean mIncludeEdge; + private int mColor; + private int ignoreBottomCount = 0; + + private int mMarginStart; + private int mMarginEnd; + private boolean isCusStartAndEnd; + + public ColorDecoration(int color, int hSpacing, int vSpacing, boolean includeEdge) { + mHorizontalSpacing = hSpacing; + mVerticalSpacing = vSpacing; + mIncludeEdge = includeEdge; + this.mColor = color; + } + + /** + * + * @param marginStart + * px + * @param marginEnd + * px + */ + public ColorDecoration(int color, int hSpacing, int vSpacing, boolean includeEdge, int marginStart, int marginEnd) { + mHorizontalSpacing = hSpacing; + mVerticalSpacing = vSpacing; + mIncludeEdge = includeEdge; + this.mColor = color; + + isCusStartAndEnd = true; + mMarginStart = marginStart; + mMarginEnd = marginEnd; + } + + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { + super.getItemOffsets(outRect, view, parent, state); + // Only handle the vertical situation + int position = parent.getChildAdapterPosition(view); + if (parent.getLayoutManager() instanceof GridLayoutManager) { + GridLayoutManager layoutManager = (GridLayoutManager) parent.getLayoutManager(); + int spanCount = layoutManager.getSpanCount(); + int column = position % spanCount; + getGridItemOffsets(outRect, position, column, spanCount); + } else if (parent.getLayoutManager() instanceof StaggeredGridLayoutManager) { + StaggeredGridLayoutManager layoutManager = (StaggeredGridLayoutManager) parent.getLayoutManager(); + int spanCount = layoutManager.getSpanCount(); + StaggeredGridLayoutManager.LayoutParams lp = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams(); + int column = lp.getSpanIndex(); + getGridItemOffsets(outRect, position, column, spanCount); + } else if (parent.getLayoutManager() instanceof LinearLayoutManager) { + if (((LinearLayoutManager) parent.getLayoutManager()).getOrientation() == LinearLayoutManager.VERTICAL) { + if (mIncludeEdge) { + if (position == 0) { + outRect.top = mVerticalSpacing; + } + outRect.bottom = mVerticalSpacing; + } else { + if (position > 0) { + outRect.top = mVerticalSpacing; + } + } + } else { + if (mIncludeEdge) { + if (position == 0) { + outRect.left = mHorizontalSpacing; + } + outRect.right = mHorizontalSpacing; + } else { + if (position > 0) { + outRect.left = mHorizontalSpacing; + } + } + } + } + + } + + @Override + public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { + super.onDraw(c, parent, state); + if (parent.getLayoutManager() instanceof LinearLayoutManager) { + if (((LinearLayoutManager) parent.getLayoutManager()).getOrientation() == LinearLayoutManager.VERTICAL) { + drawVertical(c, parent); + } else { + drawHorizontal(c, parent); + } + }else{ + c.drawColor(mColor); + } + + } + + + + private void getGridItemOffsets(Rect outRect, int position, int column, int spanCount) { + if (mIncludeEdge) { + outRect.left = mHorizontalSpacing * (spanCount - column) / spanCount; + outRect.right = mHorizontalSpacing * (column + 1) / spanCount; + if (position < spanCount) { + outRect.top = mVerticalSpacing; + } + outRect.bottom = mVerticalSpacing; + } else { + outRect.left = mHorizontalSpacing * column / spanCount; + outRect.right = mHorizontalSpacing * (spanCount - 1 - column) / spanCount; + if (position >= spanCount) { + outRect.top = mVerticalSpacing; + } + } + } + + private final Rect mBounds = new Rect(); + + private void drawVertical(Canvas canvas, RecyclerView parent) { + canvas.save(); + final int left; + final int right; + + if (parent.getClipToPadding()) { + + left = isCusStartAndEnd ? mMarginStart : parent.getPaddingLeft(); + right = parent.getWidth() - (isCusStartAndEnd ? mMarginEnd : parent.getPaddingRight()); + canvas.clipRect(left, parent.getPaddingTop(), right, + parent.getHeight() - parent.getPaddingBottom()); + } else { + left = 0; + right = parent.getWidth(); + } + + final int childCount = parent.getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = parent.getChildAt(i); + parent.getDecoratedBoundsWithMargins(child, mBounds); + if (mIncludeEdge){ + if (i == 0){ + int top = mBounds.top; + int bottom = mVerticalSpacing; + canvas.save(); + canvas.clipRect(left, top, right, bottom); + canvas.drawColor(mColor); + canvas.restore(); + } + int bottom = mBounds.bottom + Math.round(child.getTranslationY()); + int top = bottom - mVerticalSpacing; + canvas.save(); + canvas.clipRect(left, top, right, bottom); + canvas.drawColor(mColor); + canvas.restore(); + }else{ + if (i > 0) { + int top = mBounds.top + Math.round(child.getTranslationY()); + int bottom = top + mVerticalSpacing; + canvas.save(); + canvas.clipRect(left, top, right, bottom); + canvas.drawColor(mColor); + canvas.restore(); + } + } + + } + canvas.restore(); + } + + private void drawHorizontal(Canvas canvas, RecyclerView parent) { + canvas.save(); + final int top; + final int bottom; + if (parent.getClipToPadding()) { + top = parent.getPaddingTop(); + bottom = parent.getHeight() - parent.getPaddingBottom(); + canvas.clipRect(parent.getPaddingLeft(), top, + parent.getWidth() - parent.getPaddingRight(), bottom); + } else { + top = 0; + bottom = parent.getHeight(); + } + + final int childCount = parent.getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = parent.getChildAt(i); + parent.getLayoutManager().getDecoratedBoundsWithMargins(child, mBounds); + if(mIncludeEdge){ + if (i == 0){ + int left = mBounds.left; + int right = mHorizontalSpacing; + canvas.save(); + canvas.clipRect(left, top, right, bottom); + canvas.drawColor(mColor); + canvas.restore(); + } + int right = mBounds.right + Math.round(child.getTranslationX()); + int left = right - mHorizontalSpacing; + canvas.save(); + canvas.clipRect(left, top, right, bottom); + canvas.drawColor(mColor); + canvas.restore(); + }else { + if (i > 0) { + int left = mBounds.left + Math.round(child.getTranslationX()); + int right = left + mHorizontalSpacing; + canvas.save(); + canvas.clipRect(left, top, right, bottom); + canvas.drawColor(mColor); + canvas.restore(); + } + } + } + canvas.restore(); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/DatingItemDecoration.java b/app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/DatingItemDecoration.java new file mode 100644 index 0000000..5577422 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/DatingItemDecoration.java @@ -0,0 +1,49 @@ +package com.chwl.app.ui.widget.recyclerview.decoration; + +import android.graphics.Rect; +import android.view.View; + +import androidx.recyclerview.widget.RecyclerView; + +import com.netease.nim.uikit.common.util.sys.ScreenUtil; + +import org.jetbrains.annotations.NotNull; + + +public class DatingItemDecoration extends RecyclerView.ItemDecoration { + + private final int spacingWidth = ScreenUtil.dip2px(48f); + private final int vSpacing = ScreenUtil.dip2px(5f); + + private boolean isRTL = false; + + public DatingItemDecoration(boolean isRTL){ + this.isRTL = isRTL; + } + + @Override + public void getItemOffsets(@NotNull Rect outRect, @NotNull View view, @NotNull RecyclerView parent, @NotNull RecyclerView.State state) { + super.getItemOffsets(outRect, view, parent, state); + int position = parent.getChildLayoutPosition(view); + if (position == 1 || position == 5) { + outRect.set(0, 0, spacingWidth / 2, 0); + } + if (position == 2 || position == 6) { + outRect.set(-spacingWidth / 2, 0, spacingWidth, 0); + } + if (position == 3 || position == 7) { + outRect.set(spacingWidth, 0, -spacingWidth / 2, 0); + } + if (position == 4 || position == 8) { + outRect.set(spacingWidth / 2, 0, 0, 0); + } + if (position == 5 || position == 6 || position == 7 || position == 8) { + outRect.top = vSpacing; + } + if (isRTL) { + int temp = outRect.right; + outRect.right = outRect.left; + outRect.left = temp; + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/GridSpacingItemDecoration.java b/app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/GridSpacingItemDecoration.java new file mode 100644 index 0000000..8dfda06 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/GridSpacingItemDecoration.java @@ -0,0 +1,45 @@ +package com.chwl.app.ui.widget.recyclerview.decoration; + +import android.content.Context; +import android.graphics.Rect; +import android.util.TypedValue; +import android.view.View; + +import androidx.recyclerview.widget.RecyclerView; + +/** + * 自适应任意列的 GridLayoutManager 的分割块 ItemDecoration + * + */ +public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration { + + private int spanCount; + private int dividerWidth; + private int dividerWidthTop; + private int dividerWidthBottom; + + /** + * @param spanCount gridLayoutManager 列数 + * @param dividerWidthDp 分割块宽高,单位:dp + */ + public GridSpacingItemDecoration(Context context, int spanCount, int dividerWidthDp) { + this.spanCount = spanCount; + this.dividerWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dividerWidthDp, context.getResources().getDisplayMetrics()); + this.dividerWidthTop = dividerWidth / 2; + this.dividerWidthBottom = dividerWidth - dividerWidthTop; + } + + @Override + public void getItemOffsets(Rect outRect, View child, RecyclerView parent, RecyclerView.State state) { + super.getItemOffsets(outRect, child, parent, state); + + int pos = parent.getChildAdapterPosition(child); + int column = (pos) % spanCount;// 计算这个child 处于第几列 + + outRect.top = dividerWidthTop; + outRect.bottom = dividerWidthBottom; + + outRect.left = (column * dividerWidth / spanCount); + outRect.right = dividerWidth - (column + 1) * dividerWidth / spanCount; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/GridSpacingItemNewDecoration.java b/app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/GridSpacingItemNewDecoration.java new file mode 100644 index 0000000..a0127dd --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/GridSpacingItemNewDecoration.java @@ -0,0 +1,99 @@ +package com.chwl.app.ui.widget.recyclerview.decoration; + +import android.graphics.Rect; +import android.view.View; + +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.StaggeredGridLayoutManager; + +import com.example.lib_utils.UiUtils; + +/** + * User: wukai + * Date: 2017/03/26 + * Description: 设置RecyclerView布局垂直和水平间隔 + */ +public class GridSpacingItemNewDecoration extends RecyclerView.ItemDecoration { + + private int mVerSpacing; + private int mHorSpacing; + private boolean mIncludeEdge; + private boolean mHasHeaderView; + private Boolean isRTL; + + public GridSpacingItemNewDecoration(int spacing, boolean includeEdge) { + this(spacing, spacing, includeEdge); + } + + public GridSpacingItemNewDecoration(int verSpacing, int horSpacing, boolean includeEdge) { + mVerSpacing = verSpacing; + mHorSpacing = horSpacing; + mIncludeEdge = includeEdge; + } + + public GridSpacingItemNewDecoration(int verSpacing, int horSpacing, boolean includeEdge, boolean hasHeaderView) { + mVerSpacing = verSpacing; + mHorSpacing = horSpacing; + mIncludeEdge = includeEdge; + mHasHeaderView = hasHeaderView; + } + + private int getSpanCount(RecyclerView parent) { + int spanCount = -1; + RecyclerView.LayoutManager layoutManager = parent.getLayoutManager(); + if (layoutManager instanceof GridLayoutManager) { + spanCount = ((GridLayoutManager) layoutManager).getSpanCount(); + } else if (layoutManager instanceof StaggeredGridLayoutManager) { + spanCount = ((StaggeredGridLayoutManager) layoutManager).getSpanCount(); + } + return spanCount; + } + + private int getSpanIndex(View view, RecyclerView parent) { + int spanIndex = parent.getChildAdapterPosition(view); + RecyclerView.LayoutManager layoutManager = parent.getLayoutManager(); + if (layoutManager instanceof StaggeredGridLayoutManager) { + StaggeredGridLayoutManager.LayoutParams layoutParams = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams(); + spanIndex = layoutParams.getSpanIndex(); + } + return spanIndex; + } + + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { + if (isRTL == null) { + isRTL = UiUtils.INSTANCE.isRtl(parent.getContext()); + } + int spanCount = getSpanCount(parent); + int position = parent.getChildAdapterPosition(view); // item position + int spanIndex = getSpanIndex(view, parent); + int column = spanIndex % spanCount; // item column + + if(position == 0 && mHasHeaderView) { + return; + } + + if (mIncludeEdge) { + outRect.left = mHorSpacing - column * mHorSpacing / spanCount; // spacing - column * ((1f / spanCount) * spacing) + outRect.right = (column + 1) * mHorSpacing / spanCount; // (column + 1) * ((1f / spanCount) * spacing) + + if (position < spanCount) { // top edge 第一行设置top + outRect.top = mVerSpacing; + } + outRect.bottom = mVerSpacing; // item bottom 每次都是设置bottom + } else { + outRect.left = column * mHorSpacing / spanCount; // column * ((1f / spanCount) * spacing) + outRect.right = mHorSpacing - (column + 1) * mHorSpacing / spanCount; // spacing - (column + 1) * ((1f / spanCount) * spacing) + if (position >= spanCount) { // 第二行开始设置top + outRect.top = mVerSpacing; // item top + } + } + if (isRTL) { + int right = outRect.right; + outRect.right = outRect.left; + outRect.left = right; + } + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/GridVItemDecoration.java b/app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/GridVItemDecoration.java new file mode 100644 index 0000000..f73cded --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/GridVItemDecoration.java @@ -0,0 +1,158 @@ +package com.chwl.app.ui.widget.recyclerview.decoration; + +import android.content.Context; +import android.graphics.Rect; +import android.view.View; + +import androidx.recyclerview.widget.RecyclerView; + +import com.netease.nim.uikit.common.util.log.LogUtil; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; + +import lombok.Setter; + +/** + * 垂直方向下的格子布局,通用的间隔设置 + * 只适合垂直布局 + * 单位均为dp + * create by lvzebiao @2020/1/2 + */ +public class GridVItemDecoration extends RecyclerView.ItemDecoration { + + private Context context; + + /** + * 水平的分割线 + */ + private int hDivider; + /** + * 垂直的分割线 + */ + private int vDivider; + + private int topDivider; + + private int bottomDivider; + + @Setter + private boolean needLeft; + + @Setter + private boolean needRight; + + @Setter + private boolean needTop; + + @Setter + private boolean needBottom; + + private int spanCount; + + public GridVItemDecoration(Context context, int divider, int spanCount) { + this.context = context; + setDivider(divider); + this.spanCount = spanCount; + } + + @Override + public void getItemOffsets(Rect outRect, View child, RecyclerView parent, RecyclerView.State state) { + super.getItemOffsets(outRect, child, parent, state); + + if (spanCount == 0) { + return; + } + + int pos = parent.getChildAdapterPosition(child); + + outRect.top = 0; + if (isLastRow(parent, pos)) { + outRect.bottom = 0; + } else { + outRect.bottom = hDivider; + } + + if (needTop && pos < spanCount) { + //给第0行添加分割线 + outRect.top = topDivider; + } + + if (needBottom && isLastRow(parent, pos)) { + //给最后一行添加分割线 + outRect.bottom = bottomDivider; + } + + int column = (pos) % spanCount;// 计算这个child 处于第几列 + + if (needLeft) { + if (needRight) { + outRect.left = vDivider - column * vDivider / spanCount; + outRect.right = vDivider / spanCount * (column + 1); + } else { + //这种情况就比较简单 + outRect.left = vDivider; + outRect.right = 0; + } + + } else { + if (needRight) { + outRect.left = 0; + outRect.right = vDivider; + } else { + outRect.left = (column * vDivider / spanCount); + outRect.right = vDivider - (column + 1) * vDivider / spanCount; + } + } + + } + + /** + * 判断是否是最后一行 + */ + private boolean isLastRow(RecyclerView parent, int pos) { + int size = parent.getAdapter().getItemCount(); + + int remainder = size % spanCount; + + LogUtil.print("remainder=" + remainder); + + int temp; + if (remainder == 0) { + temp = size - spanCount; + } else { + temp = size - remainder; + } + LogUtil.print("temp=" + temp); + return pos >= temp; + } + + private void setDivider(int divider) { + this.vDivider = UIUtil.dip2px(context, divider); + setHDivider(divider); + } + + public void setNeedMargin(boolean needMargin) { + needLeft = needTop = needRight = needBottom = needMargin; + } + + /** + * 此方法必须在 {@link #setDivider(int)} 之后调用 + */ + public void setHDivider(int hDivider) { + int px = UIUtil.dip2px(context, hDivider); + this.hDivider = px; + this.topDivider = px; + this.bottomDivider = px; + } + + public void setVDivider(int vDivider) { + this.vDivider = UIUtil.dip2px(context, vDivider); + } + + public void setTopDivider(int topDivider) { + this.topDivider = UIUtil.dip2px(context, topDivider); + } + + public void setBottomDivider(int bottomDivider) { + this.bottomDivider = UIUtil.dip2px(context, bottomDivider); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/HorizontalDecoration.java b/app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/HorizontalDecoration.java new file mode 100644 index 0000000..8202925 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/HorizontalDecoration.java @@ -0,0 +1,56 @@ +package com.chwl.app.ui.widget.recyclerview.decoration; + +import android.graphics.Rect; +import android.view.View; + +import androidx.recyclerview.widget.RecyclerView; + +import lombok.Setter; + +/** + * 水平的间隔 + * Created by lvzebiao on 2019/1/31. + */ + +public class HorizontalDecoration extends RecyclerView.ItemDecoration { + private int px; + /** + * 如果头需要则为ture + */ + private boolean first; + /** + * 如果尾需要则为ture + */ + private boolean last; + private int side = 0; + + @Setter + private int bottomPx; + + public HorizontalDecoration(int px, boolean first, boolean last) { + this.px = px; + this.first = first; + this.last = last; + this.bottomPx = px; + } + + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { + super.getItemOffsets(outRect, view, parent, state); + int position = parent.getChildAdapterPosition(view); + int top = 0, bottom = 0; + if (position == 0) { + if (first) { + top = px; + } + bottom = px; + } else if (position == parent.getAdapter().getItemCount() - 1) { + if (last) { + bottom = bottomPx; + } + } else { + bottom = px; + } + outRect.set(0, top, 0, bottom); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/SpacingDecoration.java b/app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/SpacingDecoration.java new file mode 100644 index 0000000..5b86481 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/SpacingDecoration.java @@ -0,0 +1,73 @@ +package com.chwl.app.ui.widget.recyclerview.decoration; + +import android.graphics.Rect; +import android.view.View; + +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.StaggeredGridLayoutManager; + +/** + * Created by huangjun on 2016/12/9. + */ +public class SpacingDecoration extends RecyclerView.ItemDecoration { + private int mHorizontalSpacing = 0; + private int mVerticalSpacing = 0; + private boolean mIncludeEdge = false; + + public SpacingDecoration(int hSpacing, int vSpacing, boolean includeEdge) { + mHorizontalSpacing = hSpacing; + mVerticalSpacing = vSpacing; + mIncludeEdge = includeEdge; + } + + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { + super.getItemOffsets(outRect, view, parent, state); + // Only handle the vertical situation + int position = parent.getChildAdapterPosition(view); + if (parent.getLayoutManager() instanceof GridLayoutManager) { + GridLayoutManager layoutManager = (GridLayoutManager) parent.getLayoutManager(); + int spanCount = layoutManager.getSpanCount(); + int column = position % spanCount; + getGridItemOffsets(outRect, position, column, spanCount); + } else if (parent.getLayoutManager() instanceof StaggeredGridLayoutManager) { + StaggeredGridLayoutManager layoutManager = (StaggeredGridLayoutManager) parent.getLayoutManager(); + int spanCount = layoutManager.getSpanCount(); + StaggeredGridLayoutManager.LayoutParams lp = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams(); + int column = lp.getSpanIndex(); + getGridItemOffsets(outRect, position, column, spanCount); + } else if (parent.getLayoutManager() instanceof LinearLayoutManager) { + outRect.left = mHorizontalSpacing; + outRect.right = mHorizontalSpacing; + if (mIncludeEdge) { + if (position == 0) { + outRect.top = mVerticalSpacing; + } + outRect.bottom = mVerticalSpacing; + } else { + if (position > 0) { + outRect.top = mVerticalSpacing; + } + } + } + } + + private void getGridItemOffsets(Rect outRect, int position, int column, int spanCount) { + if (mIncludeEdge) { + outRect.left = mHorizontalSpacing * (spanCount - column) / spanCount; + outRect.right = mHorizontalSpacing * (column + 1) / spanCount; + if (position < spanCount) { + outRect.top = mVerticalSpacing; + } + outRect.bottom = mVerticalSpacing; + } else { + outRect.left = mHorizontalSpacing * column / spanCount; + outRect.right = mHorizontalSpacing * (spanCount - 1 - column) / spanCount; + if (position >= spanCount) { + outRect.top = mVerticalSpacing; + } + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/TagItemDecoration.kt b/app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/TagItemDecoration.kt new file mode 100644 index 0000000..74be551 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/TagItemDecoration.kt @@ -0,0 +1,42 @@ +package com.chwl.app.ui.widget.recyclerview.decoration + +import android.graphics.Rect +import android.view.View +import androidx.recyclerview.widget.RecyclerView +import androidx.recyclerview.widget.RecyclerView.ItemDecoration +import com.google.android.flexbox.FlexboxLayoutManager + +/** + * 标签列表的ItemDecoration + * 使用FlexboxLayoutManager的RecyclerView的ItemDecoration + * @param verSpacing 纵向间距 + * @param horSpacing 横向间距 + */ +class TagItemDecoration(private val verSpacing: Int, private val horSpacing: Int) : ItemDecoration() { + private var mOnLineListener: ((Int, Int, Int) -> Unit)? = null + private var mLineCount = 0 + private var mLineFirstPosition = 0 + + override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) { + super.getItemOffsets(outRect, view, parent, state) + val currentPosition = parent.getChildAdapterPosition(view) + outRect.left = horSpacing / 2 + outRect.right = horSpacing / 2 + outRect.top = verSpacing + + + if (mOnLineListener != null) { + (parent.layoutManager as? FlexboxLayoutManager)?.let { + if (mLineCount != it.flexLines.size) { + mLineCount = it.flexLines.size + mLineFirstPosition = currentPosition + } + mOnLineListener?.invoke(mLineCount, currentPosition, mLineFirstPosition) + } + } + } + + fun setOnLineListener(body: (Int, Int, Int) -> Unit) { + this.mOnLineListener = body + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/VerticalDecoration.java b/app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/VerticalDecoration.java new file mode 100644 index 0000000..389abcc --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/recyclerview/decoration/VerticalDecoration.java @@ -0,0 +1,56 @@ +package com.chwl.app.ui.widget.recyclerview.decoration; + +import android.graphics.Rect; +import android.view.View; + +import androidx.recyclerview.widget.RecyclerView; + +import com.example.lib_utils.UiUtils; + +/** + * Created by lvzebiao on 2018/9/27. + */ + +public class VerticalDecoration extends RecyclerView.ItemDecoration { + + private int px; + /**如果头需要则为ture*/ + private boolean first; + /**如果尾需要则为ture*/ + private boolean last; + + private Boolean isRTL; + + public VerticalDecoration(int px, boolean first, boolean last) { + this.px = px; + this.first = first; + this.last = last; + } + + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { + super.getItemOffsets(outRect, view, parent, state); + if (isRTL == null) { + isRTL = UiUtils.INSTANCE.isRtl(parent.getContext()); + } + int position = parent.getChildAdapterPosition(view); + int left = 0, right = 0; + if (position == 0) { + if (first) { + left = px; + } + right = px; + } else if (position == parent.getAdapter().getItemCount() - 1) { + if (last) { + right = px; + } + } else { + right = px; + } + if (isRTL) { + outRect.set(right, 0, left, 0); + } else { + outRect.set(left, 0, right, 0); + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/recyclerview/layoutmanager/BoosRoomLayoutManager.kt b/app/src/main/java/com/chwl/app/ui/widget/recyclerview/layoutmanager/BoosRoomLayoutManager.kt new file mode 100644 index 0000000..bb4977b --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/recyclerview/layoutmanager/BoosRoomLayoutManager.kt @@ -0,0 +1,302 @@ +package com.chwl.app.ui.widget.recyclerview.layoutmanager + +import android.content.Context +import android.util.AttributeSet +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import androidx.recyclerview.widget.StaggeredGridLayoutManager +import com.chwl.core.utils.myutil.MyUtil +import com.chwl.library.common.util.doLog +import com.chwl.library.common.util.doLogE + +/** + * 19 麦 管理器 + */ +class BoosRoomLayoutManager : StaggeredGridLayoutManager { + + var mSpanCount = 5 + var mAppWidth = -1 + + constructor( + context: Context?, + attrs: AttributeSet?, + defStyleAttr: Int, + defStyleRes: Int + ) : super(context, attrs, defStyleAttr, defStyleRes) + + + constructor(spanCount: Int = 5): super(spanCount, RecyclerView.VERTICAL){ + mSpanCount = spanCount + } + + constructor(spanCount: Int = 5,appWidth: Int = MyUtil.mAppWidth): super(spanCount, RecyclerView.VERTICAL){ + mSpanCount = spanCount + mAppWidth = appWidth + } + + + // 19 麦布局 + override fun onLayoutChildren(recycler: RecyclerView.Recycler, state: RecyclerView.State) { + try { + detachAndScrapAttachedViews(recycler) + "onLayoutChildren 开始绘制 麦位".doLog() + + val appWidth = if (mAppWidth != -1) mAppWidth else MyUtil.mAppWidth + val width = (appWidth / mSpanCount).toInt() + + if (itemCount == 0) return + + var offsetX = 0 //横向 X轴的偏移量 + var offsetY = 0 + + + // 8 17 是特殊 + + for (i in 0 until itemCount) { + val view = recycler.getViewForPosition(i) + addView(view) + + measureChildWithMargins(view, 0, 0) + + val viewWidth = width + var viewHeight = getDecoratedMeasuredHeight(view) + if (viewHeight == 0) viewHeight = width + +// view.setViewWH(width = viewWidth, isDP = false) + + if (i == 14) { + offsetX = 0 + "新的一行".doLog() + }else if (i != 15 && i % mSpanCount == 0) { + offsetX = 0 + "新的一行".doLog() + } + + + + val row = getRow(i) + + + offsetY = viewHeight * (row-1) + + "pos = $i row = $row viewWidth = $viewWidth viewHeight = $viewHeight left = $offsetX top = $offsetY right = ${offsetX + viewWidth} bottom : ${offsetY+viewHeight} ".doLog() + + if (i == 7) { + layoutDecorated(view, offsetX, offsetY+(viewHeight/10), offsetX + viewWidth, offsetY+viewHeight+(viewHeight/10)) + }else if (i == 12 || i == 13) { + layoutDecorated(view, offsetX+viewWidth, offsetY, offsetX + viewWidth+viewWidth, offsetY+viewHeight) + } else { + layoutDecorated(view, offsetX, offsetY, offsetX + viewWidth, offsetY+viewHeight) + } + + offsetX += viewWidth + + } + } catch (e: Exception) { + "19麦布局管理器 发生严重错误 onLayoutChildren e = ${e.message}".doLogE() + } + } + + + + + override fun generateDefaultLayoutParams(): RecyclerView.LayoutParams { + return RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT) + } + + + + + + //横轴排序 +// override fun onLayoutChildren(recycler: RecyclerView.Recycler, state: RecyclerView.State) { +// detachAndScrapAttachedViews(recycler) +// +// +// if (itemCount == 0) return +// +// var offsetX = 0 //横向 X轴的偏移量 +// var offsetY = 0 +// +// for (i in 0 until itemCount) { +// val view = recycler.getViewForPosition(i) +// addView(view) +// +// measureChildWithMargins(view, 0, 0) +// +// val viewWidth = getDecoratedMeasuredWidth(view) +// val viewHeight = getDecoratedMeasuredHeight(view) +// +// +// " viewWidth = $viewWidth viewHeight = $viewHeight left = $offsetX top = $offsetY right = ${offsetX + viewWidth} bottom : ${viewHeight*(i+1)} ".doLog() +// +// layoutDecorated(view, offsetX, offsetY, offsetX + viewWidth, viewHeight*(i+1)) +// +// offsetX += viewWidth + 10 +// offsetY = viewHeight*(i+1) +// +// } +// } + + //梯形排序 +// override fun onLayoutChildren(recycler: RecyclerView.Recycler, state: RecyclerView.State) { +// detachAndScrapAttachedViews(recycler) +// +// +// if (itemCount == 0) return +// +// var offsetX = 0 //横向 X轴的偏移量 +// var offsetY = 0 +// +// var itemWidth = 50 +// var itemHeight = 50 +// +// for (i in 0 until itemCount) { +// val view = recycler.getViewForPosition(i) +// addView(view) +// +// +// val currentItemWidth = (itemWidth * 1.5).toInt() +// val currentItemHeight = (itemHeight * 1.5).toInt() +// +// val widthSpec = View.MeasureSpec.makeMeasureSpec(currentItemWidth,View.MeasureSpec.EXACTLY) +// val heightSpec = View.MeasureSpec.makeMeasureSpec(currentItemHeight,View.MeasureSpec.EXACTLY) +// +// +// measureChildWithMargins(view, widthSpec, heightSpec) +// +// val viewWidth = currentItemWidth +// val viewHeight = currentItemHeight +// +// +// " viewWidth = $viewWidth viewHeight = $viewHeight left = $offsetX top = $offsetY right = ${offsetX + viewWidth} bottom : ${offsetY+viewHeight} ".doLog() +// +// layoutDecorated(view, offsetX, offsetY, offsetX + viewWidth, offsetY+viewHeight) +// +// offsetX += viewWidth + 10 +// offsetY = offsetY+viewHeight +// +// itemWidth = currentItemWidth +// itemHeight = currentItemHeight +// +// } +// } + + + + // 网格排序 - 均分 +// override fun onLayoutChildren(recycler: RecyclerView.Recycler, state: RecyclerView.State) { +// detachAndScrapAttachedViews(recycler) +// "onLayoutChildren 开始绘制 麦位".doLog() +// +// val width = (MyUtil.mAppWidth / mSpanCount).toInt() +// +// if (itemCount == 0) return +// +// var offsetX = 0 //横向 X轴的偏移量 +// var offsetY = 0 +// +// +// // 8 17 是特殊 +// +// for (i in 0 until itemCount) { +// val view = recycler.getViewForPosition(i) +// addView(view) +// +// measureChildWithMargins(view, 0, 0) +// +// val viewWidth = width +// var viewHeight = getDecoratedMeasuredHeight(view) +// if (viewHeight == 0) viewHeight = width +// +// if (i % mSpanCount == 0) { +// offsetX = 0 +// "新的一行".doLog() +// } +// +// val posRowColumns = MyUtil.getPosRowColumns(i, mSpanCount) +// val row = posRowColumns[0] +// val col = posRowColumns[1] +// +// offsetY = viewHeight * (row-1) +// +// "pos = $i row = $row col = $col viewWidth = $viewWidth viewHeight = $viewHeight left = $offsetX top = $offsetY right = ${offsetX + viewWidth} bottom : ${offsetY+viewHeight} appWidth=${MyUtil.mAppWidth}".doLog() +// +// layoutDecorated(view, offsetX, offsetY, offsetX + viewWidth, offsetY+viewHeight) +// +// offsetX += viewWidth +// +// } +// } + +// //网格布局 - 不均分 +// override fun onLayoutChildren(recycler: RecyclerView.Recycler, state: RecyclerView.State) { +// detachAndScrapAttachedViews(recycler) +// +// +// val width = (MyUtil.mAppWidth / mSpanCount).toInt() +// +// if (itemCount == 0) return +// +// var offsetX = 0 //横向 X轴的偏移量 +// var offsetY = 0 +// +// for (i in 0 until itemCount) { +// val view = recycler.getViewForPosition(i) +// addView(view) +// +// measureChildWithMargins(view, 0, 0) +// +// val viewWidth = getDecoratedMeasuredWidth(view) +// var viewHeight = getDecoratedMeasuredHeight(view) +// +// if (i % mSpanCount == 0) { +// offsetX = 0 +// "新的一行".doLog() +// } +// +// val posRowColumns = MyUtil.getPosRowColumns(i, mSpanCount) +// val row = posRowColumns[0] +// val col = posRowColumns[1] +// +// offsetY = viewHeight * (row-1) +// +// "pos = $i row = $row col = $col viewWidth = $viewWidth viewHeight = $viewHeight left = $offsetX top = $offsetY right = ${offsetX + viewWidth} bottom : ${offsetY+viewHeight} ".doLog() +// +// layoutDecorated(view, offsetX, offsetY, offsetX + viewWidth, offsetY+viewHeight) +// +// offsetX += viewWidth +// +// } +// } + + + + + override fun onScrollStateChanged(state: Int) { + try { + super.onScrollStateChanged(state) + } catch (e: Exception) { + "19麦布局管理器 发生严重错误 onScrollStateChanged e = ${e.message}".doLogE() + } + } + + private fun getRow(pos:Int) :Int { + return if (pos < 5){ + 1 + } else if (pos == 5 || pos == 6 || pos == 8 || pos == 9) { + 2 + } else if (pos == 10 || pos == 11 || pos == 12 || pos == 13) { + 3 + }else if (pos>13) { + 4 + } else { + 2 + } + } + + + + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/widget/recyclerview/layoutmanager/FullyGridLayoutManager.java b/app/src/main/java/com/chwl/app/ui/widget/recyclerview/layoutmanager/FullyGridLayoutManager.java new file mode 100644 index 0000000..539ab15 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/recyclerview/layoutmanager/FullyGridLayoutManager.java @@ -0,0 +1,102 @@ +package com.chwl.app.ui.widget.recyclerview.layoutmanager; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; + +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +/** + * Created by jack on 2018/4/16. + */ + +public class FullyGridLayoutManager extends GridLayoutManager { + public FullyGridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + public FullyGridLayoutManager(Context context, int spanCount) { + super(context, spanCount); + } + + public FullyGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) { + super(context, spanCount, orientation, reverseLayout); + } + + private int[] mMeasuredDimension = new int[2]; + + @Override + public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) { + final int widthMode = View.MeasureSpec.getMode(widthSpec); + final int heightMode = View.MeasureSpec.getMode(heightSpec); + final int widthSize = View.MeasureSpec.getSize(widthSpec); + final int heightSize = View.MeasureSpec.getSize(heightSpec); + + int width = 0; + int height = 0; + int count = getItemCount(); + int span = getSpanCount(); + for (int i = 0; i < count; i++) { + measureScrapChild(recycler, i, + View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), + View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), + mMeasuredDimension); + + if (getOrientation() == HORIZONTAL) { + if (i % span == 0) { + width = width + mMeasuredDimension[0]; + } + if (i == 0) { + height = mMeasuredDimension[1]; + } + } else { + if (i % span == 0) { + height = height + mMeasuredDimension[1]; + } + if (i == 0) { + width = mMeasuredDimension[0]; + } + } + } + + switch (widthMode) { + case View.MeasureSpec.EXACTLY: + width = widthSize; + case View.MeasureSpec.AT_MOST: + case View.MeasureSpec.UNSPECIFIED: + } + + switch (heightMode) { + case View.MeasureSpec.EXACTLY: + height = heightSize; + case View.MeasureSpec.AT_MOST: + case View.MeasureSpec.UNSPECIFIED: + } + + setMeasuredDimension(width, height); + } + + private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec, + int heightSpec, int[] measuredDimension) { + if (getItemCount() > 0 && position < getItemCount()) { + try { + View view = recycler.getViewForPosition(position);//fix 动态添加时报IndexOutOfBoundsException + if (view != null) { + RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams(); + int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec, + getPaddingLeft() + getPaddingRight(), p.width); + int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec, + getPaddingTop() + getPaddingBottom(), p.height); + view.measure(childWidthSpec, childHeightSpec); + measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin; + measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin; + recycler.recycleView(view); + } + } catch (Exception e) { +// e.printStackTrace(); + } + } + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/recyclerview/layoutmanager/FullyLinearLayoutManager.java b/app/src/main/java/com/chwl/app/ui/widget/recyclerview/layoutmanager/FullyLinearLayoutManager.java new file mode 100644 index 0000000..beb8209 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/recyclerview/layoutmanager/FullyLinearLayoutManager.java @@ -0,0 +1,99 @@ +package com.chwl.app.ui.widget.recyclerview.layoutmanager; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + + +public class FullyLinearLayoutManager extends LinearLayoutManager { + public FullyLinearLayoutManager(Context context) { + super(context); + } + + public FullyLinearLayoutManager(Context context, int orientation, boolean reverseLayout) { + super(context, orientation, reverseLayout); + } + + public FullyLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + private int[] mMeasuredDimension = new int[2]; + + @Override + public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, + int widthSpec, int heightSpec) { + + final int widthMode = View.MeasureSpec.getMode(widthSpec); + final int heightMode = View.MeasureSpec.getMode(heightSpec); + final int widthSize = View.MeasureSpec.getSize(widthSpec); + final int heightSize = View.MeasureSpec.getSize(heightSpec); + + int width = 0; + int height = 0; + for (int i = 0; i < getItemCount(); i++) { + measureScrapChild(recycler, i, + View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), + View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), + mMeasuredDimension); + + if (getOrientation() == HORIZONTAL) { + width = width + mMeasuredDimension[0]; + if (i == 0) { + height = mMeasuredDimension[1]; + } + } else { + height = height + mMeasuredDimension[1]; + if (i == 0) { + width = mMeasuredDimension[0]; + } + } + } + switch (widthMode) { + case View.MeasureSpec.EXACTLY: + width = widthSize; + case View.MeasureSpec.AT_MOST: + case View.MeasureSpec.UNSPECIFIED: + } + + switch (heightMode) { + case View.MeasureSpec.EXACTLY: + height = heightSize; + case View.MeasureSpec.AT_MOST: + case View.MeasureSpec.UNSPECIFIED: + } + + setMeasuredDimension(width, height); + } + + private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec, + int heightSpec, int[] measuredDimension) { + if (getItemCount() > 0 && position < getItemCount()) { + try { + View view = recycler.getViewForPosition(position);//fix 动态添加时报IndexOutOfBoundsException + if (view != null) { + RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams(); + + int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec, + getPaddingLeft() + getPaddingRight(), p.width); + + int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec, + getPaddingTop() + getPaddingBottom(), p.height); + + view.measure(childWidthSpec, childHeightSpec); + measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin; + measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin; + recycler.recycleView(view); + } + } catch (Exception e) { +// e.printStackTrace(); + } finally { + } + } + + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/HintView.java b/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/HintView.java new file mode 100644 index 0000000..3807c06 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/HintView.java @@ -0,0 +1,10 @@ +package com.chwl.app.ui.widget.rollviewpager; + + +public interface HintView { + + void initView(int length, int gravity); + + void setCurrent(int current); +} + diff --git a/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/OnRollViewClickListener.java b/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/OnRollViewClickListener.java new file mode 100644 index 0000000..6c1066b --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/OnRollViewClickListener.java @@ -0,0 +1,8 @@ +package com.chwl.app.ui.widget.rollviewpager; + +/** + * Created by zhuchenxi on 16/8/4. + */ +public interface OnRollViewClickListener { + void onItemClick(int position); +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/RollPagerView.java b/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/RollPagerView.java new file mode 100644 index 0000000..8eaf171 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/RollPagerView.java @@ -0,0 +1,448 @@ +package com.chwl.app.ui.widget.rollviewpager; + +import android.content.Context; +import android.content.res.TypedArray; +import android.database.DataSetObserver; +import android.graphics.Color; +import android.graphics.drawable.GradientDrawable; +import android.os.Handler; +import android.os.Message; +import android.util.AttributeSet; +import android.view.GestureDetector; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.Interpolator; +import android.widget.RelativeLayout; +import android.widget.Scroller; + +import androidx.annotation.Nullable; +import androidx.viewpager.widget.PagerAdapter; +import androidx.viewpager.widget.ViewPager; +import androidx.viewpager.widget.ViewPager.OnPageChangeListener; + +import com.chwl.app.R; +import com.chwl.app.ui.widget.rollviewpager.adapter.LoopPagerAdapter; +import com.chwl.app.ui.widget.rollviewpager.hintview.ColorPointHintView; + +import java.lang.ref.WeakReference; +import java.lang.reflect.Field; +import java.util.Timer; +import java.util.TimerTask; + +/** + * 支持轮播和提示的的viewpager + */ +public class RollPagerView extends RelativeLayout implements OnPageChangeListener { + + private ViewPager mViewPager; + private PagerAdapter mAdapter; + private OnRollViewClickListener mOnRollViewClickListener; + private GestureDetector mGestureDetector; + + private long mRecentTouchTime; + //播放延迟 + private int delay; + + //hint位置 + private int gravity; + + //hint颜色 + private int color; + + //hint透明度 + private int alpha; + + private int paddingLeft; + private int paddingTop; + private int paddingRight; + private int paddingBottom; + + private View mHintView; + private Timer timer; + + private JPagerObserver jPagerObserver; + + public interface HintViewDelegate { + void setCurrentPosition(int position, HintView hintView); + + void initView(int length, int gravity, HintView hintView); + } + + private HintViewDelegate mHintViewDelegate = new HintViewDelegate() { + @Override + public void setCurrentPosition(int position, HintView hintView) { + if (hintView != null) + hintView.setCurrent(position); + } + + @Override + public void initView(int length, int gravity, HintView hintView) { + if (hintView != null) + hintView.initView(length, gravity); + } + }; + + + public RollPagerView(Context context) { + this(context, null); + } + + public RollPagerView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + + } + + public RollPagerView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + initView(attrs); + } + + /** + * 读取提示形式 和 提示位置 和 播放延迟 + * + * @param attrs + */ + private void initView(AttributeSet attrs) { + if (mViewPager != null) { + removeView(mViewPager); + } + + TypedArray type = getContext().obtainStyledAttributes(attrs, R.styleable.RollViewPager); + gravity = type.getInteger(R.styleable.RollViewPager_rollviewpager_hint_gravity, 1); + delay = type.getInt(R.styleable.RollViewPager_rollviewpager_play_delay, 0); + color = type.getColor(R.styleable.RollViewPager_rollviewpager_hint_color, Color.BLACK); + alpha = type.getInt(R.styleable.RollViewPager_rollviewpager_hint_alpha, 0); + paddingLeft = (int) type.getDimension(R.styleable.RollViewPager_rollviewpager_hint_paddingLeft, 0); + paddingRight = (int) type.getDimension(R.styleable.RollViewPager_rollviewpager_hint_paddingRight, 0); + paddingTop = (int) type.getDimension(R.styleable.RollViewPager_rollviewpager_hint_paddingTop, 0); + paddingBottom = (int) type.getDimension(R.styleable.RollViewPager_rollviewpager_hint_paddingBottom, Util.dip2px(getContext(), 4)); + + mViewPager = new ViewPager(getContext()); + mViewPager.setId(R.id.viewpager_inner); + mViewPager.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); + addView(mViewPager); + type.recycle(); + initHint(new ColorPointHintView(getContext(), Color.parseColor("#9168FA"), Color.parseColor("#99B3B3C3"))); + //手势处理 + mGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() { + @Override + public boolean onSingleTapUp(MotionEvent e) { + if (mOnRollViewClickListener != null) { + if (mAdapter instanceof LoopPagerAdapter) {//原谅我写了这么丑的代码 + mOnRollViewClickListener.onItemClick(mViewPager.getCurrentItem() % ((LoopPagerAdapter) mAdapter).getRealCount()); + } else { + mOnRollViewClickListener.onItemClick(mViewPager.getCurrentItem()); + } + } + return super.onSingleTapUp(e); + } + }); + } + + private final static class TimeTaskHandler extends Handler { + private WeakReference mRollPagerViewWeakReference; + + public TimeTaskHandler(RollPagerView rollPagerView) { + this.mRollPagerViewWeakReference = new WeakReference<>(rollPagerView); + } + + @Override + public void handleMessage(Message msg) { + RollPagerView rollPagerView = mRollPagerViewWeakReference.get(); + if (rollPagerView == null) return; + int cur = rollPagerView.getViewPager().getCurrentItem() + 1; + if (cur >= rollPagerView.mAdapter.getCount()) { + cur = 0; + } + rollPagerView.getViewPager().setCurrentItem(cur); + rollPagerView.mHintViewDelegate.setCurrentPosition(cur, (HintView) rollPagerView.mHintView); + if (rollPagerView.mAdapter.getCount() <= 1) rollPagerView.stopPlay(); + + } + } + + private TimeTaskHandler mHandler = new TimeTaskHandler(this); + + private static class WeakTimerTask extends TimerTask { + private WeakReference mRollPagerViewWeakReference; + + public WeakTimerTask(RollPagerView mRollPagerView) { + this.mRollPagerViewWeakReference = new WeakReference<>(mRollPagerView); + } + + @Override + public void run() { + RollPagerView rollPagerView = mRollPagerViewWeakReference.get(); + if (rollPagerView != null) { + if (rollPagerView.isShown() && System.currentTimeMillis() - rollPagerView.mRecentTouchTime > rollPagerView.delay) { + rollPagerView.mHandler.sendEmptyMessage(0); + } + } else { + cancel(); + } + } + } + + /** + * 开始播放 + * 仅当view正在显示 且 触摸等待时间过后 播放 + */ + private void startPlay() { + if (delay <= 0 || mAdapter == null || mAdapter.getCount() <= 1) { + return; + } + if (timer != null) { + timer.cancel(); + } + timer = new Timer(); + //用一个timer定时设置当前项为下一项 + timer.schedule(new WeakTimerTask(this), delay, delay); + } + + private void stopPlay() { + if (timer != null) { + timer.cancel(); + timer = null; + } + } + + + public void setHintViewDelegate(HintViewDelegate delegate) { + this.mHintViewDelegate = delegate; + } + + + private void initHint(HintView hintview) { + if (mHintView != null) { + removeView(mHintView); + } + + if (hintview == null) { + return; + } + + mHintView = (View) hintview; + loadHintView(); + } + + /** + * 加载hintview的容器 + */ + private void loadHintView() { + addView(mHintView); + mHintView.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom); + LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); + lp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM); + ((View) mHintView).setLayoutParams(lp); + + GradientDrawable gd = new GradientDrawable(); + gd.setColor(color); + gd.setAlpha(alpha); + mHintView.setBackgroundDrawable(gd); + + mHintViewDelegate.initView(mAdapter == null ? 0 : mAdapter.getCount(), gravity, (HintView) mHintView); + } + + + /** + * 设置viewager滑动动画持续时间 + * + * @param during + */ + public void setAnimationDurtion(final int during) { + try { + // viePager平移动画事件 + Field mField = ViewPager.class.getDeclaredField("mScroller"); + mField.setAccessible(true); + Scroller mScroller = new Scroller(getContext(), + // 动画效果与ViewPager的一致 + new Interpolator() { + public float getInterpolation(float t) { + t -= 1.0f; + return t * t * t * t * t + 1.0f; + } + }) { + + @Override + public void startScroll(int startX, int startY, int dx, + int dy, int duration) { + // 如果手工滚动,则加速滚动 + if (System.currentTimeMillis() - mRecentTouchTime > delay) { + duration = during; + } else { + duration /= 2; + } + super.startScroll(startX, startY, dx, dy, duration); + } + + @Override + public void startScroll(int startX, int startY, int dx, + int dy) { + super.startScroll(startX, startY, dx, dy, during); + } + }; + mField.set(mViewPager, mScroller); + } catch (NoSuchFieldException e) { + e.printStackTrace(); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + + public void setPlayDelay(int delay) { + this.delay = delay; + startPlay(); + } + + + public void pause() { + stopPlay(); + } + + public void resume() { + startPlay(); + } + + public boolean isPlaying() { + return timer != null; + } + + + public void setOnItemClickListener(OnRollViewClickListener listener) { + this.mOnRollViewClickListener = listener; + } + + /** + * 设置提示view的位置 + */ + public void setHintPadding(int left, int top, int right, int bottom) { + paddingLeft = left; + paddingTop = top; + paddingRight = right; + paddingBottom = bottom; + mHintView.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom); + } + + /** + * 设置提示view的透明度 + * + * @param alpha 0为全透明 255为实心 + */ + public void setHintAlpha(int alpha) { + this.alpha = alpha; + initHint((HintView) mHintView); + } + + /** + * 支持自定义hintview + * 只需new一个实现HintView的View传进来 + * 会自动将你的view添加到本View里面。重新设置LayoutParams。 + * + * @param hintview + */ + public void setHintView(HintView hintview) { + + if (mHintView != null) { + removeView(mHintView); + } + this.mHintView = (View) hintview; + if (hintview != null) { + initHint(hintview); + } + } + + /** + * 取真正的Viewpager + * + * @return + */ + public ViewPager getViewPager() { + return mViewPager; + } + + /** + * 设置Adapter + * + * @param adapter + */ + public void setAdapter(PagerAdapter adapter) { + if (mAdapter != null && jPagerObserver != null) { + mAdapter.unregisterDataSetObserver(jPagerObserver); + stopPlay(); + } + adapter.registerDataSetObserver(jPagerObserver = new JPagerObserver()); + mViewPager.setAdapter(adapter); + mViewPager.clearOnPageChangeListeners(); + mViewPager.addOnPageChangeListener(this); + mAdapter = adapter; + dataSetChanged(); + } + + @Nullable + public PagerAdapter getAdapter(){ + return mAdapter; + } + + /** + * 用来实现adapter的notifyDataSetChanged通知HintView变化 + */ + private class JPagerObserver extends DataSetObserver { + @Override + public void onChanged() { + dataSetChanged(); + } + + @Override + public void onInvalidated() { + dataSetChanged(); + } + } + + private void dataSetChanged() { + if (mHintView != null) { + mHintViewDelegate.initView(mAdapter.getCount(), gravity, (HintView) mHintView); + mHintViewDelegate.setCurrentPosition(mViewPager.getCurrentItem(), (HintView) mHintView); + } + startPlay(); + } + + /** + * 为了实现触摸时和过后一定时间内不滑动,这里拦截 + * + * @param ev + * @return + */ + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + mRecentTouchTime = System.currentTimeMillis(); + mGestureDetector.onTouchEvent(ev); + return super.dispatchTouchEvent(ev); + } + + @Override + public void onPageScrollStateChanged(int arg0) { + + } + + @Override + public void onPageScrolled(int arg0, float arg1, int arg2) { + + } + + @Override + public void onPageSelected(int arg0) { + mHintViewDelegate.setCurrentPosition(arg0, (HintView) mHintView); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + if (getChildCount() == 0 && getViewPager().getCurrentItem() == 0) { + return false; + } + return super.onInterceptTouchEvent(ev); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/Util.java b/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/Util.java new file mode 100644 index 0000000..6360aad --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/Util.java @@ -0,0 +1,24 @@ +package com.chwl.app.ui.widget.rollviewpager; + +import android.content.Context; + +public class Util { + /** + * dpתpx + * + */ + public static int dip2px(Context ctx,float dpValue) { + final float scale = ctx.getResources().getDisplayMetrics().density; + return (int) (dpValue * scale + 0.5f); + } + + + /** + * pxתdp + */ + public static int px2dip(Context ctx,float pxValue) { + final float scale = ctx.getResources().getDisplayMetrics().density; + return (int) (pxValue / scale + 0.5f); + } + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/adapter/DynamicPagerAdapter.java b/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/adapter/DynamicPagerAdapter.java new file mode 100644 index 0000000..c6d5866 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/adapter/DynamicPagerAdapter.java @@ -0,0 +1,43 @@ +package com.chwl.app.ui.widget.rollviewpager.adapter; + +import android.view.View; +import android.view.ViewGroup; + +import androidx.fragment.app.FragmentPagerAdapter; +import androidx.viewpager.widget.PagerAdapter; + + +/** + * 动态管理的Adapter。概念参照{@link FragmentPagerAdapter} + * 每次都会创建新view,销毁旧View。节省内存消耗性能 + * + *

Subclasses only need to implement {@link #getView(ViewGroup,int)} + * and {@link #getCount()} to have a working adapter. + * + */ +public abstract class DynamicPagerAdapter extends PagerAdapter { + + @Override + public boolean isViewFromObject(View arg0, Object arg1) { + return arg0==arg1; + } + + @Override + public void destroyItem(ViewGroup container, int position, Object object) { + container.removeView((View) object); + } + + @Override + public int getItemPosition(Object object) { + return super.getItemPosition(object); + } + + @Override + public Object instantiateItem(ViewGroup container, int position) { + View itemView = getView(container,position); + container.addView(itemView); + return itemView; + } + public abstract View getView(ViewGroup container, int position); + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/adapter/LoopPagerAdapter.java b/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/adapter/LoopPagerAdapter.java new file mode 100644 index 0000000..36fcf69 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/adapter/LoopPagerAdapter.java @@ -0,0 +1,121 @@ +package com.chwl.app.ui.widget.rollviewpager.adapter; + +import android.database.DataSetObserver; +import android.view.View; +import android.view.ViewGroup; + +import androidx.viewpager.widget.PagerAdapter; +import androidx.viewpager.widget.ViewPager; + +import com.chwl.app.ui.widget.rollviewpager.HintView; +import com.chwl.app.ui.widget.rollviewpager.RollPagerView; + +import java.lang.reflect.Field; +import java.util.ArrayList; + +/** + * Created by Mr.Jude on 2016/1/9. + */ +public abstract class LoopPagerAdapter extends PagerAdapter { + private RollPagerView mViewPager; + + private ArrayList mViewList = new ArrayList<>(); + + private class LoopHintViewDelegate implements RollPagerView.HintViewDelegate{ + @Override + public void setCurrentPosition(int position, HintView hintView) { + if (hintView!=null&&getRealCount()>0) + hintView.setCurrent(position%getRealCount()); + } + + @Override + public void initView(int length, int gravity, HintView hintView) { + if (hintView!=null) + hintView.initView(getRealCount(),gravity); + } + } + + @Override + public void notifyDataSetChanged() { + mViewList.clear(); + initPosition(); + super.notifyDataSetChanged(); + } + + @Override + public int getItemPosition(Object object) { + return POSITION_NONE; + } + + @Override + public void registerDataSetObserver(DataSetObserver observer) { + super.registerDataSetObserver(observer); + initPosition(); + } + + private void initPosition(){ + if (mViewPager.getViewPager().getCurrentItem() == 0&&getRealCount()>0){ + int half = Integer.MAX_VALUE/2; + int start = half - half%getRealCount(); + setCurrent(start); + } + } + + private void setCurrent(int index){ + try { + Field field = ViewPager.class.getDeclaredField("mCurItem"); + field.setAccessible(true); + field.set(mViewPager.getViewPager(),index); + } catch (NoSuchFieldException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + + public LoopPagerAdapter(RollPagerView viewPager){ + this.mViewPager = viewPager; + viewPager.setHintViewDelegate(new LoopHintViewDelegate()); + } + + @Override + public boolean isViewFromObject(View arg0, Object arg1) { + return arg0==arg1; + } + + @Override + public void destroyItem(ViewGroup container, int position, Object object) { + container.removeView((View) object); + } + + @Override + public Object instantiateItem(ViewGroup container, int position) { + int realPosition = position%getRealCount(); + View itemView = findViewByPosition(container,realPosition); + container.addView(itemView); + return itemView; + } + + + private View findViewByPosition(ViewGroup container,int position){ + for (View view : mViewList) { + if (((int)view.getTag()) == position&&view.getParent()==null){ + return view; + } + } + View view = getView(container,position); + view.setTag(position); + mViewList.add(view); + return view; + } + + public abstract View getView(ViewGroup container, int position); + + @Deprecated + @Override + public final int getCount() { + return getRealCount()<=0?getRealCount():Integer.MAX_VALUE; + } + + public abstract int getRealCount(); +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/adapter/StaticPagerAdapter.java b/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/adapter/StaticPagerAdapter.java new file mode 100644 index 0000000..4d6a6b8 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/adapter/StaticPagerAdapter.java @@ -0,0 +1,70 @@ +package com.chwl.app.ui.widget.rollviewpager.adapter; + + +import android.view.View; +import android.view.ViewGroup; + +import androidx.fragment.app.FragmentStatePagerAdapter; +import androidx.viewpager.widget.PagerAdapter; + +import java.util.ArrayList; + + +/** + * 静态存储的Adapter。概念参照{@link FragmentStatePagerAdapter} + * view添加进去就不管了,View长在,内存不再。 + *

Subclasses only need to implement {@link #getView(ViewGroup,int)} + * and {@link #getCount()} to have a working adapter. + * + */ +public abstract class StaticPagerAdapter extends PagerAdapter { + private ArrayList mViewList = new ArrayList<>(); + + @Override + public boolean isViewFromObject(View arg0, Object arg1) { + return arg0==arg1; + } + + @Override + public void destroyItem(ViewGroup container, int position, Object object) { + container.removeView((View) object); + } + + @Override + public void notifyDataSetChanged() { + mViewList.clear(); + super.notifyDataSetChanged(); + } + + @Override + public int getItemPosition(Object object) { + return POSITION_NONE; + } + + @Override + public Object instantiateItem(ViewGroup container, int position) { + View itemView = findViewByPosition(container,position); + container.addView(itemView); + onBind(itemView,position); + return itemView; + } + + private View findViewByPosition(ViewGroup container,int position){ + for (View view : mViewList) { + if (((int)view.getTag()) == position&&view.getParent()==null){ + return view; + } + } + View view = getView(container,position); + view.setTag(position); + mViewList.add(view); + return view; + } + + + public void onBind(View view,int position){ + } + + public abstract View getView(ViewGroup container, int position); + +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/adapter/StaticPagerAdapterWrapper.java b/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/adapter/StaticPagerAdapterWrapper.java new file mode 100644 index 0000000..66cf90f --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/adapter/StaticPagerAdapterWrapper.java @@ -0,0 +1,26 @@ +package com.chwl.app.ui.widget.rollviewpager.adapter; + +import android.content.Context; + +import java.util.List; + +public abstract class StaticPagerAdapterWrapper extends StaticPagerAdapter { + + protected Context context; + protected List dataList; + + + public StaticPagerAdapterWrapper(List dataList, Context context) { + this.context = context; + this.dataList = dataList; + } + + public void setData(List dataList) { + this.dataList = dataList; + } + + @Override + public int getCount() { + return dataList == null ? 0 : dataList.size(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/hintview/ColorPointHintView.java b/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/hintview/ColorPointHintView.java new file mode 100644 index 0000000..108e43b --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/hintview/ColorPointHintView.java @@ -0,0 +1,40 @@ +package com.chwl.app.ui.widget.rollviewpager.hintview; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; + +import com.chwl.app.ui.widget.rollviewpager.Util; + + +/** + * Created by Mr.Jude on 2016/1/10. + */ +public class ColorPointHintView extends ShapeHintView { + private int focusColor; + private int normalColor; + + public ColorPointHintView(Context context,int focusColor,int normalColor) { + super(context); + this.focusColor = focusColor; + this.normalColor = normalColor; + } + + @Override + public Drawable makeFocusDrawable() { + GradientDrawable dot_focus = new GradientDrawable(); + dot_focus.setColor(focusColor); + dot_focus.setCornerRadius(Util.dip2px(getContext(), 4)); + dot_focus.setSize(Util.dip2px(getContext(), 8), Util.dip2px(getContext(), 8)); + return dot_focus; + } + + @Override + public Drawable makeNormalDrawable() { + GradientDrawable dot_normal = new GradientDrawable(); + dot_normal.setColor(normalColor); + dot_normal.setCornerRadius(Util.dip2px(getContext(), 4)); + dot_normal.setSize(Util.dip2px(getContext(), 8), Util.dip2px(getContext(), 8)); + return dot_normal; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/hintview/IconHintView.java b/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/hintview/IconHintView.java new file mode 100644 index 0000000..7116bed --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/hintview/IconHintView.java @@ -0,0 +1,78 @@ +package com.chwl.app.ui.widget.rollviewpager.hintview; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.PixelFormat; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; + +import androidx.annotation.DrawableRes; + +import com.chwl.app.ui.widget.rollviewpager.Util; + + +/** + * Created by Mr.Jude on 2016/1/10. + */ +public class IconHintView extends ShapeHintView { + private int focusResId; + private int normalResId; + private int size; + + + public IconHintView(Context context, @DrawableRes int focusResId, @DrawableRes int normalResId) { + this(context, focusResId, normalResId, Util.dip2px(context,32)); + } + + public IconHintView(Context context, @DrawableRes int focusResId, @DrawableRes int normalResId, int size) { + super(context); + this.focusResId = focusResId; + this.normalResId = normalResId; + this.size = size; + } + + @Override + public Drawable makeFocusDrawable() { + Drawable drawable = getContext().getResources().getDrawable(focusResId); + if (size>0){ + drawable = zoomDrawable(drawable,size,size); + } + return drawable; + } + + @Override + public Drawable makeNormalDrawable() { + Drawable drawable = getContext().getResources().getDrawable(normalResId); + if (size>0){ + drawable = zoomDrawable(drawable,size,size); + } + return drawable; + } + + private Drawable zoomDrawable(Drawable drawable, int w, int h) { + int width = drawable.getIntrinsicWidth(); + int height = drawable.getIntrinsicHeight(); + Bitmap oldbmp = drawableToBitmap(drawable); + Matrix matrix = new Matrix(); + float scaleWidth = ((float) w / width); + float scaleHeight = ((float) h / height); + matrix.postScale(scaleWidth, scaleHeight); + Bitmap newbmp = Bitmap.createBitmap(oldbmp, 0, 0, width, height, + matrix, true); + return new BitmapDrawable(null, newbmp); + } + + private Bitmap drawableToBitmap(Drawable drawable) { + int width = drawable.getIntrinsicWidth(); + int height = drawable.getIntrinsicHeight(); + Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 + : Bitmap.Config.RGB_565; + Bitmap bitmap = Bitmap.createBitmap(width, height, config); + Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, width, height); + drawable.draw(canvas); + return bitmap; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/hintview/ShapeHintView.java b/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/hintview/ShapeHintView.java new file mode 100644 index 0000000..df543d6 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/hintview/ShapeHintView.java @@ -0,0 +1,80 @@ +package com.chwl.app.ui.widget.rollviewpager.hintview; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.view.Gravity; +import android.widget.ImageView; +import android.widget.LinearLayout; + +import com.chwl.app.ui.widget.rollviewpager.HintView; + + +public abstract class ShapeHintView extends LinearLayout implements HintView { + private ImageView[] mDots; + private int length = 0; + private int lastPosition = 0; + + private Drawable dot_normal; + private Drawable dot_focus; + + public ShapeHintView(Context context){ + super(context); + } + + public ShapeHintView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + + public abstract Drawable makeFocusDrawable(); + + public abstract Drawable makeNormalDrawable(); + + @Override + public void initView(int length, int gravity) { + removeAllViews(); + lastPosition = 0; + setOrientation(HORIZONTAL); + switch (gravity) { + case 0: + setGravity(Gravity.LEFT| Gravity.CENTER_VERTICAL); + break; + case 1: + setGravity(Gravity.CENTER); + break; + case 2: + setGravity(Gravity.RIGHT| Gravity.CENTER_VERTICAL); + break; + } + + this.length = length; + mDots = new ImageView[length]; + + dot_focus = makeFocusDrawable(); + dot_normal = makeNormalDrawable(); + + for (int i = 0; i < length; i++) { + mDots[i]=new ImageView(getContext()); + LayoutParams dotlp = new LayoutParams( + LayoutParams.WRAP_CONTENT, + LayoutParams.WRAP_CONTENT); + dotlp.setMargins(10, 0, 10, 0); + mDots[i].setLayoutParams(dotlp); + mDots[i].setBackgroundDrawable(dot_normal); + addView(mDots[i]); + } + + setCurrent(0); + } + + @Override + public void setCurrent(int current) { + if (current < 0 || current > length - 1) { + return; + } + mDots[lastPosition].setBackgroundDrawable(dot_normal); + mDots[current].setBackgroundDrawable(dot_focus); + lastPosition = current; + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/hintview/TextHintView.java b/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/hintview/TextHintView.java new file mode 100644 index 0000000..8076bd8 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/rollviewpager/hintview/TextHintView.java @@ -0,0 +1,45 @@ +package com.chwl.app.ui.widget.rollviewpager.hintview; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.Gravity; + +import androidx.appcompat.widget.AppCompatTextView; + +import com.chwl.app.ui.widget.rollviewpager.HintView; + + +public class TextHintView extends AppCompatTextView implements HintView { + private int length; + + public TextHintView(Context context){ + super(context); + } + + public TextHintView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + public void initView(int length, int gravity) { + this.length = length; + switch (gravity) { + case 0: + setGravity(Gravity.LEFT| Gravity.CENTER_VERTICAL); + break; + case 1: + setGravity(Gravity.CENTER); + break; + case 2: + setGravity(Gravity.RIGHT| Gravity.CENTER_VERTICAL); + break; + } + + setCurrent(0); + } + + @Override + public void setCurrent(int current) { + setText(current+1+"/"+ length); + } +} diff --git a/app/src/main/java/com/chwl/app/ui/widget/viewpager/NoScrollViewPager.java b/app/src/main/java/com/chwl/app/ui/widget/viewpager/NoScrollViewPager.java new file mode 100644 index 0000000..81b54f1 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/viewpager/NoScrollViewPager.java @@ -0,0 +1,46 @@ +package com.chwl.app.ui.widget.viewpager; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.viewpager.widget.ViewPager; + +public class NoScrollViewPager extends ViewPager { + // false 禁止ViewPager左右滑动。 + // true 普通ViewPager + private boolean isScroll = false; + + public NoScrollViewPager(@NonNull Context context) { + this(context, null); + } + public NoScrollViewPager(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + public void setScrollable(boolean isScroll) { + this.isScroll = isScroll; + } + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + if (!isScroll){ + // 不允许拦截事件就返回false + return isScroll; + }else { + // 正常ViewPager处理拦截事件就请求父类普通ViewPager中的onInterceptTouchEvent() + return super.onInterceptTouchEvent(ev); + } + } + @Override + public boolean onTouchEvent(MotionEvent ev) { + if (!isScroll){ + // 不允许消费事件就返回false. + return isScroll; + }else { + // 正常ViewPager消耗事件就请求父类普通ViewPager中的onTouchEvent. + return super.onTouchEvent(ev); + } + } +} + diff --git a/app/src/main/java/com/chwl/app/ui/widget/viewpager/ScrollViewPager.java b/app/src/main/java/com/chwl/app/ui/widget/viewpager/ScrollViewPager.java new file mode 100644 index 0000000..8c46d29 --- /dev/null +++ b/app/src/main/java/com/chwl/app/ui/widget/viewpager/ScrollViewPager.java @@ -0,0 +1,27 @@ +package com.chwl.app.ui.widget.viewpager; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; + +import com.chwl.app.ui.widget.rollviewpager.RollPagerView; + +public class ScrollViewPager extends RollPagerView { + public ScrollViewPager(Context context) { + super(context); + } + + public ScrollViewPager(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public ScrollViewPager(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + getParent().requestDisallowInterceptTouchEvent(true); //设置不拦截 + return super.dispatchTouchEvent(ev); + } +} diff --git a/app/src/main/java/com/chwl/app/utils/ActWhiteListMrg.java b/app/src/main/java/com/chwl/app/utils/ActWhiteListMrg.java new file mode 100644 index 0000000..9c740b9 --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/ActWhiteListMrg.java @@ -0,0 +1,41 @@ +package com.chwl.app.utils; + +import android.content.Context; + +import com.netease.nim.uikit.common.util.log.LogUtil; +import com.chwl.app.NimMiddleActivity; +import com.chwl.app.R; +import com.chwl.app.other.activity.SplashActivity; +import com.chwl.core.utils.ActivityUtil; +import com.chwl.library.utils.ResUtil; + +import java.util.ArrayList; +import java.util.List; + +/** + * 一些Activity的白名单管理,比如不需要弹升级窗 + * create by lvzebiao @2019/8/14 + */ +public class ActWhiteListMrg { + + /** + * 过滤掉一些中转的activity,不进行入栈管理 + */ + public static boolean isTempActivity(Context currContext) { + if (!ActivityUtil.isCanShowAppCompatDialog(currContext)) { + return true; + } + List acts = new ArrayList<>(); + acts.add(NimMiddleActivity.class); + acts.add(SplashActivity.class); + + for (Class act : acts) { + if (act.isInstance(currContext)) { + LogUtil.print(ResUtil.getString(R.string.erban_utils_actwhitelistmrg_01) + currContext.getClass().getSimpleName()); + return true; + } + } + return false; + } + +} diff --git a/app/src/main/java/com/chwl/app/utils/AnimLoadUtil.kt b/app/src/main/java/com/chwl/app/utils/AnimLoadUtil.kt new file mode 100644 index 0000000..fa57503 --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/AnimLoadUtil.kt @@ -0,0 +1,490 @@ +package com.chwl.app.utils + +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Color +import android.text.Layout +import android.text.StaticLayout +import android.text.TextPaint +import android.text.TextUtils +import android.view.View +import com.bumptech.glide.load.DataSource +import com.bumptech.glide.load.engine.GlideException +import com.bumptech.glide.request.RequestFutureTarget +import com.bumptech.glide.request.RequestListener +import com.bumptech.glide.request.target.Target +import com.chwl.app.R +import com.chwl.app.application.App +import com.chwl.app.ui.utils.loadAnim2 +import com.chwl.core.utils.LogUtils +import com.chwl.library.common.util.isVerify +import com.chwl.library.common.util.postSafe +import com.netease.nim.uikit.support.glide.GlideApp +import com.opensource.svgaplayer.SVGADrawable +import com.opensource.svgaplayer.SVGADynamicEntity +import com.opensource.svgaplayer.SVGAImageView +import com.opensource.svgaplayer.SVGAParser +import com.opensource.svgaplayer.SVGAParser.Companion.shareParser +import com.opensource.svgaplayer.SVGAVideoEntity +import com.tencent.qgame.animplayer.AnimView +import com.tencent.qgame.animplayer.inter.IFetchResource +import com.tencent.qgame.animplayer.mix.Resource +import java.io.BufferedInputStream +import java.io.FileInputStream + +object AnimLoadUtil { + + private val mOptions : BitmapFactory.Options by lazy { BitmapFactory.Options().apply { + inJustDecodeBounds = true + } } +// private val mMediaPlayer : MediaPlayer by lazy { MediaPlayer() } + + /** + * todo 判断是否图片资源 待改进, 目前偶尔会有判断失误 + * 传入文件路径(app沙盒内存里的) 返回是否图片 + */ + fun isImageFile(path:String): Boolean { + try { + val decodeFile = BitmapFactory.decodeFile(path, mOptions) + val fillType = mOptions.outMimeType + if (fillType == null) return false + return true + } catch (e: Exception) { + return false + } + } + + fun isSvgaFile(path: String,callBack: (isSvga: Boolean,videoItem: SVGAVideoEntity?) -> Unit = {_,_->}){ + try { + val inputStream = BufferedInputStream(FileInputStream(path)) + shareParser().decodeFromInputStream( + inputStream, + path, + object : SVGAParser.ParseCompletion { + override fun onComplete(videoItem: SVGAVideoEntity) { + callBack(true,videoItem) + } + + override fun onError() { + callBack(false,null) + } + }, + true, + null, + null + ) + } catch (e: Exception) { + } + } + + //垃圾 不顶用 +// fun isMp4File(path:String): Boolean { +// try { +// mMediaPlayer.setDataSource(path) +// return true +// } catch (e: Exception) { +// return false +// } +// } + + + + fun loadVap( + animView: AnimView, + url: String?, + imgUrlMap: HashMap? = null, + textMap: HashMap? = null, + callBack: (isSuccess: Boolean) -> Unit = {_->} + ) { + LogUtils.d("AnimLoadUtil drawEffect loadVap 准备开始 imgUrlMap = $imgUrlMap textMap = $textMap url = $url}") + if (url == null) { + callBack(false) + return + } + animView.visibility = View.VISIBLE + var index = 0 + val bitmapMap = hashMapOf() + + if (!imgUrlMap.isNullOrEmpty()) { + imgUrlMap.keys.forEach { key -> + + if (!imgUrlMap[key].isVerify()){ + callBack(false) + return + } + + downLoadAvatar(imgUrlMap[key]) { resource -> + if (resource == null) { + callBack(false) + } else { + index++ + bitmapMap[key] = resource + if (index == imgUrlMap.keys.size) { + animView.setFetchResource(object : IFetchResource { + override fun fetchImage( + resource: Resource, + result: (Bitmap?) -> Unit + ) { + LogUtils.d("AnimLoadUtil drawEffect loadVap animView.setFetchResource fetchImage resource.tag = ${resource.tag}") + if (bitmapMap.isEmpty()) { + result(null) + } else { + var bitmap: Bitmap? = null + bitmapMap.keys.forEach { + if (resource.tag == it) { + bitmap = bitmapMap[it] + } + } + result(bitmap) + } + } + + override fun fetchText( + resource: Resource, + result: (String?) -> Unit + ) { + var text = " " + if (textMap.isNullOrEmpty()) { + result(text) + } else { + textMap.keys.forEach { + if (resource.tag == it) { + text = textMap[it].toString() + } + } + result(text) + } + LogUtils.d("AnimLoadUtil drawEffect loadVap animView.setFetchResource fetchText text.key = ${resource.tag} text.value = $text") + } + + override fun releaseResource(resources: List) { + resources?.forEach { + it?.bitmap?.recycle() + } + } + }) + LogUtils.d("AnimLoadUtil drawEffect animViewSetAnimListener startPlay url = $url") + animView.loadAnim2(url,false){ isSuccess -> + callBack(isSuccess) + } + } + } + + } + } + } else { + animView.loadAnim2(url){ isSuccess -> + callBack(isSuccess) + } + } + } + + fun downLoadAvatar(url: String?, onResourceReady: (resource: Bitmap?) -> Unit = {_->}) { + if (url.isNullOrEmpty()) { + onResourceReady(null) + return + } + try { + val futureTarget = + RequestFutureTarget(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) + GlideApp.with(App.instance()) + .asBitmap() + .circleCrop() + .load(url) + .addListener(object : RequestListener { + override fun onLoadFailed( + e: GlideException?, + model: Any?, + target: Target?, + isFirstResource: Boolean + ): Boolean { + onResourceReady(null) + return true + } + + override fun onResourceReady( + resource: Bitmap?, + model: Any?, + target: Target?, + dataSource: DataSource?, + isFirstResource: Boolean + ): Boolean { + onResourceReady(resource) + return true + } + }) + .into(futureTarget) + .get() + } catch (e: Exception) { +// onResourceReady(null) + } + } + + + fun loadSvga( + shareParser:SVGAParser? =null, + svgaView: SVGAImageView, + path: String, + imgUrlMap: HashMap? = null, + textMap: HashMap? = null, + callBack: (isSuccess: Boolean) -> Unit + ) { + val svgaParser = shareParser ?: shareParser() + val inputStream = BufferedInputStream(FileInputStream(path)) + svgaParser.decodeFromInputStream(inputStream, path, object : SVGAParser.ParseCompletion { + override fun onComplete(svgaVideoEntity: SVGAVideoEntity) { + + if (!svgaView.isAttachedToWindow) { + callBack(false) + return + } + + val dynamicEntity = SVGADynamicEntity() + + if (!textMap.isNullOrEmpty()) { + textMap.keys.forEach { key -> + val textPaint = TextPaint() + textPaint.color = Color.WHITE //字体颜色 + textPaint.textSize = 24f //字体大小 + dynamicEntity.setDynamicText( + StaticLayout( + textMap[key], + 0, + textMap[key]!!.length, + textPaint, + 0, + Layout.Alignment.ALIGN_CENTER, + 1.0f, + 0.0f, + false + ), key + ) + } + } + + + var index = 0 + if (!imgUrlMap.isNullOrEmpty()) { + imgUrlMap.keys.forEach { key -> + addDynamicImage( + svgaView, + dynamicEntity, + imgUrlMap[key], + key + ) { + index++ + if (index == imgUrlMap.size) { + val drawable = SVGADrawable(svgaVideoEntity, dynamicEntity) + svgaView.setImageDrawable(drawable) + svgaView.stepToFrame(0, true) + callBack(true) + } + } + } + } else { + val drawable = SVGADrawable(svgaVideoEntity, dynamicEntity) + svgaView.setImageDrawable(drawable) + svgaView.stepToFrame(0, true) + callBack(true) + } + } + + override fun onError() { + callBack(false) + } + }, true, null, null) + } + + fun loadSvgaForEntity( + svgaView: SVGAImageView, + svgaVideoEntity: SVGAVideoEntity, + imgUrlMap: HashMap? = null, + textMap: HashMap? = null, + isSafe:Boolean = true, + callBack: (isSuccess: Boolean) -> Unit, + ) { + + if (isSafe) { + if(!svgaView.isAttachedToWindow) { + callBack(false) + return + } + } + + val dynamicEntity = SVGADynamicEntity() + + + if (!textMap.isNullOrEmpty()) { + textMap.keys.forEach { key -> + val textPaint = TextPaint() + textPaint.color = Color.WHITE //字体颜色 + textPaint.textSize = 24f //字体大小 + dynamicEntity.setDynamicText( + StaticLayout( + textMap[key], + 0, + textMap[key]!!.length, + textPaint, + 0, + Layout.Alignment.ALIGN_CENTER, + 1.0f, + 0.0f, + false + ), key + ) + } + } + + var index = 0 + if (!imgUrlMap.isNullOrEmpty()) { + imgUrlMap.keys.forEach { key -> + addDynamicImage( + svgaView, + dynamicEntity, + imgUrlMap[key], + key + ) { + index++ + if (index == imgUrlMap.size) { + val drawable = SVGADrawable(svgaVideoEntity, dynamicEntity) + svgaView.setImageDrawable(drawable) + svgaView.stepToFrame(0, true) + callBack(true) + } + } + } + } else { + val drawable = SVGADrawable(svgaVideoEntity, dynamicEntity) + svgaView.setImageDrawable(drawable) + svgaView.stepToFrame(0, true) + callBack(true) + } + + } + + + fun loadSvgaGetCache( + svgaView: SVGAImageView, + path: String, + imgUrlMap: HashMap? = null, + textMap: HashMap? = null, + callBack: (entity: SVGAVideoEntity?) -> Unit + ) { + + val inputStream = BufferedInputStream(FileInputStream(path)) + shareParser().decodeFromInputStream(inputStream, path, object : SVGAParser.ParseCompletion { + override fun onComplete(svgaVideoEntity: SVGAVideoEntity) { + if (!svgaView.isAttachedToWindow) { + callBack(null) + return + } + + val dynamicEntity = SVGADynamicEntity() + + if (!textMap.isNullOrEmpty()) { + textMap.keys.forEach { key -> + val textPaint = TextPaint() + textPaint.color = Color.WHITE //字体颜色 + textPaint.textSize = 22f //字体大小 + dynamicEntity.setDynamicText( + StaticLayout( + textMap[key], + 0, + textMap[key]!!.length, + textPaint, + 0, + Layout.Alignment.ALIGN_CENTER, + 1.0f, + 0.0f, + false + ), key + ) + } + } + + var index = 0 + if (!imgUrlMap.isNullOrEmpty()) { + imgUrlMap.keys.forEach { key -> + addDynamicImage( + svgaView, + dynamicEntity, + imgUrlMap[key], + key + ) { + index++ + if (index == imgUrlMap.size) { + svgaView.postSafe { + val drawable = SVGADrawable(svgaVideoEntity, dynamicEntity) + svgaView.setImageDrawable(drawable) + svgaView.stepToFrame(0, true) + callBack(svgaVideoEntity) + } + } + } + } + } else { + val drawable = SVGADrawable(svgaVideoEntity, dynamicEntity) + svgaView.setImageDrawable(drawable) + svgaView.stepToFrame(0, true) + callBack(svgaVideoEntity) + } + } + + override fun onError() { + callBack(null) + } + }, true, null, null) + } + + + private fun addDynamicImage( + view: View, + dynamicEntity: SVGADynamicEntity, + url: String?, + forKey: String?, + callBack: () -> Unit + ) { + if (TextUtils.isEmpty(url) || TextUtils.isEmpty(forKey)) { + LogUtils.d("AnimLoadUtil drawEffect addDynamicImage: url or forKey is null or empty") + return + } + GlideApp.with(App.instance()) + .asBitmap() + .circleCrop() + .load(url) + .addListener(object : RequestListener { + override fun onLoadFailed( + e: GlideException?, + model: Any, + target: Target, + isFirstResource: Boolean + ): Boolean { + dynamicEntity.setDynamicImage( + BitmapFactory.decodeResource(view.resources, R.drawable.default_avatar), + forKey!! + ) + callBack() + return false + } + + override fun onResourceReady( + resource: Bitmap?, + model: Any, + target: Target, + dataSource: DataSource, + isFirstResource: Boolean + ): Boolean { + resource?.let { + dynamicEntity.setDynamicImage( + resource, + forKey!! + ) + } + callBack() + return false + } + }) + .submit() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/utils/AppBarStateChangeListener.java b/app/src/main/java/com/chwl/app/utils/AppBarStateChangeListener.java new file mode 100644 index 0000000..a6819bc --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/AppBarStateChangeListener.java @@ -0,0 +1,40 @@ +package com.chwl.app.utils; + +import com.google.android.material.appbar.AppBarLayout; + +public abstract class AppBarStateChangeListener implements AppBarLayout.OnOffsetChangedListener { + + public enum State { + EXPANDED, + COLLAPSED, + IDLE + } + + private State mCurrentState = State.IDLE; + + @Override + public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { + if (verticalOffset == 0) { + if (mCurrentState != State.EXPANDED) { + onStateChanged(appBarLayout, State.EXPANDED); + } + mCurrentState = State.EXPANDED; + } else if (Math.abs(verticalOffset) >= appBarLayout.getTotalScrollRange() * getBias()) { + if (mCurrentState != State.COLLAPSED) { + onStateChanged(appBarLayout, State.COLLAPSED); + } + mCurrentState = State.COLLAPSED; + } else { + if (mCurrentState != State.IDLE) { + onStateChanged(appBarLayout, State.IDLE); + } + mCurrentState = State.IDLE; + } + } + + protected float getBias() { + return 1f; + } + + public abstract void onStateChanged(AppBarLayout appBarLayout, State state); +} diff --git a/app/src/main/java/com/chwl/app/utils/AvatarHelper.kt b/app/src/main/java/com/chwl/app/utils/AvatarHelper.kt new file mode 100644 index 0000000..4c78abc --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/AvatarHelper.kt @@ -0,0 +1,42 @@ +package com.chwl.app.utils + +import androidx.core.view.isVisible +import com.chwl.app.R +import com.chwl.library.widget.SVGAView +import com.chwl.core.decoration.headwear.bean.HeadWearInfo +import com.chwl.core.noble.NobleUtil + +object AvatarHelper { + + /** + * 加载头饰 + */ + @JvmStatic + fun loadAvatarFrame(view: SVGAView, headWearInfo: HeadWearInfo?) { + loadAvatarFrame(view, headWearInfo?.firstUrl, headWearInfo?.type ?: 0) + } + + /** + * 加载头饰 + * @param type 头饰类型 0:图片、1:SVGA + */ + @JvmStatic + fun loadAvatarFrame(view: SVGAView, url: String?, type: Int) { + view.setTag(R.id.head_wear, url) + if (url.isNullOrEmpty()) { + view.clearAnimation() + view.stopAnimation() + view.setImageDrawable(null) + return + } + if (type == 1) { + view.clearAnimation() + view.loadUrl(url) + view.isVisible = true + } else { + view.stopAnimation() + NobleUtil.loadHeadWear(url, view, R.id.head_wear, url) + view.isVisible = true + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/utils/BlurTransformation.java b/app/src/main/java/com/chwl/app/utils/BlurTransformation.java new file mode 100644 index 0000000..47d5a7b --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/BlurTransformation.java @@ -0,0 +1,94 @@ +package com.chwl.app.utils; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.os.Build; +import android.renderscript.RSRuntimeException; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.load.Transformation; +import com.bumptech.glide.load.engine.Resource; +import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; +import com.bumptech.glide.load.resource.bitmap.BitmapResource; + +import java.security.MessageDigest; + +public class BlurTransformation implements Transformation { + + private static int MAX_RADIUS = 25; + private static int DEFAULT_DOWN_SAMPLING = 1; + + private Context mContext; + private BitmapPool mBitmapPool; + + private int mRadius; + private int mSampling; + + public BlurTransformation(Context context) { + this(context, Glide.get(context).getBitmapPool(), MAX_RADIUS, DEFAULT_DOWN_SAMPLING); + } + + public BlurTransformation(Context context, BitmapPool pool) { + this(context, pool, MAX_RADIUS, DEFAULT_DOWN_SAMPLING); + } + + public BlurTransformation(Context context, BitmapPool pool, int radius) { + this(context, pool, radius, DEFAULT_DOWN_SAMPLING); + } + + public BlurTransformation(Context context, int radius) { + this(context, Glide.get(context).getBitmapPool(), radius, DEFAULT_DOWN_SAMPLING); + } + + public BlurTransformation(Context context, int radius, int sampling) { + this(context, Glide.get(context).getBitmapPool(), radius, sampling); + } + + public BlurTransformation(Context context, BitmapPool pool, int radius, int sampling) { + mContext = context.getApplicationContext(); + mBitmapPool = pool; + mRadius = radius; + mSampling = sampling; + } + + @Override + public Resource transform(Context context, Resource resource, int i, int i1) { + Bitmap source = resource.get(); + + int width = source.getWidth(); + int height = source.getHeight(); + int scaledWidth = width / mSampling; + int scaledHeight = height / mSampling; + + Bitmap bitmap = mBitmapPool.get(scaledWidth, scaledHeight, Bitmap.Config.ARGB_8888); + if (bitmap == null) { + bitmap = Bitmap.createBitmap(scaledWidth, scaledHeight, Bitmap.Config.ARGB_8888); + } + + Canvas canvas = new Canvas(bitmap); + canvas.scale(1 / (float) mSampling, 1 / (float) mSampling); + Paint paint = new Paint(); + paint.setFlags(Paint.FILTER_BITMAP_FLAG); + canvas.drawBitmap(source, 0, 0, paint); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { + try { + bitmap = RSBlur.blur(mContext, bitmap, mRadius); + } catch (RSRuntimeException e) { + bitmap = FastBlur.blur(bitmap, mRadius, true); + } + } else { + bitmap = FastBlur.blur(bitmap, mRadius, true); + } + + return BitmapResource.obtain(bitmap, mBitmapPool); + } + + @Override + public void updateDiskCacheKey(MessageDigest messageDigest) { + String key = "BlurTransformation(radius=" + mRadius + ", sampling=" + mSampling + ")"; + messageDigest.update(key.getBytes()); + } +} diff --git a/app/src/main/java/com/chwl/app/utils/CertificateHelper.java b/app/src/main/java/com/chwl/app/utils/CertificateHelper.java new file mode 100644 index 0000000..01aeef2 --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/CertificateHelper.java @@ -0,0 +1,119 @@ +package com.chwl.app.utils; + +import static com.chwl.core.certification.CertificationModel.CER_TYPE_FORCE; +import static com.chwl.core.certification.CertificationModel.CER_TYPE_GUIDE; +import static com.chwl.core.certification.CertificationModel.CER_TYPE_NONE; + +import android.content.Context; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.style.ForegroundColorSpan; + +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; + +import com.chwl.app.R; +import com.chwl.app.common.widget.dialog.DialogManager; +import com.chwl.app.ui.webview.CommonWebViewActivity; +import com.chwl.core.UriProvider; +import com.chwl.core.certification.CertificationModel; +import com.chwl.core.user.UserModel; +import com.chwl.core.user.bean.UserInfo; + +/** + * 强制用户实名认证 + */ +public class CertificateHelper { + + private Context mContext; + private DialogManager mDialogManager; + private CertificateStatusListener mCertificateStatusListener; + + public CertificateHelper(Context mContext, CertificateStatusListener certificateStatusListener) { + this.mContext = mContext; + mDialogManager = new DialogManager(mContext); + mDialogManager.setCanceledOnClickOutside(false); + mCertificateStatusListener = certificateStatusListener; + } + + public void certificate(boolean isForce) { + + UserInfo userInfo = UserModel.get().getCacheLoginUserInfo(); + if (userInfo != null) { + + if (!userInfo.isCertified()) { + if (isForce) { + mDialogManager.showTipsDialog(getCertificationTips(), + mContext.getString(R.string.go_to_certification), + new DialogManager.AbsOkDialogListener() { + @Override + public void onOk() { + // 跳去实名认证页面 + CommonWebViewActivity.start(mContext, + UriProvider.getTutuRealNamePage()); + } + }); + + } else { + + switch (CertificationModel.get().getCertificationType()) { + default: + case CER_TYPE_NONE: + if (mCertificateStatusListener != null) + mCertificateStatusListener.certificated(); + break; + + case CER_TYPE_GUIDE: + mDialogManager.showTipsDialog(getCertificationTips(), + mContext.getString(R.string.go_to_certification), + new DialogManager.OkCancelDialogListener() { + @Override + public void onCancel() { + if (mCertificateStatusListener != null) + mCertificateStatusListener.certificated(); + } + + @Override + public void onOk() { + // 跳去实名认证页面 + CommonWebViewActivity.start(mContext, + UriProvider.getTutuRealNamePage()); + } + }); + break; + + case CER_TYPE_FORCE: + mDialogManager.showTipsDialog(getCertificationTips(), + mContext.getString(R.string.go_to_certification), + new DialogManager.AbsOkDialogListener() { + @Override + public void onOk() { + // 跳去实名认证页面 + CommonWebViewActivity.start(mContext, + UriProvider.getTutuRealNamePage()); + } + }); + break; + } + + } + + } else if (mCertificateStatusListener != null) + mCertificateStatusListener.certificated(); + } + + } + + @NonNull + private SpannableStringBuilder getCertificationTips () { + String tips = mContext.getString(R.string.tips_need_to_certification); + SpannableStringBuilder builder = new SpannableStringBuilder(tips); + builder.setSpan(new ForegroundColorSpan(ContextCompat.getColor(mContext, R.color.appColor)), + tips.length() - 4, tips.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE); + return builder; + } + + public interface CertificateStatusListener { + void certificated(); + } +} diff --git a/app/src/main/java/com/chwl/app/utils/CleanLeakUtils.java b/app/src/main/java/com/chwl/app/utils/CleanLeakUtils.java new file mode 100644 index 0000000..87f3eb3 --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/CleanLeakUtils.java @@ -0,0 +1,59 @@ +package com.chwl.app.utils; + +import android.content.Context; +import android.os.Build; +import android.view.View; +import android.view.inputmethod.InputMethodManager; + +import java.lang.reflect.Field; + +/** + * + * 参考 https://blog.csdn.net/qq402164452/article/details/54378688 + * InputMethodManager的mNextServedView引用了MainActivity从而导致了内存泄漏。 + * @author jack + * @Description + * @Date 2018/5/16 + */ + +public class CleanLeakUtils { + public static void fixInputMethodManagerLeak(Context destContext) { + //在15<=API<=23中都存在 + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) { + return; + } + + if (destContext == null) { + return; + } + + InputMethodManager inputMethodManager = (InputMethodManager) destContext.getSystemService(Context.INPUT_METHOD_SERVICE); + if (inputMethodManager == null) { + return; + } + + String [] viewArray = new String[]{"mCurRootView", "mServedView", "mNextServedView"}; + Field filed; + Object filedObject; + + for (String view:viewArray) { + try{ + filed = inputMethodManager.getClass().getDeclaredField(view); + if (!filed.isAccessible()) { + filed.setAccessible(true); + } + filedObject = filed.get(inputMethodManager); + if (filedObject != null && filedObject instanceof View) { + View fileView = (View) filedObject; + if (fileView.getContext() == destContext) { // 被InputMethodManager持有引用的context是想要目标销毁的 + filed.set(inputMethodManager, null); // 置空,破坏掉path to gc节点 + } else { + break;// 不是想要目标销毁的,即为又进了另一层界面了,不要处理,避免影响原逻辑,也就不用继续for循环了 + } + } + }catch(Throwable t){ + t.printStackTrace(); + } + } + } +} diff --git a/app/src/main/java/com/chwl/app/utils/ClipboardUtils.java b/app/src/main/java/com/chwl/app/utils/ClipboardUtils.java new file mode 100644 index 0000000..dc6b796 --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/ClipboardUtils.java @@ -0,0 +1,136 @@ +package com.chwl.app.utils; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.app.Application; +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; +import android.os.Build; +import android.os.Bundle; +import android.text.TextUtils; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.chwl.app.application.App; + +/** + *

+ *     author : wk
+ *     time   : 2019/08/21
+ *     desc   : 剪贴板相关工具类
+ * 
+ */ +public class ClipboardUtils { + private static final String TAG = "ClipboardUtils"; + + /** + * 复制文本到剪贴板 + * + * @param text 文本 + */ + public static void copyText(final CharSequence text) { + try { + ClipboardManager cm = (ClipboardManager) App.getApplication().getSystemService(Context.CLIPBOARD_SERVICE); + cm.setPrimaryClip(ClipData.newPlainText("text", text)); + } catch (Exception e) { + Log.e(TAG, "copyText", e); + } + } + + /** + * 获取剪贴板的文本 + */ + public static void getText(@Nullable Activity activity, final Function f) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && activity != null) { + getTextFroClipAboveAndroidQ(activity, f); + } else { + f.invoke(getTextFromClip()); + } + } + + /** + * Android Q获取剪贴板的文本 + * 参考文档:https://juejin.cn/post/6844903922767757325 + */ + @TargetApi(Build.VERSION_CODES.Q) + private static void getTextFroClipAboveAndroidQ(@NonNull final Activity activity, final Function f) { + Runnable runnable = new Runnable() { + @Override + public void run() { + f.invoke(getTextFromClip()); + } + }; + activity.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() { + @Override + public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) { + } + + @Override + public void onActivityStarted(@NonNull Activity activity) { + } + + @Override + public void onActivityResumed(@NonNull Activity activity) { + } + + @Override + public void onActivityPaused(@NonNull Activity activity) { + } + + @Override + public void onActivityStopped(@NonNull Activity activity) { + } + + @Override + public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) { + } + + @Override + public void onActivityDestroyed(@NonNull Activity activity) { + activity.getWindow().getDecorView().removeCallbacks(runnable); + activity.unregisterActivityLifecycleCallbacks(this); + } + }); + activity.getWindow().getDecorView().post(runnable); + } + + /** + * 低于Android Q获取剪贴板的内容 + */ + private static String getTextFromClip() { + try { + ClipboardManager clipboardManager = (ClipboardManager) App.getApplication().getSystemService(Context.CLIPBOARD_SERVICE); + if (null == clipboardManager || !clipboardManager.hasPrimaryClip()) { + return ""; + } + ClipData clipData = clipboardManager.getPrimaryClip(); + if (null == clipData || clipData.getItemCount() < 1) { + return ""; + } + ClipData.Item item = clipData.getItemAt(0); + if (item == null) { + return ""; + } + CharSequence clipText = item.getText(); + if (TextUtils.isEmpty(clipText)) { + return ""; + } else { + return clipText.toString(); + } + } catch (Exception e) { + Log.e(TAG, "getTextFromClip", e); + } + return ""; + } + + public interface Function { + /** + * Invokes the function. + */ + void invoke(String text); + } + +} diff --git a/app/src/main/java/com/chwl/app/utils/CommonJumpHelper.java b/app/src/main/java/com/chwl/app/utils/CommonJumpHelper.java new file mode 100644 index 0000000..5df1221 --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/CommonJumpHelper.java @@ -0,0 +1,91 @@ +package com.chwl.app.utils; + + +import static com.chwl.core.home.bean.BannerInfo.SKIP_TYPE_NULL; +import static com.chwl.core.home.bean.BannerInfo.SKIP_TYPE_ROUTER; +import static com.chwl.core.home.bean.BannerInfo.SKIP_TYP_APP; +import static com.chwl.core.home.bean.BannerInfo.SKIP_TYP_CHAT_ROOM; +import static com.chwl.core.home.bean.BannerInfo.SKIP_TYP_H5; +import static com.chwl.core.home.bean.BannerInfo.SKIP_TYP_H5_CP; +import static com.chwl.core.home.bean.BannerInfo.SKIP_TYP_H5_CUSTOM; +import static com.chwl.core.home.bean.BannerInfo.SKIP_TYP_H5_WEE_STAR; + +import android.content.Context; +import android.content.Intent; +import android.text.TextUtils; + +import com.chwl.app.avroom.activity.AVRoomActivity; +import com.chwl.app.ui.im.RouterHandler; +import com.chwl.app.ui.webview.CommonWebViewActivity; +import com.chwl.core.bean.IRouterData; +import com.chwl.library.utils.JavaUtil; + +/** + * 用于banner做通用跳转 + * + * @author xj + */ +public class CommonJumpHelper { + /** + * 通用跳转 + * + * @param context + */ + public static void bannerJump(Context context, IRouterData bannerInfo) { + int skipType = bannerInfo.getSkipType(); + if (skipType == SKIP_TYPE_ROUTER) { + bannerJump(context, JavaUtil.str2int(bannerInfo.getRouterType()), bannerInfo.getRouterValue()); + } else { + bannerJump(context, skipType, bannerInfo.getSkipUri()); + } + } + + /** + * 通用跳转 + * + * @param context + */ + public static void bannerJump(Context context, int skipType, String skipContent) { + if (null == context) { + return; + } + switch (skipType) { + case SKIP_TYP_APP: + if (TextUtils.isEmpty(skipContent)) { + return; + } + RouterHandler.handle(context, JavaUtil.str2int(skipContent), null); + break; + case SKIP_TYP_CHAT_ROOM: + if (TextUtils.isEmpty(skipContent)) { + return; + } + AVRoomActivity.start(context, JavaUtil.str2long(skipContent)); + + break; + case SKIP_TYP_H5: + case SKIP_TYP_H5_CP: + case SKIP_TYP_H5_WEE_STAR: + case SKIP_TYP_H5_CUSTOM: + if (TextUtils.isEmpty(skipContent)) { + return; + } + Intent intent = new Intent(context, CommonWebViewActivity.class); + intent.putExtra("url", skipContent); + context.startActivity(intent); + break; + case SKIP_TYPE_ROUTER: + RouterHandler.handle(context, skipType, skipContent); + break; + case SKIP_TYPE_NULL: + //啥也不干 + break; + default: + break; + + } + + + } + +} diff --git a/app/src/main/java/com/chwl/app/utils/DoubleClickCheckListener.java b/app/src/main/java/com/chwl/app/utils/DoubleClickCheckListener.java new file mode 100644 index 0000000..ffb0681 --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/DoubleClickCheckListener.java @@ -0,0 +1,34 @@ +package com.chwl.app.utils; + + +import android.view.View; + +import com.chad.library.adapter.base.BaseQuickAdapter; + +public abstract class DoubleClickCheckListener implements BaseQuickAdapter.OnItemClickListener { + + private long mLastClickTime; + private long timeInterval = 1000L; + + public DoubleClickCheckListener() { + } + + public DoubleClickCheckListener(long timeInterval) { + if (timeInterval <= 1000L) { + timeInterval = 1000L; + } + this.timeInterval = timeInterval; + } + + @Override + public void onItemClick(BaseQuickAdapter adapter, View view, int position) { + long nowTime = System.currentTimeMillis(); + if (nowTime - mLastClickTime > timeInterval) { + // 单次点击事件 + mLastClickTime = nowTime; + onItemClickSingle(adapter, view, position); + } + } + + protected abstract void onItemClickSingle(BaseQuickAdapter adapter, View view, int position); +} diff --git a/app/src/main/java/com/chwl/app/utils/FastBlur.java b/app/src/main/java/com/chwl/app/utils/FastBlur.java new file mode 100644 index 0000000..f86f2b7 --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/FastBlur.java @@ -0,0 +1,257 @@ +package com.chwl.app.utils; + +import android.graphics.Bitmap; + +/** + * Copyright (C) 2017 Wasabeef + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +public class FastBlur { + + public static Bitmap blur(Bitmap sentBitmap, int radius, boolean canReuseInBitmap) { + + // Stack Blur v1.0 from + // http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html + // + // Java Author: Mario Klingemann + // http://incubator.quasimondo.com + // created Feburary 29, 2004 + // Android port : Yahel Bouaziz + // http://www.kayenko.com + // ported april 5th, 2012 + + // This is a compromise between Gaussian Blur and Box blur + // It creates much better looking blurs than Box Blur, but is + // 7x faster than my Gaussian Blur implementation. + // + // I called it Stack Blur because this describes best how this + // filter works internally: it creates a kind of moving stack + // of colors whilst scanning through the image. Thereby it + // just has to add one new block of color to the right side + // of the stack and remove the leftmost color. The remaining + // colors on the topmost layer of the stack are either added on + // or reduced by one, depending on if they are on the right or + // on the left side of the stack. + // + // If you are using this algorithm in your code please add + // the following line: + // + // Stack Blur Algorithm by Mario Klingemann + + Bitmap bitmap; + if (canReuseInBitmap) { + bitmap = sentBitmap; + } else { + bitmap = sentBitmap.copy(sentBitmap.getConfig(), true); + } + + if (radius < 1) { + return (null); + } + + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + + int[] pix = new int[w * h]; + bitmap.getPixels(pix, 0, w, 0, 0, w, h); + + int wm = w - 1; + int hm = h - 1; + int wh = w * h; + int div = radius + radius + 1; + + int r[] = new int[wh]; + int g[] = new int[wh]; + int b[] = new int[wh]; + int rsum, gsum, bsum, x, y, i, p, yp, yi, yw; + int vmin[] = new int[Math.max(w, h)]; + + int divsum = (div + 1) >> 1; + divsum *= divsum; + int dv[] = new int[256 * divsum]; + for (i = 0; i < 256 * divsum; i++) { + dv[i] = (i / divsum); + } + + yw = yi = 0; + + int[][] stack = new int[div][3]; + int stackpointer; + int stackstart; + int[] sir; + int rbs; + int r1 = radius + 1; + int routsum, goutsum, boutsum; + int rinsum, ginsum, binsum; + + for (y = 0; y < h; y++) { + rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0; + for (i = -radius; i <= radius; i++) { + p = pix[yi + Math.min(wm, Math.max(i, 0))]; + sir = stack[i + radius]; + sir[0] = (p & 0xff0000) >> 16; + sir[1] = (p & 0x00ff00) >> 8; + sir[2] = (p & 0x0000ff); + rbs = r1 - Math.abs(i); + rsum += sir[0] * rbs; + gsum += sir[1] * rbs; + bsum += sir[2] * rbs; + if (i > 0) { + rinsum += sir[0]; + ginsum += sir[1]; + binsum += sir[2]; + } else { + routsum += sir[0]; + goutsum += sir[1]; + boutsum += sir[2]; + } + } + stackpointer = radius; + + for (x = 0; x < w; x++) { + + r[yi] = dv[rsum]; + g[yi] = dv[gsum]; + b[yi] = dv[bsum]; + + rsum -= routsum; + gsum -= goutsum; + bsum -= boutsum; + + stackstart = stackpointer - radius + div; + sir = stack[stackstart % div]; + + routsum -= sir[0]; + goutsum -= sir[1]; + boutsum -= sir[2]; + + if (y == 0) { + vmin[x] = Math.min(x + radius + 1, wm); + } + p = pix[yw + vmin[x]]; + + sir[0] = (p & 0xff0000) >> 16; + sir[1] = (p & 0x00ff00) >> 8; + sir[2] = (p & 0x0000ff); + + rinsum += sir[0]; + ginsum += sir[1]; + binsum += sir[2]; + + rsum += rinsum; + gsum += ginsum; + bsum += binsum; + + stackpointer = (stackpointer + 1) % div; + sir = stack[(stackpointer) % div]; + + routsum += sir[0]; + goutsum += sir[1]; + boutsum += sir[2]; + + rinsum -= sir[0]; + ginsum -= sir[1]; + binsum -= sir[2]; + + yi++; + } + yw += w; + } + for (x = 0; x < w; x++) { + rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0; + yp = -radius * w; + for (i = -radius; i <= radius; i++) { + yi = Math.max(0, yp) + x; + + sir = stack[i + radius]; + + sir[0] = r[yi]; + sir[1] = g[yi]; + sir[2] = b[yi]; + + rbs = r1 - Math.abs(i); + + rsum += r[yi] * rbs; + gsum += g[yi] * rbs; + bsum += b[yi] * rbs; + + if (i > 0) { + rinsum += sir[0]; + ginsum += sir[1]; + binsum += sir[2]; + } else { + routsum += sir[0]; + goutsum += sir[1]; + boutsum += sir[2]; + } + + if (i < hm) { + yp += w; + } + } + yi = x; + stackpointer = radius; + for (y = 0; y < h; y++) { + // Preserve alpha channel: ( 0xff000000 & pix[yi] ) + pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum]; + + rsum -= routsum; + gsum -= goutsum; + bsum -= boutsum; + + stackstart = stackpointer - radius + div; + sir = stack[stackstart % div]; + + routsum -= sir[0]; + goutsum -= sir[1]; + boutsum -= sir[2]; + + if (x == 0) { + vmin[y] = Math.min(y + r1, hm) * w; + } + p = x + vmin[y]; + + sir[0] = r[p]; + sir[1] = g[p]; + sir[2] = b[p]; + + rinsum += sir[0]; + ginsum += sir[1]; + binsum += sir[2]; + + rsum += rinsum; + gsum += ginsum; + bsum += binsum; + + stackpointer = (stackpointer + 1) % div; + sir = stack[stackpointer]; + + routsum += sir[0]; + goutsum += sir[1]; + boutsum += sir[2]; + + rinsum -= sir[0]; + ginsum -= sir[1]; + binsum -= sir[2]; + + yi += w; + } + } + + bitmap.setPixels(pix, 0, w, 0, 0, w, h); + + return (bitmap); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/utils/FloatManager.java b/app/src/main/java/com/chwl/app/utils/FloatManager.java new file mode 100644 index 0000000..43a8fb8 --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/FloatManager.java @@ -0,0 +1,71 @@ +package com.chwl.app.utils; + +import android.content.Context; +import android.graphics.PixelFormat; +import android.os.Build; +import android.view.Gravity; +import android.view.ViewGroup; +import android.view.WindowManager; + +import com.chwl.app.application.App; +import com.chwl.app.ui.widget.MarqueeLayout; +import com.chwl.library.utils.SizeUtils; + +/** + *

悬浮窗管理

+ * + * @author jiahui + * @date 2018/1/10 + */ +public class FloatManager { + private WindowManager mWindowManager; + private MarqueeLayout marqueeLayout; + + + private static class FloatManagerHelper { + private static volatile FloatManager INSTANCE = new FloatManager(); + } + + public static FloatManager get() { + return FloatManagerHelper.INSTANCE; + } + + private FloatManager() { + mWindowManager = (WindowManager) App.instance().getSystemService(Context.WINDOW_SERVICE); + } + + /** + * 显示全局通知 + * @param context + * @param marqueeLayout -- + */ + public void showGlobalNotice(Context context, MarqueeLayout marqueeLayout) { + if (this.marqueeLayout != null && mWindowManager != null && marqueeLayout.isAttachedToWindow()) + mWindowManager.removeView(marqueeLayout); + this.marqueeLayout = marqueeLayout; + WindowManager.LayoutParams params = new WindowManager.LayoutParams(); + params.gravity = Gravity.TOP | Gravity.START; + params.height = SizeUtils.dp2px(context, 30); + params.width = ViewGroup.LayoutParams.MATCH_PARENT; + params.y = SizeUtils.dp2px(context, 62); + params.setTitle("Toast"); + params.x = 0; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; + } else { + params.type = WindowManager.LayoutParams.TYPE_TOAST; + } + + params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; + params.format = PixelFormat.TRANSLUCENT; + if (mWindowManager != null && !marqueeLayout.isAttachedToWindow()) + mWindowManager.addView(marqueeLayout, params); + marqueeLayout.startMarquee(); + marqueeLayout.setOnAnimatorListener( + animation -> { + if (mWindowManager != null) + mWindowManager.removeView(marqueeLayout); + }); + } + +} diff --git a/app/src/main/java/com/chwl/app/utils/FontTextView.java b/app/src/main/java/com/chwl/app/utils/FontTextView.java new file mode 100644 index 0000000..79ee1e7 --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/FontTextView.java @@ -0,0 +1,33 @@ +package com.chwl.app.utils; + +import android.content.Context; +import android.content.res.AssetManager; +import android.graphics.Typeface; +import android.util.AttributeSet; + +import androidx.appcompat.widget.AppCompatTextView; + +public class FontTextView extends AppCompatTextView { + public FontTextView(Context context) { + super(context); + init(context); + } + + public FontTextView(Context context, AttributeSet attrs) { + super(context, attrs); + init(context); + } + + public FontTextView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context); + } + + private void init(Context context) { + AssetManager mgr = context.getAssets(); + //根据路径得到Typeface + Typeface tf = Typeface.createFromAsset(mgr, "fonts/NimbusSanConLOT-Bla.otf"); + //设置字体 + setTypeface(tf); + } +} diff --git a/app/src/main/java/com/chwl/app/utils/GiftAnimUtil.java b/app/src/main/java/com/chwl/app/utils/GiftAnimUtil.java new file mode 100644 index 0000000..9471a07 --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/GiftAnimUtil.java @@ -0,0 +1,81 @@ +package com.chwl.app.utils; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.animation.PropertyValuesHolder; +import android.animation.ValueAnimator; +import android.view.View; +import android.view.animation.Animation; + +public class GiftAnimUtil { + + + public static void showAnimation(View view) { + // 透明度从0到1 + ObjectAnimator fadeIn = ObjectAnimator.ofFloat(view, "alpha", 1f, 1f); + fadeIn.setDuration(1000); + + // 尺寸从0%到100% + ObjectAnimator scaleUp = ObjectAnimator.ofPropertyValuesHolder( + view, + PropertyValuesHolder.ofFloat(View.SCALE_X, 0f, 1.2f,1f), + PropertyValuesHolder.ofFloat(View.SCALE_Y, 0f, 1.2f,1f) + ); + scaleUp.setDuration(1000); + + // 组合动画 + AnimatorSet appearSet = new AnimatorSet(); + appearSet.playTogether(fadeIn, scaleUp); + +// // 设置动画结束监听器 +// appearSet.addListener(new AnimatorListenerAdapter() { +// @Override +// public void onAnimationEnd(Animator animation) { +// // 显示动画结束后触发扩展动画 +// expandAnimation(view); +// } +// }); + + // 开始显示动画 + appearSet.start(); + } + + public static void expandAnimation(View view) { + // 尺寸从100%到120% + ObjectAnimator scaleExpand = ObjectAnimator.ofPropertyValuesHolder( + view, + PropertyValuesHolder.ofFloat(View.SCALE_X, 1f, 1.2f,1f), + PropertyValuesHolder.ofFloat(View.SCALE_Y, 1f, 1.2f,1f) + ); + scaleExpand.setDuration(500); + + // 循环执行3秒 +// scaleExpand.setRepeatCount(1); +// scaleExpand.setRepeatMode(ValueAnimator.RESTART); +// scaleExpand.setStartDelay(3000); // 确保在3秒后开始重复 + + // 设置动画结束监听器 +// scaleExpand.addListener(new AnimatorListenerAdapter() { +// @Override +// public void onAnimationEnd(Animator animation) { +// // 扩展动画结束后触发退出动画 +// fadeOutAnimation(view); +// } +// }); + + // 开始扩展动画 + scaleExpand.start(); + } + + public static void fadeOutAnimation(View view) { + // 透明度从1到0 + ObjectAnimator fadeOut = ObjectAnimator.ofFloat(view, "alpha", 1f, 0f); + fadeOut.setDuration(500); + + // 开始退出动画 + fadeOut.start(); + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/utils/HomeUIManager.kt b/app/src/main/java/com/chwl/app/utils/HomeUIManager.kt new file mode 100644 index 0000000..6a60245 --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/HomeUIManager.kt @@ -0,0 +1,112 @@ +package com.chwl.app.utils + +import android.graphics.Color +import android.view.View +import android.widget.ImageView +import com.chwl.app.R +import com.chwl.app.ui.utils.loadImage +import com.chwl.core.home.bean.ConfigInfo +import com.chwl.core.home.bean.MainTabInfo +import com.chwl.core.home.bean.MainTabType +import com.chwl.library.common.util.isVerify +import com.chwl.library.utils.ResUtil + +//管理 首页UI 配置 +object HomeUIManager { + + var mConfigInfo: ConfigInfo? = null + + fun setHomeUI(view: View) { + try { + if (mConfigInfo != null) { + val homeTopImg = view.findViewById(R.id.homeTopImg) + val homeRootView = view.findViewById(R.id.homeRootView) + + if (mConfigInfo?.appUiSetting?.headIcon.isVerify()) { + homeTopImg?.loadImage(mConfigInfo?.appUiSetting?.headIcon) + } + + if (mConfigInfo?.appUiSetting?.backgroundColor.isVerify()) { + homeRootView?.setBackgroundColor(Color.parseColor(mConfigInfo?.appUiSetting?.backgroundColor)) + } + } + } catch (e: Exception) { } + } + + fun setHomeTabBg(view: View?) { + try { + if (view != null && view is ImageView) { + if (mConfigInfo?.appUiSetting?.navbar.isVerify()) { + view.loadImage(mConfigInfo?.appUiSetting?.navbar) + } + } + }catch (e:Exception){ } + } + + fun getHomeTabIcons(): List? { + var list :List?= null + + val home = MainTabInfo( + "", + "", + ResUtil.getString(R.string.xchat_android_core_initial_initialmodel_03), + MainTabType.TAB_TYPE_HOME, + null + ) + if (mConfigInfo?.appUiSetting?.homeSelectIcon.isVerify() && mConfigInfo?.appUiSetting?.homeUnSelectIcon.isVerify()) { + home.tabSelectedIcon = mConfigInfo?.appUiSetting?.homeSelectIcon?:"" + home.tabIcon = mConfigInfo?.appUiSetting?.homeUnSelectIcon?:"" + } + + val game = MainTabInfo( + "", + "", + "Game", + MainTabType.TAB_TYPE_GAME, + null + ) + if (mConfigInfo?.appUiSetting?.gameSelectIcon.isVerify() && mConfigInfo?.appUiSetting?.gameUnSelectIcon.isVerify()) { + game.tabSelectedIcon = mConfigInfo?.appUiSetting?.gameSelectIcon?:"" + game.tabIcon = mConfigInfo?.appUiSetting?.gameUnSelectIcon?:"" + } + + val square = MainTabInfo( + "", + "", + "Square", + MainTabType.TAB_TYPE_SQUARE, + null + ) + if (mConfigInfo?.appUiSetting?.dynamicSelectIcon.isVerify() && mConfigInfo?.appUiSetting?.dynamicUnSelectIcon.isVerify()) { + square.tabSelectedIcon = mConfigInfo?.appUiSetting?.dynamicSelectIcon?:"" + square.tabIcon = mConfigInfo?.appUiSetting?.dynamicUnSelectIcon?:"" + } + + val msg = MainTabInfo( + "", + "", + ResUtil.getString(R.string.xchat_android_core_initial_initialmodel_06), + MainTabType.TAB_TYPE_MSG, + null + ) + if (mConfigInfo?.appUiSetting?.msgSelectIcon.isVerify() && mConfigInfo?.appUiSetting?.msgUnSelectIcon.isVerify()) { + msg.tabSelectedIcon = mConfigInfo?.appUiSetting?.msgSelectIcon?:"" + msg.tabIcon = mConfigInfo?.appUiSetting?.msgUnSelectIcon?:"" + } + + val me = MainTabInfo( + "", + "", + ResUtil.getString(R.string.xchat_android_core_initial_initialmodel_07), + MainTabType.TAB_TYPE_ME, + null + ) + if (mConfigInfo?.appUiSetting?.mineSelectIcon.isVerify() && mConfigInfo?.appUiSetting?.mineUnSelectIcon.isVerify()) { + me.tabSelectedIcon = mConfigInfo?.appUiSetting?.mineSelectIcon?:"" + me.tabIcon = mConfigInfo?.appUiSetting?.mineUnSelectIcon?:"" + } + + list = arrayListOf(home,game,square,msg,me) + return list + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/utils/KeyBoardUtils.java b/app/src/main/java/com/chwl/app/utils/KeyBoardUtils.java new file mode 100644 index 0000000..612428e --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/KeyBoardUtils.java @@ -0,0 +1,44 @@ +package com.chwl.app.utils; + +import android.app.Activity; +import android.content.Context; +import android.view.inputmethod.InputMethodManager; +import android.widget.EditText; + +/** + * Created by MadisonRong on 07/03/2018. + */ + +public class KeyBoardUtils { + + public static void showKeyBoard(Context context, EditText editText) { + if (context==null) return; + InputMethodManager imm = (InputMethodManager) + context.getSystemService(Context.INPUT_METHOD_SERVICE); + if (imm == null) return; + imm.showSoftInput(editText, InputMethodManager.SHOW_FORCED); + } + + public static void hideKeyBoard(Context context, EditText editText) { + if (context==null) return; + InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); + if (imm == null) return; + imm.hideSoftInputFromWindow(editText.getWindowToken(), 0); + } + + public static void showDialogSoftInput(Context activity) { + InputMethodManager inputMethodManager = + (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE); + if (inputMethodManager == null) return; + inputMethodManager.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS); + } + + public static void hideDialogSoftInput(Context activity) { + InputMethodManager inputMethodManager = + (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE); + if (inputMethodManager == null) return; + inputMethodManager.hideSoftInputFromWindow( + ((Activity)activity).getWindow().getDecorView().getWindowToken(), 0); + } +} + diff --git a/app/src/main/java/com/chwl/app/utils/LimitInputFliter.java b/app/src/main/java/com/chwl/app/utils/LimitInputFliter.java new file mode 100644 index 0000000..736e9c2 --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/LimitInputFliter.java @@ -0,0 +1,19 @@ +package com.chwl.app.utils; + +import android.text.InputFilter; +import android.text.Spanned; + +/** + * Created by lvzebiao on 2019/1/24. + */ + +public class LimitInputFliter implements InputFilter { + + @Override + public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { + if (source.equals(" ") || source.toString().contentEquals("\n")) { + return ""; + } + return null; + } +} diff --git a/app/src/main/java/com/chwl/app/utils/LoginSuccessManager.kt b/app/src/main/java/com/chwl/app/utils/LoginSuccessManager.kt new file mode 100644 index 0000000..0ec3e60 --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/LoginSuccessManager.kt @@ -0,0 +1,87 @@ +package com.chwl.app.utils + +import android.app.Activity +import com.chwl.app.ui.bean.FirstRechargeInfo +import com.chwl.app.ui.webview.DialogWebViewCenterActivity +import com.chwl.core.UriProvider +import com.chwl.core.bean.response.ServiceResult +import com.chwl.core.utils.net.RxHelper +import com.chwl.library.common.util.SPUtils +import com.chwl.library.common.util.toDP +import com.chwl.library.net.rxnet.RxNet +import com.netease.nim.uikit.common.util.sys.ScreenUtil +import io.reactivex.Single +import retrofit2.http.GET +import java.lang.ref.SoftReference + +/** + * 处理一些 登录成功后的逻辑 + */ +class LoginSuccessManager private constructor() { + + companion object { + @Volatile + private var INSTANCE: LoginSuccessManager? = null + + fun getInstance(): LoginSuccessManager { + return INSTANCE ?: synchronized(this) { + INSTANCE ?: LoginSuccessManager().also { INSTANCE = it } + } + } + + private const val IS_FIRST_RECHARGE = "is_first_recharge" + + } + + var mContextSoft : SoftReference?= null + + + /** + * 处理登录成功后的 要做的一些逻辑 + */ + public fun onLoadLoginUserInfoEvent(activity: Activity) { + + mContextSoft = SoftReference(activity) + + + val isFirstRecharge = SPUtils.getBoolean(IS_FIRST_RECHARGE, false) + mFirstRechargeStatus = isFirstRecharge + if (!isFirstRecharge) { + getFirstRechargeInfo() + .doOnSuccess { + mContextSoft?.get()?.let { act-> + DialogWebViewCenterActivity.start(act,UriProvider.getFirstRechargeIndex(),false, (ScreenUtil.screenHeight * 0.55).toInt(),13.toDP(),DialogWebViewCenterActivity.T_FIRST_RECHARNGE_INDEX) + } + mFirstRechargeInfo = it + SPUtils.putBoolean(IS_FIRST_RECHARGE,it.chargeStatus) + }.subscribe() + } + } + + /** + * 首冲相关 + */ + var mFirstRechargeInfo : FirstRechargeInfo? = null + var mFirstRechargeStatus = false + private fun getFirstRechargeInfo(): Single { + if (mFirstRechargeInfo != null) { + return Single.just(mFirstRechargeInfo); + } else { + return api.getFirstRechargeInfo() + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()) + } + } + + + + + private val api: Api = RxNet.create(Api::class.java); + private interface Api { + + @GET("/firstcharge/info") + fun getFirstRechargeInfo() : Single> + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/utils/MsgBuilder.kt b/app/src/main/java/com/chwl/app/utils/MsgBuilder.kt new file mode 100644 index 0000000..b2147e6 --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/MsgBuilder.kt @@ -0,0 +1,95 @@ +package com.chwl.app.utils + +import android.text.style.ForegroundColorSpan +import android.view.View +import androidx.core.graphics.toColorInt +import com.chwl.app.ui.webview.CommonWebViewActivity +import com.chwl.core.im.custom.bean.FairyMsgAttachment +import com.chwl.core.manager.RoomEvent +import com.chwl.core.utils.extension.sub + +class MsgBuilder { + + companion object { + + @JvmStatic + fun setUpKitchenClick(view: View, skipUrl: String, needLevel: Int): Boolean { + val expLevel = UserUtils.getExpLevel() + if (expLevel != 0 && needLevel != 0 && expLevel >= needLevel) { + view.setOnClickListener { + CommonWebViewActivity.start( + view.context, + skipUrl + ) + } + return true + } + return false + } + + @JvmStatic + fun buildFairyMsg( + roomEvent: Int, + attachment: FairyMsgAttachment + ): SpannableBuilder { + val builder = SpannableBuilder() + val fairyMsgInfo = attachment.fairyMsgInfo + when (roomEvent) { + RoomEvent.FAIRY_DRAW_GIFT_L4, + RoomEvent.FAIRY_DRAW_GIFT_L5 -> { + builder.append("好運爆棚!", ForegroundColorSpan("#8C4700".toColorInt())) + .append( + fairyMsgInfo.nick.sub(6), + ForegroundColorSpan("#EC4613".toColorInt()) + ) + .append(" 在奪寶精靈中獲得 ", ForegroundColorSpan("#8C4700".toColorInt())) + .append( + fairyMsgInfo.rewardName, + ForegroundColorSpan("#EC4613".toColorInt()) + ) + } + + RoomEvent.FAIRY_CONVERT_L1 -> { + builder.append("厲害了!", ForegroundColorSpan("#8C4700".toColorInt())) + .append( + fairyMsgInfo.nick.sub(6), + ForegroundColorSpan("#EC4613".toColorInt()) + ) + .append(" 在奪寶精靈中初級召喚 ", ForegroundColorSpan("#8C4700".toColorInt())) + .append( + "${fairyMsgInfo.rewardShowValue}鉆${fairyMsgInfo.rewardName}", + ForegroundColorSpan("#EC4613".toColorInt()) + ) + } + RoomEvent.FAIRY_CONVERT_L2 -> { + builder.append("厲害了!", ForegroundColorSpan("#8C4700".toColorInt())) + .append( + fairyMsgInfo.nick.sub(6), + ForegroundColorSpan("#EC4613".toColorInt()) + ) + .append(" 在奪寶精靈中史詩召喚 ", ForegroundColorSpan("#8C4700".toColorInt())) + .append( + "${fairyMsgInfo.rewardShowValue}鉆${fairyMsgInfo.rewardName}", + ForegroundColorSpan("#EC4613".toColorInt()) + ) + } + + RoomEvent.FAIRY_CONVERT_L3 -> { + builder.append("厲害了!", ForegroundColorSpan("#8C4700".toColorInt())) + .append( + fairyMsgInfo.nick.sub(6), + ForegroundColorSpan("#EC4613".toColorInt()) + ) + .append(" 在奪寶精靈中傳說召喚 ", ForegroundColorSpan("#8C4700".toColorInt())) + .append( + "${fairyMsgInfo.rewardShowValue}鉆${fairyMsgInfo.rewardName}", + ForegroundColorSpan("#EC4613".toColorInt()) + ) + } + } + return builder + + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/utils/NamePlateHelper.kt b/app/src/main/java/com/chwl/app/utils/NamePlateHelper.kt new file mode 100644 index 0000000..c5e1886 --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/NamePlateHelper.kt @@ -0,0 +1,75 @@ +package com.chwl.app.utils + +import android.view.View +import android.widget.ImageView +import android.widget.TextView +import androidx.core.view.isVisible +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.core.user.bean.UserInfo + + +object NamePlateHelper { + + fun load( + viewGroup: View?, + textView: TextView, + imageView: ImageView, userInfo: UserInfo? + ) { + load( + viewGroup, + textView, + imageView, + userInfo?.nameplateWord, + userInfo?.nameplatePic, + userInfo?.isCustomWord + ) + } + + /** + * 加载数据 + * @param viewGroup 铭牌View-Layout + * @param textView 铭牌View-文本 + * @param imageView 铭牌View-图片/背景 + * @param word 铭牌文字 + * @param pic 铭牌图片 + * @param isCustom 是否自定义铭牌 + */ + fun load( + viewGroup: View?, + textView: TextView, + imageView: ImageView, + word: String?, + pic: String?, + isCustom: Boolean? + ) { + if (isCustom == true) { + // 自定义模式:不展示文字 + load(viewGroup, textView, imageView, null, pic) + } else { + load(viewGroup, textView, imageView, word, pic) + } + } + + private fun load( + viewGroup: View?, + textView: TextView, + imageView: ImageView, + word: String?, + pic: String? + ) { + // 图片优先:无图片时都不展示 + if (pic.isNullOrEmpty()) { + viewGroup?.isVisible = false + } else { + imageView.isVisible = true + ImageLoadUtils.loadImage(imageView, pic) + if (!word.isNullOrEmpty()) { + textView.text = word + textView.isVisible = true + } else { + textView.isVisible = false + } + viewGroup?.isVisible = true + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/utils/NotificationsUtils.java b/app/src/main/java/com/chwl/app/utils/NotificationsUtils.java new file mode 100644 index 0000000..0adf5bd --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/NotificationsUtils.java @@ -0,0 +1,128 @@ +package com.chwl.app.utils; + +import android.app.Activity; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.provider.Settings; + +import androidx.core.app.NotificationManagerCompat; + +import com.netease.nim.uikit.common.util.log.LogUtil; +import com.chwl.app.R; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.SingleToastUtil; + +/** + * 通知栏监测工具 + * Created by lvzebiao on 2020/3/16. + */ +public class NotificationsUtils { + + public static boolean isNotificationEnabled(Context context) { + return NotificationManagerCompat.from(context.getApplicationContext()).areNotificationsEnabled(); + } + + private static boolean miuiOpen(Activity activity) { + try { + if (OSUtils.isMIUI()) { + Intent intent = new Intent(); + ComponentName cn = new ComponentName("com.android.settings", "com.android.settings.Settings$NotificationFilterActivity"); + Bundle bundle = new Bundle(); + bundle.putString("appName", activity.getResources().getString(activity.getApplicationInfo().labelRes)); + bundle.putString("packageName", activity.getPackageName()); + bundle.putString(":android:show_fragment", "NotificationAccessSettings"); + intent.putExtras(bundle); + intent.setComponent(cn); + activity.startActivity(intent); + return true; + } + } catch (Exception ex) { + ex.printStackTrace(); + } + return false; + } + + public static void openPush(Activity activity) { + try { + if (miuiOpen(activity)) { + //如果是MIUI系统,能成功跳转,则用MIUI跳转,否则走官方方法 + return; + } + + Intent intent = new Intent(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + //这种方案适用于 API 26, 即8.0(含8.0)以上可以用 + intent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS); + intent.putExtra(Settings.EXTRA_APP_PACKAGE, activity.getPackageName()); + intent.putExtra(Settings.EXTRA_CHANNEL_ID, activity.getApplicationInfo().uid); + activity.startActivity(intent); + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + intent.setAction("android.settings.APP_NOTIFICATION_SETTINGS"); + intent.putExtra("app_package", activity.getPackageName()); + intent.putExtra("app_uid", activity.getApplicationInfo().uid); + activity.startActivity(intent); + } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) { + intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.addCategory(Intent.CATEGORY_DEFAULT); + intent.setData(Uri.parse("package:" + activity.getPackageName())); + activity.startActivity(intent); + } else { + toPermissionSetting(activity); + } + } catch (Exception ex) { + String log = ResUtil.getString(R.string.erban_utils_notificationsutils_01); + SingleToastUtil.showToast(log); + LogUtil.e(ResUtil.getString(R.string.erban_utils_notificationsutils_02) + log); + } + } + + /** + * 跳转到权限设置 + * + * @param activity + */ + public static void toPermissionSetting(Activity activity) { + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) { + toSystemConfig(activity); + } else { + try { + toApplicationInfo(activity); + } catch (Exception e) { + e.printStackTrace(); + toSystemConfig(activity); + } + } + } + + /** + * 应用信息界面 + * + * @param activity + */ + public static void toApplicationInfo(Activity activity) { + Intent localIntent = new Intent(); + localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + localIntent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + localIntent.setData(Uri.fromParts("package", activity.getPackageName(), null)); + activity.startActivity(localIntent); + } + + /** + * 系统设置界面 + * + * @param activity + */ + public static void toSystemConfig(Activity activity) { + try { + Intent intent = new Intent(Settings.ACTION_SETTINGS); + activity.startActivity(intent); + } catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/app/src/main/java/com/chwl/app/utils/NumberFormatUtil.java b/app/src/main/java/com/chwl/app/utils/NumberFormatUtil.java new file mode 100644 index 0000000..af442c9 --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/NumberFormatUtil.java @@ -0,0 +1,37 @@ +package com.chwl.app.utils; + +import android.text.TextUtils; + +/** + * create by lvzebiao @2019/3/15 + */ +public class NumberFormatUtil { + + /** + * 数字格式转化 如 1000 → 1,000 + */ + public static String formatCommaInt(long value) { + String string = String.valueOf(value); + if (TextUtils.isEmpty(string)) { + return "0"; + } + try { + char [] chars = string.toCharArray(); + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < chars.length; i++) { + int low = chars.length - 1 - i; + String lowString = String.valueOf(chars[low]); + builder.insert(0, lowString); + if (i > 0 && (i + 1) % 3 == 0 && i < chars.length - 1) { + String comma = ","; + builder.insert(0, comma); + } + } + return builder.toString(); + } catch (Exception ex) { + ex.printStackTrace(); + } + return String.valueOf(value); + } + +} diff --git a/app/src/main/java/com/chwl/app/utils/NumberUtils.kt b/app/src/main/java/com/chwl/app/utils/NumberUtils.kt new file mode 100644 index 0000000..be865db --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/NumberUtils.kt @@ -0,0 +1,108 @@ +package com.chwl.app.utils + +import java.math.RoundingMode +import java.text.DecimalFormat +import java.text.DecimalFormatSymbols +import java.util.Locale +import kotlin.math.roundToLong + + +/** + * @Author Vance + * Date:2023/12/05 0005 13:59 + */ +object NumberUtils { + + private val df = DecimalFormat("0.##", DecimalFormatSymbols.getInstance(Locale.US)) + private val df2 = DecimalFormat("###,##0.##", DecimalFormatSymbols.getInstance(Locale.US)) + + @JvmStatic + fun format(num:Long):String{ + return format(num.toDouble()) + } + + @JvmStatic + fun format(num:Int):String{ + return format(num.toLong()) + } + + @JvmStatic + fun format(num:Double, roundUp:Boolean = true):String{ + val longValue = num.roundToLong() + return if(num < 10000){ + if(num - num.toLong() > 0){ + num.toString() + }else { + longValue.toString() + } + }else if(longValue < 1000000){ + format(longValue, "K",roundUp = roundUp) + }else if(longValue < 1000000000){ + format(longValue/1000, "M",roundUp = roundUp) + }else + format(longValue/1000000, "B",roundUp = roundUp) + } + + @JvmStatic + fun format(numOfK:Long, suffix:String, roundUp:Boolean = true):String{ + df.roundingMode = if(roundUp) RoundingMode.HALF_UP else RoundingMode.DOWN + return df.format(numOfK/1000.0)+suffix + } + + /** + * 用逗号分隔 + */ + @JvmStatic + @JvmOverloads + fun formatCommaSplit(number:Double, roundUp:Boolean = true):String { + df.roundingMode = if(roundUp) RoundingMode.HALF_UP else RoundingMode.DOWN + return df2.format(number) + } + + @JvmStatic + fun formatCommaSplit(number:Long):String { + return df2.format(number) + } + + @JvmStatic + @JvmOverloads + fun parseLong(str:String?, def:Long = 0):Long{ + if(str.isNullOrEmpty()){ + return def + } + + return try { + str.toLong() + } catch (e: Exception) { + return def + } + } + + @JvmStatic + @JvmOverloads + fun parseInt(str:String?, def:Int = 0):Int{ + if(str.isNullOrEmpty()){ + return def + } + + return try { + str.toInt() + } catch (e: Exception) { + return def + } + } + + @JvmStatic + @JvmOverloads + fun parseDouble(str:String?, def:Double = 0.0):Double{ + if(str.isNullOrEmpty()){ + return def + } + + return try { + str.toDouble() + } catch (e: Exception) { + return def + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/utils/OSUtils.java b/app/src/main/java/com/chwl/app/utils/OSUtils.java new file mode 100644 index 0000000..f984cf3 --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/OSUtils.java @@ -0,0 +1,59 @@ +package com.chwl.app.utils; + +import android.text.TextUtils; + +import java.io.BufferedReader; +import java.io.InputStreamReader; + +/** + * + */ +public class OSUtils { + //小米 + private static final String KEY_MIUI_VERSION_NANE = "ro.miui.ui.version.name"; // "V8" + private static final String KEY_MIUI_VERSION_CODE = "ro.miui.ui.version.code"; + //vivo + private static final String KEY_FUNTOUCHOS_OS_NAME = "ro.vivo.os.name"; // "Funtouch" + private static final String KEY_FUNTOUCHOS_OS_VERSION = "ro.vivo.os.version"; // "3.0" + private static final String KEY_FUNTOUCHOS_DISPLAY_ID = "ro.vivo.os.build.display.id"; // "FuntouchOS_3.0" + + public static boolean isMIUI() { + return hasBuildPropertie(KEY_MIUI_VERSION_NANE) || hasBuildPropertie(KEY_MIUI_VERSION_CODE); + } + + public static boolean isFuntouchOS() { + return hasBuildPropertie(KEY_FUNTOUCHOS_OS_NAME) || hasBuildPropertie(KEY_FUNTOUCHOS_OS_VERSION) + || hasBuildPropertie(KEY_FUNTOUCHOS_DISPLAY_ID); + } + + public static String getMIUIName() { + return getSystemProperty(KEY_MIUI_VERSION_NANE); + } + + public static boolean hasBuildPropertie(String propName) { + return !TextUtils.isEmpty(getSystemProperty(propName)); + } + + public static String getSystemProperty(String propName) { + String line; + BufferedReader input = null; + try { + Process p = Runtime.getRuntime().exec("getprop " + propName); + input = new BufferedReader(new InputStreamReader(p.getInputStream()), 1024); + line = input.readLine(); + input.close(); + } catch (Exception ex) { + return null; + } finally { + if (input != null) { + try { + input.close(); + } catch (Exception e) { + + } + } + } + return line; + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/utils/ObjectTypeHelper.java b/app/src/main/java/com/chwl/app/utils/ObjectTypeHelper.java new file mode 100644 index 0000000..7c15325 --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/ObjectTypeHelper.java @@ -0,0 +1,81 @@ +package com.chwl.app.utils; + +import com.chwl.core.community.bean.DynamicMedia; +import com.example.matisse.internal.entity.CustomItem; + +import java.util.ArrayList; +import java.util.List; + +/** + * create by lvzebiao @2019/11/19 + */ +public class ObjectTypeHelper { + + public static List customToStringList(List paramsList) { + List resultList = new ArrayList<>(); + if (paramsList == null) { + return resultList; + } + for (CustomItem item : paramsList) { + resultList.add(item.getPath()); + } + return resultList; + } + + public static List customToMediaList(List paramsList) { + List resultList = new ArrayList<>(); + if (paramsList == null) { + return resultList; + } + for (CustomItem item : paramsList) { + DynamicMedia media = new DynamicMedia(); + media.setLocalFilePath(item.getPath()); + media.setWidth(item.getWidth()); + media.setHeight(item.getHeight()); + media.setFormat(item.getFormat()); + resultList.add(media); + } + return resultList; + } + + public static List stringToCustomList(List paramsList) { + List resultList = new ArrayList<>(); + if (paramsList == null) { + return resultList; + } + for (String item : paramsList) { + resultList.add(new CustomItem(item, 0)); + } + return resultList; + } + + public static ArrayList mediaToCustomList(List paramsList) { + ArrayList resultList = new ArrayList<>(); + if (paramsList == null) { + return resultList; + } + for (DynamicMedia media : paramsList) { + CustomItem item = new CustomItem(); + item.setPath(media.getResUrl()); + item.setFileType(CustomItem.UNKOWN); + if (media.isJpgOrPng()) { + item.setFileType(CustomItem.IMAGE_NORMAL); + } else if (media.isGif()) { + item.setFileType(CustomItem.GIF); + } + item.setFormat(media.getFormat()); + resultList.add(item); + } + return resultList; + } + + public static ArrayList pathToCustomItems(String path) { + ArrayList resultList = new ArrayList<>(); + CustomItem item = new CustomItem(); + item.setPath(path); + item.setFileType(CustomItem.UNKOWN); + resultList.add(item); + return resultList; + } + +} diff --git a/app/src/main/java/com/chwl/app/utils/PermissionUtil.kt b/app/src/main/java/com/chwl/app/utils/PermissionUtil.kt new file mode 100644 index 0000000..30708da --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/PermissionUtil.kt @@ -0,0 +1,125 @@ +package com.chwl.app.utils + +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.pm.PackageManager +import android.net.Uri +import android.os.Build +import androidx.core.content.ContextCompat +import com.chwl.app.BuildConfig +import com.chwl.app.ui.setting.bean.PermissionEntity + +class PermissionUtil { + companion object { + val instance = PermissionUtil() + } + + fun getGrantedPermissions(context: Context): List { + val packageInfo = context.packageManager.getPackageInfo( + context.packageName, + PackageManager.GET_PERMISSIONS, + ) + val permissions = packageInfo.requestedPermissions + val list = permissions?.filter { str -> str.startsWith("android.permission") }?.let { + if (Build.VERSION.SDK_INT < 23) { + it + } else { + it.filter { s -> + ContextCompat.checkSelfPermission(context, s) == + PackageManager.PERMISSION_GRANTED + } + } + } + + val permissionList = ArrayList() + list?.forEach { + PermissionEntity.fetchPermission(it) + ?.let { permission -> + if (!permissionList.contains(permission)) permissionList.add(permission) + } + } + return permissionList + } + + fun jumpToSetting(context: Context) { + when (Build.BRAND?.toLowerCase()) { + "redmi", "xiaomi" -> toXiaomiPermission(context) + "huawei", "honor" -> toCommonPermission(context) + "meizu" -> toMeizuPermission(context) + else -> toCommonPermission(context) + } + } + + private fun toHuaWeiPermission(context: Context) { + try { + val intent = Intent() + intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK + val comp = ComponentName( + "com.huawei.systemmanager", + "com.huawei.permissionmanager.ui.MainActivity" + )//华为权限管理 + intent.component = comp + context.startActivity(intent) + } catch (e: Exception) { + e.printStackTrace() + toCommonPermission(context) + } + } + + private fun toXiaomiPermission(context: Context) { + try { // MIUI 8 + val localIntent = Intent("miui.intent.action.APP_PERM_EDITOR") + localIntent.setClassName( + "com.miui.securitycenter", + "com.miui.permcenter.permissions.PermissionsEditorActivity" + ) + localIntent.putExtra("extra_pkgname", context.packageName) + context.startActivity(localIntent) + } catch (e: Exception) { + try { // MIUI 5/6/7 + val localIntent = Intent("miui.intent.action.APP_PERM_EDITOR") + localIntent.setClassName( + "com.miui.securitycenter", + "com.miui.permcenter.permissions.AppPermissionsEditorActivity" + ) + localIntent.putExtra("extra_pkgname", context.packageName) + context.startActivity(localIntent) + } catch (e1: Exception) { // 否则跳转到应用详情 + toCommonPermission(context) + } + } + } + + private fun toMeizuPermission(context: Context) { + try { + val intent = Intent("com.meizu.safe.security.SHOW_APPSEC") + intent.addCategory(Intent.CATEGORY_DEFAULT) + intent.putExtra("packageName", BuildConfig.APPLICATION_ID) + context.startActivity(intent) + } catch (e: Exception) { + e.printStackTrace() + toCommonPermission(context) + } + } + + private fun toCommonPermission(context: Context) { + val localIntent = Intent() + localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + if (Build.VERSION.SDK_INT >= 9) { + localIntent.action = "android.settings.APPLICATION_DETAILS_SETTINGS" + localIntent.data = Uri.fromParts("package", context.packageName, null) + } else if (Build.VERSION.SDK_INT <= 8) { + localIntent.action = Intent.ACTION_VIEW + localIntent.setClassName( + "com.android.settings", + "com.android.settings.InstalledAppDetails" + ) + localIntent.putExtra( + "com.android.settings.ApplicationPkgName", + context.packageName + ) + } + context.startActivity(localIntent) + } +} diff --git a/app/src/main/java/com/chwl/app/utils/PushMessageHandler.java b/app/src/main/java/com/chwl/app/utils/PushMessageHandler.java new file mode 100644 index 0000000..27435c9 --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/PushMessageHandler.java @@ -0,0 +1,70 @@ +package com.chwl.app.utils; + +import android.app.Activity; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.text.TextUtils; + +import com.coorchice.library.utils.LogUtils; +import com.netease.nimlib.sdk.StatusBarNotificationConfig; +import com.netease.nimlib.sdk.mixpush.MixPushMessageHandler; +import com.chwl.core.DemoCache; + +import java.io.Serializable; +import java.util.Map; + +public class PushMessageHandler implements MixPushMessageHandler { + public static final String PAYLOAD_SKIPTYPE = "skiptype"; + public static final String PAYLOAD_PUSH_TITLE = "pushTitle"; + public static final String PAYLOAD_DATA = "data"; + + public static final int PAYLOAD_SKIPTYPE_INVITE_FANS = 2;//进入房间 + public static final int PAYLOAD_SKIPTYPE_H5 = 3;//跳转网页 + public static final int PAYLOAD_SKIPTYPE_PRIVATE_MSG = 4;//消息私聊页 + + @Override + public boolean onNotificationClicked(Context context, Map payload) { + LogUtils.e( "rev pushMessage payload " + payload); + + String skiptype = payload.get(PAYLOAD_SKIPTYPE); +// String push_title = payload.get(PAYLOAD_PUSH_TITLE); +// String payloadData = payload.get(PAYLOAD_DATA); + + if (!TextUtils.isEmpty(skiptype)) { + Intent notifyIntent = new Intent(); + notifyIntent.setComponent(initLaunchComponent(context)); + notifyIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); + notifyIntent.setAction(Intent.ACTION_VIEW); + notifyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // 必须 + notifyIntent.putExtra(PAYLOAD_DATA, (Serializable) payload); + + context.startActivity(notifyIntent); + return true; + + } else { + LogUtils.e("rev pushMessage payload false"); + return false; + } + } + + private ComponentName initLaunchComponent(Context context) { + ComponentName launchComponent; + StatusBarNotificationConfig config = DemoCache.getNotificationConfig(); + Class entrance = config.notificationEntrance; + if (entrance == null) { + launchComponent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName()).getComponent(); + } else { + launchComponent = new ComponentName(context, entrance); + } + return launchComponent; + } + + @Override + public boolean cleanMixPushNotifications(int pushType) { + return false; + } + +} + + diff --git a/app/src/main/java/com/chwl/app/utils/RSBlur.java b/app/src/main/java/com/chwl/app/utils/RSBlur.java new file mode 100644 index 0000000..4f96055 --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/RSBlur.java @@ -0,0 +1,66 @@ +package com.chwl.app.utils; + +import android.annotation.TargetApi; +import android.content.Context; +import android.graphics.Bitmap; +import android.os.Build; +import android.renderscript.Allocation; +import android.renderscript.Element; +import android.renderscript.RSRuntimeException; +import android.renderscript.RenderScript; +import android.renderscript.ScriptIntrinsicBlur; + +/** + * Copyright (C) 2017 Wasabeef + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +public class RSBlur { + + @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) + public static Bitmap blur(Context context, Bitmap bitmap, int radius) throws RSRuntimeException { + RenderScript rs = null; + Allocation input = null; + Allocation output = null; + ScriptIntrinsicBlur blur = null; + try { + rs = RenderScript.create(context); + rs.setMessageHandler(new RenderScript.RSMessageHandler()); + input = Allocation.createFromBitmap(rs, bitmap, Allocation.MipmapControl.MIPMAP_NONE, + Allocation.USAGE_SCRIPT); + output = Allocation.createTyped(rs, input.getType()); + blur = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); + + blur.setInput(input); + blur.setRadius(radius); + blur.forEach(output); + output.copyTo(bitmap); + } finally { + if (rs != null) { + rs.destroy(); + } + if (input != null) { + input.destroy(); + } + if (output != null) { + output.destroy(); + } + if (blur != null) { + blur.destroy(); + } + } + + return bitmap; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/utils/RegexUtil.java b/app/src/main/java/com/chwl/app/utils/RegexUtil.java new file mode 100644 index 0000000..0c13f65 --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/RegexUtil.java @@ -0,0 +1,66 @@ +package com.chwl.app.utils; + +import android.text.TextUtils; + +/** + * 正则表达式工具类 + * Created by yudi + * on 2018/3/26. + */ + +public class RegexUtil { + /** + * 这个遇到了的特殊字符再加上去 + * 否则可能引入其他问题 + */ + private static String INVISIBLE_CHARS = +// "" /* dummy empty string for homogeneity */ +// "\\u0009" // CHARACTER TABULATION +// + "\\u000A" // LINE FEED (LF) +// + "\\u000B" // LINE TABULATION +// + "\\u000C" // FORM FEED (FF) +// + "\\u000D" // CARRIAGE RETURN (CR) +//// + "\\u0020" // SPACE +// + "\\u0085" // NEXT LINE (NEL) +// + "\\u00A0" // NO-BREAK SPACE +// + "\\u1680" // OGHAM SPACE MARK +// + "\\u180E" // MONGOLIAN VOWEL SEPARATOR +// + "\\u2000" // EN QUAD +// + "\\u2001" // EM QUAD +// + "\\u2002" // EN SPACE +// + "\\u2003" // EM SPACE +// + "\\u2004" // THREE-PER-EM SPACE +// + "\\u2005" // FOUR-PER-EM SPACE +// + "\\u2006" // SIX-PER-EM SPACE +// + "\\u2007" // FIGURE SPACE +// + "\\u2008" // PUNCTUATION SPACE +// + "\\u2009" // THIN SPACE +// + "\\u200A" // HAIR SPACE +// + "\\u2028" // LINE SEPARATOR +// + "\\u2029" // PARAGRAPH SEPARATOR +// + "\\u202F" // NARROW NO-BREAK SPACE +// + "\\u205F" // MEDIUM MATHEMATICAL SPACE +// + "\\u2060" +// + "\\u2062" + "\\u2063" // INVISIBLE SEPARATOR +// + "\\u3000" // IDEOGRAPHIC SPACE + ; + /* A \s that actually works for Java’s native character set: Unicode */ + private static String VISIBLE_CHARS = "^[" + INVISIBLE_CHARS + "]"; + /* A \S that actually works for Java’s native character set: Unicode */ + private static String NOT_VISIBLE_CHARS = "[" + INVISIBLE_CHARS + "]"; + + public static String getPrintableStringReg() { + return VISIBLE_CHARS; + } + + public static String getNotPrintableStringReg() { + // bug-fixed java.lang.RuntimeException:Unable to resume activity {com.chwl.app/com.chwl.app.MainActivity}: kotlin.KotlinNullPointerException + return TextUtils.isEmpty(NOT_VISIBLE_CHARS) ? "" : NOT_VISIBLE_CHARS; + } + + public static String getPrintableString(String text) { + if (TextUtils.isEmpty(text)) return ""; + return text.replaceAll(getNotPrintableStringReg(), "?"); + } +} diff --git a/app/src/main/java/com/chwl/app/utils/ResourceManager.kt b/app/src/main/java/com/chwl/app/utils/ResourceManager.kt new file mode 100644 index 0000000..453658d --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/ResourceManager.kt @@ -0,0 +1,102 @@ +package com.chwl.app.utils + +import com.bumptech.glide.load.DataSource +import com.bumptech.glide.load.engine.GlideException +import com.bumptech.glide.request.RequestListener +import com.bumptech.glide.request.target.Target +import com.chwl.core.gift.bean.RoomMicDress +import com.chwl.core.home.bean.ClientResource +import com.chwl.core.initial.InitialModel +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.library.common.glide.GlideUtils +import com.chwl.library.common.util.doLog +import com.chwl.library.common.util.isVerify +import com.example.lib_utils.AppUtils +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import java.io.File + +object ResourceManager { + + public var mClientResource : ClientResource? = null + private val needLog = false; + + fun initResource() { + InitialModel.get().clientResource().doOnSuccess { +// "data = $it".doLog() + mClientResource = it + preLoad(it) + }.subscribe() + } + + fun getRoomMicSkins() : RoomMicDress?{ + val mCurrentRoomInfo = AvRoomDataManager.get().mCurrentRoomInfo + if (mCurrentRoomInfo != null) { + return getRoomMicDress(RoomMicDress.RoomDressType.T_Skin,mCurrentRoomInfo.usedMicSkinId) + } + return null + } + + fun getRoomMicEffects() : RoomMicDress?{ + val mCurrentRoomInfo = AvRoomDataManager.get().mCurrentRoomInfo + if (mCurrentRoomInfo != null) { + return getRoomMicDress(RoomMicDress.RoomDressType.T_Effects,mCurrentRoomInfo.usedMicEffectId) + } + return null + } + + private fun getRoomMicDress(type:Int,id:Int) : RoomMicDress ?{ + var data : RoomMicDress?=null; + if (mClientResource?.roomMicDressList.isVerify()) { + mClientResource?.roomMicDressList?.forEachIndexed { index, roomMicDress -> + if (roomMicDress.dressType == type) { + if (roomMicDress.id == id) { + data = roomMicDress + } + } + } + } + return data + } + + private fun preLoad(clientResource: ClientResource) { + GlobalScope.launch { + clientResource?.roomMicDressList?.forEach { + delay(500) + doLoad(it.normalMicLockUrl) + doLoad(it.normalMicLockUrl) + doLoad(it.bossMicUrl) + doLoad(it.bossMicLockUrl) + } + } + } + + private fun doLoad(url: String) { + if (url.isVerify()) { + "预加载 -> ResourceManager doLoad url = $url".doLog(needLog) + GlideUtils.instance().downloadFromUrl2(AppUtils.getApp(),url,object : RequestListener { + override fun onLoadFailed( + e: GlideException?, + model: Any?, + target: Target?, + isFirstResource: Boolean + ): Boolean { + "预加载 -> ResourceManager onLoadFailed error = ${e?.message} url = $url".doLog(needLog) + return true + } + + override fun onResourceReady( + resource: File?, + model: Any?, + target: Target?, + dataSource: DataSource?, + isFirstResource: Boolean + ): Boolean { + "预加载 -> ResourceManager onResourceReady Success url = $url".doLog(needLog) + return true + } + }) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/utils/RoomBoomManager.kt b/app/src/main/java/com/chwl/app/utils/RoomBoomManager.kt new file mode 100644 index 0000000..327976e --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/RoomBoomManager.kt @@ -0,0 +1,304 @@ +package com.chwl.app.utils + +import android.annotation.SuppressLint +import android.widget.FrameLayout +import com.bumptech.glide.load.DataSource +import com.bumptech.glide.load.engine.GlideException +import com.bumptech.glide.request.RequestListener +import com.bumptech.glide.request.target.Target +import com.chwl.app.application.GlobalHandleManager +import com.chwl.app.avroom.dialog.RoomBoomRewardDialog +import com.chwl.app.avroom.widget.GalleryLayoutManager.LayoutParams +import com.chwl.core.gift.bean.BoomInfo +import com.chwl.core.gift.bean.BoomMsgAnimBean +import com.chwl.core.gift.bean.BoomMsgAwardList +import com.chwl.core.gift.bean.BoomMsgDialogBean +import com.chwl.core.gift.bean.BoomMsgExpPushBean +import com.chwl.core.gift.bean.RoomNotifyDialogBean +import com.chwl.core.im.custom.bean.BoomMsgAttachment +import com.chwl.core.im.custom.bean.CustomAttachment.BOOM_FIRST +import com.chwl.core.im.custom.bean.CustomAttachment.BOOM_SECOND_DIALOG +import com.chwl.core.im.custom.bean.CustomAttachment.BOOM_SECOND_EXP_PUSH +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.manager.IMNetEaseManager +import com.chwl.core.manager.RoomEvent +import com.chwl.core.utils.LogUtils +import com.chwl.library.common.glide.GlideUtils +import com.chwl.library.common.util.isVerify +import com.tencent.qgame.animplayer.AnimConfig +import com.tencent.qgame.animplayer.AnimView +import com.tencent.qgame.animplayer.inter.IAnimListener +import java.io.File +import java.util.LinkedList + +@SuppressLint("StaticFieldLeak") +object RoomBoomManager { + + private val AnimQueue = LinkedList() + private val awardQueue = LinkedList() + private var mAnimLayout: FrameLayout? = null + + var boomInfo : List? = null + + var mRoomUid = -1L + + fun addDialog(data: BoomMsgDialogBean) { + if (!AvRoomDataManager.get().hasAvRoomAct) return + LogUtils.dd(" RoomBoomManager addDialog() ") + RoomNotifyDialogManager.addDialog(RoomNotifyDialogBean(BOOM_FIRST, BOOM_SECOND_DIALOG,data)) + } + + + + fun addAnim(data: BoomMsgAnimBean) { + LogUtils.dd(" RoomBoomManager addAnim()-- start") + if (mAnimLayout == null) return + AnimQueue.add(data) + LogUtils.dd(" RoomBoomManager addAnim()-- end") + showNextAnim() + } + + private fun showNextAnim() { + LogUtils.dd(" RoomBoomManager showNextAnim()-- start") + if (AnimQueue.isNotEmpty() && mAnimLayout != null && !isAnimStart) { +// val animData = AnimQueue.removeAt(0) + val minBy = AnimQueue.minBy { it.level } + val index = AnimQueue.indexOf(minBy) + val animData = AnimQueue.removeAt(index) + animData?.let { anim -> + val urls = arrayListOf() + if (anim.countDownUrl.isVerify()) urls.add(anim.countDownUrl) + if (anim.endUrl.isVerify()) urls.add(anim.endUrl) + LogUtils.dd(" RoomBoomManager showNextAnim()-- end") + startDownAnim(urls, anim) + } + + } + } + + var isAnimStart = false + private fun startDownAnim(urls: ArrayList, animData: BoomMsgAnimBean) { + LogUtils.dd(" RoomBoomManager startDownAnim()") + if (urls.isVerify()) { + isAnimStart = true + urls.forEach { url -> + LogUtils.dd(" RoomBoomManager startDownAnim() forEach url=$url") + mAnimLayout?.let { animLayout -> + GlideUtils.instance().downloadFromUrl2( + animLayout.context, + url.trim(), + object : RequestListener { + override fun onLoadFailed( + e: GlideException?, + model: Any?, + target: Target?, + isFirstResource: Boolean + ): Boolean { + LogUtils.dd(" RoomBoomManager onLoadFailed()-- end url=$url") + startShowAnim(animLayout, animData, true) + return true + } + + override fun onResourceReady( + resource: File?, + model: Any?, + target: Target?, + dataSource: DataSource?, + isFirstResource: Boolean + ): Boolean { + LogUtils.dd(" RoomBoomManager onResourceReady()-- end url=$url") + resource?.let { file -> + if (url == animData.countDownUrl) { + animData.countDownFile = file + } else if (url == animData.endUrl) { + animData.endFile = file + } + } + startShowAnim(animLayout, animData) + return true + } + }) + } + } + } + } + + + private fun startShowAnim( + animLayout: FrameLayout, + animData: BoomMsgAnimBean, + isFailed: Boolean = false + ) { + LogUtils.dd(" RoomBoomManager startShowAnim()-- animData=$animData isFailed=$isFailed") + if (isFailed) { + startAnimEnd(animData) + } else { + if (animData.countDownFile != null && animData.endFile != null) { + isAnimStart = true + playerAnim(animLayout, animData.countDownFile) { + isAnimStart = true + playerAnim(animLayout, animData.endFile) { + isAnimStart = true + LogUtils.dd(" RoomBoomManager startShowAnim() playerAnim-onVideoComplete() endFile ") + mAnimLayout?.post { + showAwardDialog(animData) + } + } + } + } + } + } + + private fun playerAnim(animLayout: FrameLayout,file: File,onComplete : ()->Unit) { + LogUtils.dd(" RoomBoomManager playerAnim --start file=${file.name}") + animLayout.post { + animLayout.removeAllViews() + val animView = AnimView(animLayout.context) + animLayout.addView(animView) + val layoutParams = animView.layoutParams + layoutParams.width = LayoutParams.MATCH_PARENT + layoutParams.height = LayoutParams.MATCH_PARENT + animView.layoutParams = layoutParams +// animView.setLoop(1) + animView.setAnimListener(object : IAnimListener { + override fun onFailed(errorType: Int, errorMsg: String?) { + LogUtils.dd(" RoomBoomManager playerAnim --playAnim onFailed() file=${file.name} ") + } + + override fun onVideoComplete() { + LogUtils.dd(" RoomBoomManager playerAnim --playAnim onVideoComplete() file=${file.name} ") + isAnimStart = false + onComplete() + } + + override fun onVideoDestroy() { + LogUtils.dd(" RoomBoomManager playerAnim --playAnim onVideoDestroy() file=${file.name} ") + } + + override fun onVideoRender(frameIndex: Int, config: AnimConfig?) { + + } + + override fun onVideoStart() { + LogUtils.dd(" RoomBoomManager playerAnim --playAnim onVideoStart file=${file.name} ") + } + }) + animView.startPlay(file) + } + LogUtils.dd(" RoomBoomManager playerAnim --end file=${file.name} ") + } + + private fun startAnimEnd(animData: BoomMsgAnimBean, needRemove:Boolean = true) { + LogUtils.dd(" RoomBoomManager startAnimEnd ") + isAnimStart = false + if (awardQueue.isVerify()) { + var awardIndex = -1 + awardQueue.forEachIndexed { index, boomMsgAwardList -> + if (boomMsgAwardList.list.isVerify()) { + if (animData.level == (boomMsgAwardList.list?.get(0)?.level ?: -1)){ + awardIndex = index + } + } + } + LogUtils.dd(" RoomBoomManager startAnimEnd find awardIndex =$awardIndex") + if (awardIndex != -1) { + if (needRemove) awardQueue.removeAt(awardIndex) + } + } + showNextAnim() + } + + + fun addAward(awardList: BoomMsgAwardList) { + LogUtils.dd(" RoomBoomManager addAward() -- start") + if (mAnimLayout == null) return + awardQueue.add(awardList) + LogUtils.dd(" RoomBoomManager addAward() -- end") + } + + private fun showAwardDialog(animData: BoomMsgAnimBean) { + LogUtils.dd(" RoomBoomManager showAwardDialog ") + try { + if (awardQueue.isVerify()) { + var awardIndex = -1 + awardQueue.forEachIndexed { index, boomMsgAwardList -> + if (boomMsgAwardList.list.isVerify()) { + if (animData.level == (boomMsgAwardList.list?.get(0)?.level ?: -1)) { + awardIndex = index + } + } + } + + LogUtils.dd(" RoomBoomManager showAwardDialog find awardIndex = $awardIndex") + + if (awardIndex != -1) { + val award = awardQueue.removeAt(awardIndex) + if (award.list.isVerify()) { + val activity = GlobalHandleManager.get().activity ?: return + val dialog = RoomBoomRewardDialog(activity) + dialog.list = award.list + dialog.setOnDismissListener { + startAnimEnd(animData, false) + } + dialog.showDialog() + LogUtils.dd(" RoomBoomManager showAwardDialog showDialog ") + }else{ + startAnimEnd(animData) + } + } else { + startAnimEnd(animData) + } + } else { + startAnimEnd(animData) + } + } catch (e: Exception) { + startAnimEnd(animData) + } + + LogUtils.dd(" RoomBoomManager showAwardDialog -- end") + } + + fun init(view: FrameLayout) { + mAnimLayout = view + } + + fun notify(bean: BoomMsgDialogBean) { + LogUtils.dd(" RoomBoomManager notify()-- BOOM_SECOND_EXP_PUSH start") + // BOOM_SECOND_DIALOG 是广播消息,在BaseAct 处理 + val msg = BoomMsgAttachment(BOOM_FIRST,BOOM_SECOND_EXP_PUSH) + msg.expPushBean = BoomMsgExpPushBean().apply { + pic = bean.pic + level = bean.level + speed = 0 + } + IMNetEaseManager.get().chatRoomEventObservable.onNext( + RoomEvent() + .setEvent(RoomEvent.MSG_BOOM) + .setBoomMsg(msg) + ) + + LogUtils.dd(" RoomBoomManager notify()-- BOOM_SECOND_DIALOG start") + + val msg2 = BoomMsgAttachment(BOOM_FIRST,BOOM_SECOND_DIALOG) + msg2.DialogBean = bean + IMNetEaseManager.get().chatRoomEventObservable.onNext( + RoomEvent() + .setEvent(RoomEvent.MSG_BOOM) + .setBoomMsg(msg2) + ) + LogUtils.dd(" RoomBoomManager notify()-- end") + } + + fun clear() { + mAnimLayout = null + AnimQueue.clear() + awardQueue.clear() + boomInfo = null + } + + fun clearQueue() { + AnimQueue.clear() + awardQueue.clear() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/utils/RoomHelperManager.kt b/app/src/main/java/com/chwl/app/utils/RoomHelperManager.kt new file mode 100644 index 0000000..fba9d3f --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/RoomHelperManager.kt @@ -0,0 +1,294 @@ +package com.chwl.app.utils + +import android.content.Intent +import android.icu.util.Calendar +import android.icu.util.TimeZone +import android.net.Uri +import com.chwl.app.R +import com.chwl.app.avroom.bean.LuckyBagConfig +import com.chwl.app.avroom.bean.LuckyBagEntity +import com.chwl.app.avroom.bean.RoomLuckyBagInfo +import com.chwl.app.avroom.fragment.BaseRoomFragment +import com.chwl.app.avroom.widget.LuckyBagBtn +import com.chwl.app.base.BaseFragment +import com.chwl.core.bean.response.ServiceResult +import com.chwl.core.file.FileModel +import com.chwl.core.gift.bean.RoomNotifyDialogBean +import com.chwl.core.im.custom.bean.RedPackageLuckyBagAttachment +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.manager.RoomEvent +import com.chwl.core.user.UserModel +import com.chwl.core.utils.myutil.MyUriUtils +import com.chwl.core.utils.net.RxHelper +import com.chwl.library.common.file.FileHelper +import com.chwl.library.common.util.doLog +import com.chwl.library.common.util.doToast +import com.chwl.library.common.util.doToastDeBug +import com.chwl.library.common.util.isVerify +import com.chwl.library.net.rxnet.RxNet +import com.google.gson.JsonElement +import com.hjq.toast.ToastUtils +import io.reactivex.Single +import retrofit2.http.GET +import retrofit2.http.POST +import retrofit2.http.Query +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale + +/** + * 单利工具 抽取部分逻辑 放到这里维护 + */ +object RoomHelperManager { + + var mLuckyBagConfig : LuckyBagConfig?= null + var roomUid = 0L + + + +// +// fun getTimeDown(beginTime:Long) : Long { +// var downTime = 0L +// val timez = TimeZone.getDefault() +// val localTime = System.currentTimeMillis() +// val timeOffset = timez.getOffset(localTime) +// val east8 = TimeZone.getTimeZone("Asia/Shanghai").getOffset(localTime) +//// val cTime = localTime + (east8 - timeOffset) +// val cTime = localTime; +// downTime = (beginTime - cTime).coerceAtLeast(0) / 1000 +// "倒计时 计算 localTime=$localTime timeOffset=$timeOffset east8=$east8 beginTime=$beginTime cTime=$cTime downTime=$downTime ".doLog() +// return downTime +// } + + fun getTimeDown(countDownTime: Long,countDownSecond:Int) : Long { + var downTime = 0L + val localTime = System.currentTimeMillis() + val cSecond = (localTime - countDownTime).coerceAtLeast(0) / 1000 + downTime = (countDownSecond - cSecond).coerceAtLeast(0) + "倒计时 开奖 计算 localTime=$localTime countDownTime=$countDownTime countDownSecond=$countDownSecond cSecond=$cSecond downTime=$downTime TimeString=${getTimeString(downTime)}".doLog() + return downTime + } + + + fun getTimeString(seconds:Long): String { + val minutes = seconds / 60 + val reSeconds = seconds % 60 + return String.format(Locale.ENGLISH,"%02d:%02d",minutes,reSeconds) + } + + + + fun timeToUtc(time:Long):Long{ + val calendar = Calendar.getInstance(TimeZone.getTimeZone("Asia/Shanghai")) + calendar.timeInMillis = time + + val utcCalender = Calendar.getInstance(TimeZone.getTimeZone("UTC")) + utcCalender.timeInMillis = calendar.timeInMillis + utcCalender.timeZone = TimeZone.getTimeZone("UTC") + + "倒计时 timeToUtc() time = $time utcCalender.timeInMillis=${ utcCalender.timeInMillis} ".doLog() + return utcCalender.timeInMillis + } + + + fun is8Hours() :Boolean{ + val i = TimeZone.getDefault().rawOffset / 3600000 + return i == 8 + } + + + /** + * 获取房间 红包信息 + */ + public fun getLuckyBagInfo(run:(info:RoomLuckyBagInfo)->Unit) { + val roomUid = AvRoomDataManager.get().roomUid + if (roomUid > 0) { + getRoomLuckyBagInfo(roomUid) + .doOnSuccess { + mLuckyBagConfig = it.redEnvelopeV2Config + run(it) + } + .subscribe() + } + } + public fun test(run:(info:RoomLuckyBagInfo)->Unit) { + getRoomLuckyBagInfo(3224) + .doOnSuccess { + mLuckyBagConfig = it.redEnvelopeV2Config + run(it) + } + .subscribe() + } + + + + fun onLuckyBagAdd(roomEvent: RoomEvent, luckyBagBtn: LuckyBagBtn) { + try { + val attachment = roomEvent.chatRoomMessage.attachment as RedPackageLuckyBagAttachment + if (attachment.redPackageLuckyBag?.roomUid == AvRoomDataManager.get().roomUid) { + luckyBagBtn.addData(LuckyBagEntity().apply { + beginTime = attachment.redPackageLuckyBag.beginTime + countDownSecond = attachment.redPackageLuckyBag.countDownSecond + countDownTime = System.currentTimeMillis() + type = attachment.redPackageLuckyBag.redEnvelopeType + nick = attachment.redPackageLuckyBag.sendUserNick + avatar = attachment.redPackageLuckyBag.sendUserAvatar + userId = attachment.redPackageLuckyBag.roomUid + roomUid = attachment.redPackageLuckyBag.roomUid + id = attachment.redPackageLuckyBag.redEnvelopeId + }) + } + RoomNotifyDialogManager.addDialog(RoomNotifyDialogBean(attachment.first,attachment.second,attachment.redPackageLuckyBag)) + } catch (e: Exception) { + "红包 红包推送 处理出错 ${e.message}".doLog() + } + } + + //请求 发送图片公屏消息 + fun sendPicMsg(fragment: BaseRoomFragment<*, *>, data: Intent?) { + fragment?.context?.let { context -> + data?.data?.let { uri -> + try { + val date = Date(System.currentTimeMillis()) + val dateFormat = SimpleDateFormat("MMddHHmmssSS") + val nowTime = dateFormat.format(date) + val localeUri = Uri.parse("file://${FileHelper.getRootCacheDir()?.path}/${nowTime}.jpg") + + val isCopy = MyUriUtils.copyFileToUrl(context, uri, localeUri) + if (isCopy) { + if (MyUriUtils.isGif(context, localeUri)) { + ToastUtils.show(R.string.error_file_type) + } else { + FileModel.get().uploadFile(localeUri.path) + .compose(fragment.bindToLifecycle()) + .doOnSuccess { ossUrl -> + "图片上传oss成功".doToastDeBug() + try { + postSendPic(AvRoomDataManager.get().roomUid, ossUrl) + .compose(fragment.bindToLifecycle()) + .doOnSuccess { + R.string.sent_success.doToast() + } + .doOnError { + it?.message?.doToast() + } + .subscribe() + } catch (e: Exception) { + R.string.retryTips.doToast() + } + } + .doOnError { + it?.message?.doToast() + }.subscribe() + } + } else { + R.string.retryTips.doToast() + } + } catch (e: Exception) { + R.string.retryTips.doToast() + } + } + } + + } + + fun getGiftNumbers(isBag: Boolean): MutableList { + var data = mutableListOf() + + try { + val roomGiftPanelNums = ResourceManager.mClientResource?.roomGiftPanelNums + if (roomGiftPanelNums.isVerify()) { + val numbers = roomGiftPanelNums?.get(UserModel.get().cacheLoginUserInfo?.partitionId?.toString() ?: "") + if (numbers.isVerify()) { + val split = numbers?.split(",") + split?.forEach { + data.add(it.toInt()) + } + } + } + } catch (e: Exception) { + } + + if (!data.isVerify()){ + data.add(1) + data.add(7) + data.add(17) + } + + if (isBag) { + data.add(-1) + } + + return data + } + + fun shareRoomGen(fragment: BaseFragment, roomUid:Long, share:(link:String)->Unit) { + postShareGen(roomUid).compose(fragment.bindToLifecycle()) + .doOnSuccess { + if (it.isVerify()) { + share(it) + } + } + .doOnError { + it?.message?.doToast() + }.subscribe() + } + fun shareRoomGet(fragment: BaseFragment, code:String, getInfo:(link:String)->Unit) { + getShareGet(code).compose(fragment.bindToLifecycle()) + .doOnSuccess { + if (it.isVerify()) { + getInfo(it) + } + } + .doOnError { + it?.message?.doToast() + }.subscribe() + } + + private fun getRoomLuckyBagInfo(roomUid: Long): Single { + return api.getRoomLuckyBagInfo(roomUid) + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()) + } + + + private fun postSendPic(roomUid:Long,picUrl:String): Single { + return api.postSendPic(roomUid,picUrl) + .compose(RxHelper.handleIgnoreData()) + .compose(RxHelper.handleSchedulers()) + } + + private fun postShareGen(roomUid:Long): Single { + return api.postShareGen(roomUid) + .compose(RxHelper.handleStringData()) + .compose(RxHelper.handleSchedulers()) + } + private fun getShareGet(code:String): Single { + return api.getShareGet(code) + .compose(RxHelper.handleStringData()) + .compose(RxHelper.handleSchedulers()) + } + + + + private val api: Api = RxNet.create(Api::class.java); + interface Api { + + //获取 房间幸运礼包list 和 config + @GET("/new-red-envelope/list") + fun getRoomLuckyBagInfo(@Query("roomUid") roomUid: Long): Single> + + @POST("/roomScreen/sendPic") + fun postSendPic(@Query("roomUid") roomUid:Long,@Query("picUrl") picUrl:String) : Single> + + @POST("/share/gen") + fun postShareGen(@Query("targetUid") roomUid:Long) : Single> + + @GET("/share/getInfo") + fun getShareGet(@Query("code") code:String) : Single> + + + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/utils/RoomNotifyDialogManager.kt b/app/src/main/java/com/chwl/app/utils/RoomNotifyDialogManager.kt new file mode 100644 index 0000000..468588f --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/RoomNotifyDialogManager.kt @@ -0,0 +1,365 @@ +package com.chwl.app.utils + +import android.view.LayoutInflater +import android.view.View +import android.widget.FrameLayout +import com.alibaba.fastjson2.JSON +import com.chwl.app.BuildConfig +import com.chwl.app.R +import com.chwl.app.application.GlobalHandleManager +import com.chwl.app.avroom.dialog.BaseRoomNotifyDialog +import com.chwl.app.avroom.dialog.RoomNotifyBoomDialog +import com.chwl.app.avroom.dialog.RoomNotifyBravoDialog +import com.chwl.app.avroom.dialog.RoomNotifyCpBindDialog +import com.chwl.app.avroom.dialog.RoomNotifyCpGiftDialog +import com.chwl.app.avroom.dialog.RoomNotifyLevelUpDialog +import com.chwl.app.avroom.dialog.RoomNotifyLuckBagDialog +import com.chwl.app.avroom.dialog.RoomNotifyLuckyGiftDialog +import com.chwl.app.avroom.widget.CoinTipsView +import com.chwl.app.databinding.LayoutRoomNotifyBravoGiftTipBinding +import com.chwl.app.databinding.LayoutRoomNotifyLuckyGiftTipBinding +import com.chwl.core.auth.AuthModel +import com.chwl.core.gift.bean.BoomMsgDialogBean +import com.chwl.core.gift.bean.BravoGiftMsgNotifyBean +import com.chwl.core.gift.bean.BravoGiftRewardBean +import com.chwl.core.gift.bean.CpMsgBean +import com.chwl.core.gift.bean.LuckyGiftMsgAllBean +import com.chwl.core.gift.bean.LuckyGiftMsgSelfBean +import com.chwl.core.gift.bean.RoomNotifyDialogBean +import com.chwl.core.im.custom.bean.CustomAttachment +import com.chwl.core.manager.AvRoomDataManager +import com.chwl.core.redpackage.bean.RedPackageLuckyBag +import com.chwl.core.user.event.BravoCoinAnimEvent +import com.chwl.core.utils.myutil.MyUtil +import com.chwl.library.common.util.doLog +import com.chwl.library.common.util.formatToString +import com.chwl.library.common.util.postSafe +import com.chwl.library.common.util.setAutoSizeModel +import com.chwl.library.widget.SVGAView +import com.opensource.svgaplayer.SVGACallback +import org.greenrobot.eventbus.EventBus +import java.lang.String +import java.util.LinkedList +import kotlin.Double +import kotlin.Int +import kotlin.apply +import kotlin.synchronized + +/** + * //xxx 优化方案: 创建一次 飘屏, 使用后 存起来, 下次取出来复用, 避免重复创建,节省内存消耗 -> + */ +object RoomNotifyDialogManager { + private val selfQueue = LinkedList() + private val roomQueue = LinkedList() + private val queue = LinkedList() + private var dialog : BaseRoomNotifyDialog<*>?=null + + private val dialogBuffer = HashMap>() + private val luckyGiftTipPool = WeakPool(3) + private val BravoGiftTipsPool = WeakPool(3) + private var BravoGiftAnimPlayingNum = 0 + + + fun addDialog(data : RoomNotifyDialogBean) { + + if (BuildConfig.DEBUG) { + "RoomNotifyDialogManager 飘屏 addDialog = ${JSON.toJSONString(data)}".doLog() + } + + val roomUid = AvRoomDataManager.get().roomUid + val uid = AuthModel.get().currentUid + + if (data.first == CustomAttachment.CUSTOM_MSG_SUPER_LUCKY_GIFT_TEMPLATE) { + if (data.second == CustomAttachment.CUSTOM_MSG_SUPER_LUCKY_GIFT_ROOM || data.second == CustomAttachment.CUSTOM_MSG_SUPER_LUCKY_GIFT_ALL){ + if (data.data is LuckyGiftMsgAllBean){ + val luckyGiftMsgAllBean = data.data as LuckyGiftMsgAllBean + if (luckyGiftMsgAllBean.roomUid == roomUid) { + roomQueue.add(data) + } else { + queue.add(data) + } + } + }else if (data.second == CustomAttachment.CUSTOM_MSG_SUPER_BRAVO_GIFT_NOTIFY){ + if (data.data is BravoGiftMsgNotifyBean) { + val bravoGiftBean = data.data as BravoGiftMsgNotifyBean + if (bravoGiftBean.sender?.uid == uid) { + selfQueue.add(data) + }else if (bravoGiftBean.roomUid == roomUid) { + roomQueue.add(data) + } else { + queue.add(data) + } + } + } + } else if(data.first == CustomAttachment.CP_FIRST){ + if (data.data is CpMsgBean){ + val cpMsgBean = data.data as CpMsgBean + if (cpMsgBean.senderUid == uid || cpMsgBean.receiverUid == uid) { + selfQueue.add(data) + }else if (cpMsgBean.roomUid == roomUid) { + roomQueue.add(data) + } else { + queue.add(data) + } + } + }else if (data.first == CustomAttachment.BOOM_FIRST) { + if (data.data is BoomMsgDialogBean) { + val boomMsgDialogBean = data.data as BoomMsgDialogBean + if (boomMsgDialogBean.uid == uid) { + selfQueue.add(data) + }else if (boomMsgDialogBean.roomUid == roomUid) { + roomQueue.add(data) + } else { + queue.add(data) + } + } + }else if (data.first == CustomAttachment.CUSTOM_MSG_RED_PACKAGE){ + if (data.data is RedPackageLuckyBag) { + val redPackageLuckyBag = data.data as RedPackageLuckyBag + if (redPackageLuckyBag.roomUid == roomUid) { + roomQueue.add(data) + } else { + queue.add(data) + } + } + }else{ + queue.add(data) + } + showNextDialog() + } + + private fun showNextDialog() { + if (dialog?.isShowing == true){ + return + } + var data : RoomNotifyDialogBean? = null + + if (selfQueue.isNotEmpty()) { + data = selfQueue.removeAt(0) + }else if (roomQueue.isNotEmpty()) { + data = roomQueue.removeAt(0) + }else if (queue.isNotEmpty()) { + data = queue.removeAt(0) + } + + if (data != null) { + dialog = createDialog(data) + dialog?.mCallBack = object : BaseRoomNotifyDialog.CallBack { + override fun onHide() { + showNextDialog() + } + } + dialog?.showDialog() + } + + } + + private fun createDialog(bean: RoomNotifyDialogBean): BaseRoomNotifyDialog<*>?{ + var dialog : BaseRoomNotifyDialog<*>? = null + val activity = GlobalHandleManager.get().activity ?: return null + + if (bean.first == CustomAttachment.CUSTOM_MSG_SUPER_LUCKY_GIFT_TEMPLATE) { + if (bean.second == CustomAttachment.CUSTOM_MSG_SUPER_LUCKY_GIFT_ROOM || bean.second == CustomAttachment.CUSTOM_MSG_SUPER_LUCKY_GIFT_ALL){ + if (bean.data is LuckyGiftMsgAllBean){ + if (dialogBuffer.containsKey(bean.first)) { + val dialogBuffer = dialogBuffer.get(bean.first) + if (dialogBuffer is RoomNotifyLuckyGiftDialog) { + dialogBuffer?.luckyGiftMsgBean = bean.data as LuckyGiftMsgAllBean + } + return dialogBuffer + } else { + dialog = RoomNotifyLuckyGiftDialog(activity) + dialog.luckyGiftMsgBean = bean.data as LuckyGiftMsgAllBean + dialogBuffer[bean.first] = dialog + return dialog + } + } + }else if (bean.second == CustomAttachment.CUSTOM_MSG_SUPER_BRAVO_GIFT_NOTIFY){ + if (bean.data is BravoGiftMsgNotifyBean) { + dialog = RoomNotifyBravoDialog(activity).apply { + this.data = bean.data as BravoGiftMsgNotifyBean + } + } + } + } else if(bean.first == CustomAttachment.CP_FIRST){ + if (bean.data is CpMsgBean){ + if (bean.second == CustomAttachment.CP_SECOND_GIFT){ + dialog = RoomNotifyCpGiftDialog(activity).apply { + cpMsgBean = bean.data as CpMsgBean + } + }else if (bean.second == CustomAttachment.CP_SECOND_UPGRADE){ + dialog = RoomNotifyLevelUpDialog(activity).apply { + cpMsgBean = bean.data as CpMsgBean + } + }else if (bean.second == CustomAttachment.CP_SECOND_BIND){ + dialog = RoomNotifyCpBindDialog(activity).apply { + cpMsgBean = bean.data as CpMsgBean + } + } + } + + }else if (bean.first == CustomAttachment.BOOM_FIRST) { + if (bean.data is BoomMsgDialogBean) { + dialog = RoomNotifyBoomDialog(activity).apply { + this.data = bean.data as BoomMsgDialogBean + } + } + }else if (bean.first == CustomAttachment.CUSTOM_MSG_RED_PACKAGE){ + if (bean.data is RedPackageLuckyBag) { + dialog = RoomNotifyLuckBagDialog(activity).apply { + this.data = bean.data as RedPackageLuckyBag + } + } + } + return dialog + } + + + fun showLuckyGiftTipsNotify( + notifyLayout: FrameLayout, + luckyGiftMsgBean: LuckyGiftMsgSelfBean + ) { + val root: View = luckyGiftTipPool.acquire { + LayoutInflater.from(notifyLayout.context).inflate(R.layout.layout_room_notify_lucky_gift_tip, notifyLayout, false) + } + val binding: LayoutRoomNotifyLuckyGiftTipBinding = LayoutRoomNotifyLuckyGiftTipBinding.bind(root) + binding.coinNum.text = luckyGiftMsgBean.coins.toString() + binding.coinNum.setAutoSizeModel() + binding.winNum.text = luckyGiftMsgBean.times.toString() + if (luckyGiftMsgBean.level > 1) { + binding.rootView.setBackgroundResource(R.drawable.bg_lucky_gift_tip_2) + } + root.alpha = 0f + root.scaleX = 0f + root.scaleY = 0f + notifyLayout.addView(root) + GiftAnimUtil.showAnimation(root) + notifyLayout.postDelayed({ + root.animate() + .alpha(0f) + .setDuration(500) + .withEndAction { + notifyLayout.post(Runnable { + root.clearAnimation() + notifyLayout.removeView(root) + luckyGiftTipPool.release(root) + }) + } + .start() + }, 2300) + } + + + + //超级礼物中奖提示 + fun showBravoGiftTipsNotify( layout: FrameLayout, data: BravoGiftRewardBean,coinView:CoinTipsView) { +// "超级礼物中奖提示消息 接收 = data = ${JSON.toJSONString(data)}".doLog() + synchronized(this){ +// "超级礼物中奖提示消息 开始执行".doLog() + + val roomUid = AvRoomDataManager.get().roomUid + if (roomUid <= 0 || data.uid <= 0 || data.roomUid <= 0) return + if (!AvRoomDataManager.get().isCurrentRoom(roomUid)) return + + //发送主播动效消息 + val bravoCoinAnimEvent = BravoCoinAnimEvent() + bravoCoinAnimEvent.data = data + EventBus.getDefault().post(bravoCoinAnimEvent) + + //被送超级礼物金币增加 + if (data.receiverUidList?.contains(AuthModel.get().currentUid) == true) { +// "执行了加金币 被送超级礼物金币增加 = ${data.receiverProfit}".doLog() + coinView.showView(String.valueOf(data.receiverProfit), true,true) +// coinView.plusCoin(data.receiverProfit.toInt()) //手动调整下金币显示 + } + + + if (data?.tip != null && AuthModel.get().isMy(data.uid)) { + val root: View = BravoGiftTipsPool.acquire { + LayoutInflater.from(layout.context).inflate(R.layout.layout_room_notify_bravo_gift_tip, layout, false) + } + val binding: LayoutRoomNotifyBravoGiftTipBinding = LayoutRoomNotifyBravoGiftTipBinding.bind(root) + binding.coinNum.text = data?.tip?.coins?.formatToString() + binding.coinNum.setAutoSizeModel() + binding.winNum.text = data?.tip?.times?.formatToString() + if ((data?.tip?.level ?: 0) == 3) { + binding.rootView.setBackgroundResource(R.drawable.bg_bravo_gift_2) + } + + root.alpha = 0f + root.scaleX = 0f + root.scaleY = 0f + layout.addView(root) + GiftAnimUtil.showAnimation(root) + layout.postDelayed({ + root.animate() + .alpha(0f) + .setDuration(500) + .withEndAction { + layout.post(Runnable { + root.clearAnimation() + layout.removeView(root) + BravoGiftTipsPool.release(root) + }) + } + .start() + }, 2300) + + //中奖展示金币增加 + coinView.showView(String.valueOf( (data?.tip?.coins?:0.0).formatToString()), true) +// "执行了加金币 中奖展示金币增加 = ${data?.tip?.coins}".doLog() + + if (!AvRoomDataManager.get().mIsNeedGiftEffect) return +// "data?.tip?.level=${data?.tip?.level}".doLog() + if ((data?.tip?.level ?: 0) < 3) return + if (MyUtil.isDoubleClick()) return +// "判断是否可以播放 BravoGiftAnimPlayingNum = $BravoGiftAnimPlayingNum".doLog() + if (BravoGiftAnimPlayingNum >= 3) return + val svgaView = SVGAView(layout.context) + layout.addView(svgaView,0) + svgaView.loops = 1 + svgaView.clearsAfterStop = true + svgaView.clearsAfterDetached = true + svgaView.callback = object : SVGACallback { + override fun onFinished() { + BravoGiftAnimPlayingNum-- + layout.postSafe { + layout.removeView(svgaView) + } + } + override fun onPause() { + } + override fun onRepeat() { + } + override fun onStep(frame: Int, percentage: Double) { + } + } + svgaView.loadFileHasCallBack("svga/bravo_anim.svga") { isSuccess -> + if (isSuccess) { + BravoGiftAnimPlayingNum++ + } + } + } + } + } + + + + //添加超级礼物主播奖励 动画队列 + + fun clear() { + dialogBuffer?.clear() + queue?.clear() + selfQueue?.clear() + roomQueue?.clear() + luckyGiftTipPool?.clear() + BravoGiftTipsPool?.clear() + dialog?.clearDialog() + dialog = null + BravoGiftAnimPlayingNum = 0 + + } + + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/utils/ShareManager.kt b/app/src/main/java/com/chwl/app/utils/ShareManager.kt new file mode 100644 index 0000000..8cb223e --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/ShareManager.kt @@ -0,0 +1,115 @@ +package com.chwl.app.utils + +import android.content.Context +import android.content.Intent +import com.alibaba.fastjson2.JSON +import com.chwl.app.BuildConfig +import com.chwl.app.R +import com.chwl.app.avroom.activity.AVRoomActivity +import com.chwl.app.base.BaseActivity +import com.chwl.app.base.BaseFragment +import com.chwl.app.ui.bean.ShareInfo +import com.chwl.app.ui.link.LinkHelper +import com.chwl.app.ui.webview.CommonWebViewActivity +import com.chwl.core.UriProvider +import com.chwl.core.bean.response.ServiceResult +import com.chwl.core.utils.net.RxHelper +import com.chwl.library.common.util.doLog +import com.chwl.library.common.util.doToast +import com.chwl.library.common.util.isVerify +import com.chwl.library.net.rxnet.RxNet +import com.example.lib_utils.ktx.getString +import io.reactivex.Single +import retrofit2.http.GET +import retrofit2.http.POST +import retrofit2.http.Query + +object ShareManager { + + private val TYPE_ENTER_ROOM = 1; // 跳房间 + private val TYPE_ENTER_EVENT = 2; // 跳活动 + private val CODE = "code" + + + fun shareRoomGen(fragment: BaseFragment, roomUid:Long, share:(link:String)->Unit) { + postShareGen(roomUid).compose(fragment.bindToLifecycle()) + .doOnSuccess { + if (it.isVerify()) { + share(it) + } + } + .doOnError { + it?.message?.doToast() + }.subscribe() + } + + fun shareRoomGet(act: BaseActivity, getInfo:(link:String)->Unit) { + val code = LinkHelper.getLinkIntent()?.uri?.getQueryParameter(CODE) + if (code.isVerify()) { + getShareGet(code!!).compose(act.bindToLifecycle()) + .doOnSuccess { + + if (BuildConfig.DEBUG) { + "邀请码解析 = ${JSON.toJSONString(it)}".doLog() + } + + it?.let { info-> + when (info.shareType) { + TYPE_ENTER_ROOM -> { + if (it.targetUid > 0) { + AVRoomActivity.start(act, it.targetUid) + } + } + TYPE_ENTER_EVENT -> { + if (it.targetId.isVerify()) { + try { + CommonWebViewActivity.start(act,UriProvider.getEventDetail(it.targetId.toLong())) + } catch (e: Exception) { + } + } + } + else -> {} + } + } + LinkHelper.setLinkIntent(null) + } + .doOnError { + it?.message?.doToast() + }.subscribe() + } + } + + fun showShareAction(context:Context, string: String) { + val shareIntent = Intent(Intent.ACTION_SEND) + shareIntent.setType("text/plain") + shareIntent.putExtra(Intent.EXTRA_TEXT, string) + context.startActivity(Intent.createChooser(shareIntent, R.string._ver_24_share.getString())) + } + + private fun postShareGen(roomUid:Long): Single { + return api.postShareGen(roomUid) + .compose(RxHelper.handleStringData()) + .compose(RxHelper.handleSchedulers()) + } + private fun getShareGet(code:String): Single { + return api.getShareGet(code) + .compose(RxHelper.handleBeanData()) + .compose(RxHelper.handleSchedulers()) + } + + + + private val api: Api = RxNet.create(Api::class.java); + private interface Api { + + + + @POST("/share/gen") + fun postShareGen(@Query("targetUid") roomUid:Long) : Single> + + @GET("/share/getInfo") + fun getShareGet(@Query("code") code:String) : Single> + + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/utils/SpannableBuilder.java b/app/src/main/java/com/chwl/app/utils/SpannableBuilder.java new file mode 100644 index 0000000..35b0c39 --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/SpannableBuilder.java @@ -0,0 +1,73 @@ +package com.chwl.app.utils; + +import android.content.Context; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.TextUtils; +import android.text.style.ForegroundColorSpan; + + +/** + * 这里独立写一个不再引用公屏那个,怕万一公屏改动,影响范围太大 + * Created by lvzebiao on 2019/2/27. + */ + +public class SpannableBuilder { + private SpannableStringBuilder builder; + + public SpannableBuilder() { + builder = new SpannableStringBuilder(); + } + + /** + * @param text 文字 + * @return -返回一个spannableStringBuilder + */ + public SpannableBuilder append(CharSequence text) { + if (TextUtils.isEmpty(text)) return this; + builder.append(text); + return this; + } + + /** + * @param text -文字 + * @param what -span类型 + * @return -返回一个spannableStringBuilder + */ + public SpannableBuilder append(CharSequence text, Object what) { + if (TextUtils.isEmpty(text)) return this; + int start = builder.length(); + builder.append(text); + builder.setSpan(what, start, builder.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + return this; + } + + /** + * 支持多個spannable 對同一段文字修改 + * + * @param text + * @param what + * @return + */ + public SpannableBuilder append(CharSequence text, Object... what) { + if (TextUtils.isEmpty(text)) return this; + int start = builder.length(); + builder.append(text); + for (int i = 0; i < what.length; i++) { + Object o = what[i]; + if (o == null) { + continue; + } + builder.setSpan(what[i], start, builder.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + } + return this; + } + + public SpannableStringBuilder build() { + return builder; + } + + public static ForegroundColorSpan createColor(Context context, int color) { + return new ForegroundColorSpan(context.getResources().getColor(color)); + } +} diff --git a/app/src/main/java/com/chwl/app/utils/ThreadUtil.java b/app/src/main/java/com/chwl/app/utils/ThreadUtil.java new file mode 100644 index 0000000..8bedb76 --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/ThreadUtil.java @@ -0,0 +1,136 @@ +package com.chwl.app.utils; + +import android.os.Handler; +import android.os.Looper; + +import com.chwl.app.R; +import com.chwl.library.utils.ResUtil; + +import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * Created by xiongxuesong-pc on 2016/6/1. + */ +public class ThreadUtil { + private static ThreadUtil.ThreadPool mThreadPool = getThreadPool(); + private static Handler mHandler; + + private ThreadUtil() { + } + + /** + * 在子线程执行任务 + * + * @param task + */ + public static void runInThread(Runnable task) { + mThreadPool.execute(task); + } + + /** + * 清理线程中的问题; + * + * @param task + */ + public static void cancelThread(Runnable task) { + mThreadPool.cancel(task); + } + + // ///////////////判断当前是否在主线程运行/////////////////// + public static boolean isRunOnUiThread() { + // 获取当前线程id, 如果当前线程id等于主线程id, 那就说明当前是在主线程 + return android.os.Process.myTid() == getMainThreadId(); + } + + private static int getMainThreadId() { + return android.os.Process.myTid(); + } + + /** + * 在UI线程执行任务 + * + * @param task + */ + public static void runOnUiThread(Runnable task) { + // 判断当时是否是主线程,如果是,就直接运行 + if (isRunOnUiThread()) { + // 当前就是主线程 + task.run(); + } else { + // 不是主线程, 需要运行在主线程 + // handler处理发送Message之外,也可以发送一个Runnable对象,也是运行在主线程的 + mHandler.post(task); + } + } + + + /** + * 在UI线程延时执行任务 + * + * @param task + * @param delayMillis 延时时间,单位毫秒 + */ + public static void runInUIThread(Runnable task, long delayMillis) { + mHandler.postDelayed(task, delayMillis); + } + + + /** + * 获取单例的线程池对象 + * + * @return + */ + public static ThreadUtil.ThreadPool getThreadPool() { + + if (mThreadPool == null) { + synchronized (ThreadUtil.class) { + if (mThreadPool == null) { + // cpu个数 + int cpuNum = Runtime.getRuntime().availableProcessors(); + int count = cpuNum * 2 + 1; + System.out.println(ResUtil.getString(R.string.erban_utils_threadutil_01) + cpuNum); + mThreadPool = new ThreadPool(count, count, 0L); + mHandler = new Handler(Looper.getMainLooper()); + } + } + } + + return mThreadPool; + } + + + public static class ThreadPool { + + private int corePoolSize;// 核心线程数 + private int maximumPoolSize;// 最大线程数 + private long keepAliveTime;// 保持活跃时间(休息时间) + + private ThreadPoolExecutor executor; + + private ThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime) { + this.corePoolSize = corePoolSize; + this.maximumPoolSize = maximumPoolSize; + this.keepAliveTime = keepAliveTime; + } + + public void execute(Runnable r) { + + if (executor == null) { + executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, new LinkedBlockingDeque(), + Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy()); + } + executor.execute(r);// 将当前Runnable对象放在线程池中 + } + + // 移除任务 + public void cancel(Runnable r) { + if (executor != null) { + executor.getQueue().remove(r);// 从下载队列中移除下载任务 + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/utils/TimeUiUtils.java b/app/src/main/java/com/chwl/app/utils/TimeUiUtils.java new file mode 100644 index 0000000..0995456 --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/TimeUiUtils.java @@ -0,0 +1,35 @@ +package com.chwl.app.utils; + +import com.chwl.app.R; +import com.chwl.library.utils.ResUtil; +import com.chwl.library.utils.TimeUtils; + +/** + * create by lvzebiao @2019/11/21 + */ +public class TimeUiUtils { + + public static String getDynamicUi(long ms) { + try { + long currMs = System.currentTimeMillis(); + long distanceMs = currMs - ms; + if (distanceMs < TimeUtils.MILLIS_OF_A_MINUTE) { + return ResUtil.getString(R.string.erban_utils_timeuiutils_01); + } + if (distanceMs < TimeUtils.MILLIS_OF_A_HOUR) { + return (int)(distanceMs / TimeUtils.MILLIS_OF_A_MINUTE) + ResUtil.getString(R.string.erban_utils_timeuiutils_02); + } + if (TimeUtils.isToday(ms)) { + return TimeUtils.getDateTimeString(ms, "HH:mm"); + } + if (TimeUtils.isSameYear(ms)) { + return TimeUtils.getDateTimeString(ms, "MM-dd"); + } + return TimeUtils.getDateTimeString(ms, "yyyy-MM-dd"); + } catch (Exception ex) { + ex.printStackTrace(); + } + return ""; + } + +} diff --git a/app/src/main/java/com/chwl/app/utils/UserUtils.java b/app/src/main/java/com/chwl/app/utils/UserUtils.java new file mode 100644 index 0000000..775f38f --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/UserUtils.java @@ -0,0 +1,37 @@ +package com.chwl.app.utils; + +import com.chwl.core.auth.AuthModel; +import com.chwl.core.manager.AvRoomDataManager; +import com.chwl.core.user.UserModel; +import com.chwl.core.user.bean.UserInfo; + + +public class UserUtils { + + public static UserInfo getUserInfo() { + return UserModel.get().getCacheLoginUserInfo(); + } + + public static long getUserUid() { + return AuthModel.get().getCurrentUid(); + } + + public static long getCurrentRoomUid() { + if (AvRoomDataManager.get().mCurrentRoomInfo == null) return 0; + return AvRoomDataManager.get().mCurrentRoomInfo.getUid(); + } + + public static long getCurrentRoomId() { + if (AvRoomDataManager.get().mCurrentRoomInfo == null) return 0; + return AvRoomDataManager.get().mCurrentRoomInfo.getRoomId(); + } + + public static int getExpLevel() { + UserInfo userInfo = UserModel.get().getCacheLoginUserInfo(); + if (userInfo != null && userInfo.getUserLevelVo() != null) { + return userInfo.getUserLevelVo().getExperLevelSeq(); + } + return 0; + } + +} diff --git a/app/src/main/java/com/chwl/app/utils/VapAnimListener.java b/app/src/main/java/com/chwl/app/utils/VapAnimListener.java new file mode 100644 index 0000000..c285625 --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/VapAnimListener.java @@ -0,0 +1,43 @@ +package com.chwl.app.utils; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.tencent.qgame.animplayer.AnimConfig; +import com.tencent.qgame.animplayer.inter.IAnimListener; + +public class VapAnimListener implements IAnimListener { + @Override + public void onFailed(int i, @Nullable String s) { + //播放发送错误,可能回调多次 + } + + @Override + public boolean onVideoConfigReady(@NonNull AnimConfig animConfig) { + return false; + } + + @Override + public void onVideoStart() { + //开始播放 + + } + + @Override + public void onVideoRender(int i, @Nullable AnimConfig animConfig) { + //每一帧的回调 + + } + + @Override + public void onVideoComplete() { + //播放结束,播放失败也会回调 + + } + + @Override + public void onVideoDestroy() { + //播放器被销毁 + + } +} diff --git a/app/src/main/java/com/chwl/app/utils/VpSwipeRefreshLayout.java b/app/src/main/java/com/chwl/app/utils/VpSwipeRefreshLayout.java new file mode 100644 index 0000000..1e2a74d --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/VpSwipeRefreshLayout.java @@ -0,0 +1,60 @@ +package com.chwl.app.utils; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.ViewConfiguration; + +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +public class VpSwipeRefreshLayout extends SwipeRefreshLayout { + + private float startY; + private float startX; + // 记录viewPager是否拖拽的标记 + private boolean mIsVpDragger; + private final int mTouchSlop; + + public VpSwipeRefreshLayout(Context context, AttributeSet attrs) { + super(context, attrs); + mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + int action = ev.getAction(); + switch (action) { + case MotionEvent.ACTION_DOWN: + // 记录手指按下的位置 + startY = ev.getY(); + startX = ev.getX(); + // 初始化标记 + mIsVpDragger = false; + break; + case MotionEvent.ACTION_MOVE: + // 如果viewpager正在拖拽中,那么不拦截它的事件,直接return false; + if(mIsVpDragger) { + return false; + } + + // 获取当前手指位置 + float endY = ev.getY(); + float endX = ev.getX(); + float distanceX = Math.abs(endX - startX); + float distanceY = Math.abs(endY - startY); + // 如果X轴位移大于Y轴位移,那么将事件交给viewPager处理。 + if(distanceX > mTouchSlop && distanceX > distanceY) { + mIsVpDragger = true; + return false; + } + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + // 初始化标记 + mIsVpDragger = false; + break; + } + // 如果是Y轴位移大于X轴,事件交给swipeRefreshLayout处理。 + return super.onInterceptTouchEvent(ev); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/utils/WeakPool.kt b/app/src/main/java/com/chwl/app/utils/WeakPool.kt new file mode 100644 index 0000000..0f89c8d --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/WeakPool.kt @@ -0,0 +1,62 @@ +package com.chwl.app.utils + +import androidx.core.util.Pools.Pool +import java.lang.ref.WeakReference +import java.util.LinkedList + +/** + * @Author Vance + * Date:2023/12/22 0022 14:26 + */ +class WeakPool(private var maxPoolSize: Int):Pool { + + init { + if(maxPoolSize <= 0){ + maxPoolSize = 8 + } + } + + private var mPool = LinkedList>() + + fun acquire(getIfEmpty :()->T): T { + return acquire() ?: getIfEmpty() + } + + override fun acquire(): T? { + if (mPool.size == 0) { + return null + } + + while (true){ + val item = mPool.poll() ?: return null + if(item.get() != null){ + return item.get() + } + } + } + + override fun release(instance: T): Boolean { + if(mPool.size > maxPoolSize){ + if(getRealSize() > maxPoolSize){ + return false + } + } + mPool.addFirst(WeakReference(instance)) + return true + } + + private fun getRealSize():Int{ + val iterator = mPool.listIterator() + while (iterator.hasNext()){ + val item = iterator.next().get() + if(item == null){ + iterator.remove() + } + } + return mPool.size + } + + fun clear(){ + mPool.clear() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/utils/WebViewUtils.java b/app/src/main/java/com/chwl/app/utils/WebViewUtils.java new file mode 100644 index 0000000..db04a32 --- /dev/null +++ b/app/src/main/java/com/chwl/app/utils/WebViewUtils.java @@ -0,0 +1,28 @@ +package com.chwl.app.utils; + +import android.view.ViewGroup; +import android.webkit.WebView; + +/** + * + * Created by lvzebiao on 2020/2/26. + */ + +public class WebViewUtils { + + public static void releaseWeb(WebView webView) { + try { + if (webView == null) { + return; + } + if (webView.getParent() != null) { + ((ViewGroup)webView.getParent()).removeView(webView); + } + webView.destroy(); + webView = null; + } catch (Exception ex) { + ex.printStackTrace(); + } + } + +} diff --git a/app/src/main/java/com/chwl/app/view/AutoMirroredAnimView.kt b/app/src/main/java/com/chwl/app/view/AutoMirroredAnimView.kt new file mode 100644 index 0000000..ca2d688 --- /dev/null +++ b/app/src/main/java/com/chwl/app/view/AutoMirroredAnimView.kt @@ -0,0 +1,30 @@ +package com.chwl.app.view + +import android.content.Context +import android.graphics.Canvas +import android.util.AttributeSet +import androidx.annotation.Keep +import com.tencent.qgame.animplayer.AnimView + +@Keep +class AutoMirroredAnimView : AnimView { + + constructor(context: Context, attrs: AttributeSet?) : super( + context, + attrs, + 0 + ) + + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) + + override fun dispatchDraw(canvas: Canvas) { + if (layoutDirection == LAYOUT_DIRECTION_RTL) { + canvas?.scale(-1f, 1f, width / 2f, height / 2f) + } + super.dispatchDraw(canvas) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/view/AutoMirroredImageView.kt b/app/src/main/java/com/chwl/app/view/AutoMirroredImageView.kt new file mode 100644 index 0000000..f1ee060 --- /dev/null +++ b/app/src/main/java/com/chwl/app/view/AutoMirroredImageView.kt @@ -0,0 +1,30 @@ +package com.chwl.app.view + +import android.content.Context +import android.graphics.Canvas +import android.util.AttributeSet +import android.widget.ImageView + +class AutoMirroredImageView : ImageView { + constructor(context: Context?) : super(context) + constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) + constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) + + constructor( + context: Context?, + attrs: AttributeSet?, + defStyleAttr: Int, + defStyleRes: Int + ) : super(context, attrs, defStyleAttr, defStyleRes) + + override fun onDraw(canvas: Canvas) { + if (layoutDirection == LAYOUT_DIRECTION_RTL) { + canvas?.scale(-1f, 1f, width / 2f, height / 2f) + } + super.onDraw(canvas) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/view/AutoMirroredShapeableImageView.kt b/app/src/main/java/com/chwl/app/view/AutoMirroredShapeableImageView.kt new file mode 100644 index 0000000..f780556 --- /dev/null +++ b/app/src/main/java/com/chwl/app/view/AutoMirroredShapeableImageView.kt @@ -0,0 +1,23 @@ +package com.chwl.app.view + +import android.content.Context +import android.graphics.Canvas +import android.util.AttributeSet +import com.google.android.material.imageview.ShapeableImageView + +class AutoMirroredShapeableImageView : ShapeableImageView { + constructor(context: Context?) : super(context) + constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) + constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) + + override fun onDraw(canvas: Canvas) { + if (layoutDirection == LAYOUT_DIRECTION_RTL) { + canvas?.scale(-1f, 1f, width / 2f, height / 2f) + } + super.onDraw(canvas) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/view/EffectView.kt b/app/src/main/java/com/chwl/app/view/EffectView.kt new file mode 100644 index 0000000..88a7076 --- /dev/null +++ b/app/src/main/java/com/chwl/app/view/EffectView.kt @@ -0,0 +1,673 @@ +package com.chwl.app.view + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Color +import android.graphics.Matrix +import android.graphics.drawable.AnimationDrawable +import android.graphics.drawable.BitmapDrawable +import android.graphics.drawable.Drawable +import android.text.Layout +import android.text.StaticLayout +import android.text.TextPaint +import android.text.TextUtils +import android.util.AttributeSet +import android.util.LruCache +import android.view.View +import android.view.ViewGroup +import android.widget.FrameLayout +import android.widget.ImageView +import com.bumptech.glide.Glide +import com.bumptech.glide.load.DataSource +import com.bumptech.glide.load.engine.GlideException +import com.bumptech.glide.request.RequestListener +import com.bumptech.glide.request.target.Target +import com.chwl.app.R +import com.chwl.app.application.App +import com.chwl.app.utils.AnimLoadUtil +import com.chwl.app.utils.AnimLoadUtil.downLoadAvatar +import com.chwl.core.user.bean.EffectType +import com.chwl.core.utils.LogUtils +import com.chwl.library.common.glide.GlideUtils +import com.chwl.library.common.util.doLog +import com.chwl.library.common.util.isVerify +import com.chwl.library.common.util.setViewWH +import com.chwl.library.widget.SVGAView +import com.netease.nim.uikit.support.glide.GlideApp +import com.opensource.svgaplayer.SVGACallback +import com.opensource.svgaplayer.SVGADrawable +import com.opensource.svgaplayer.SVGADynamicEntity +import com.opensource.svgaplayer.SVGAImageView +import com.opensource.svgaplayer.SVGAParser +import com.opensource.svgaplayer.SVGAParser.Companion.shareParser +import com.opensource.svgaplayer.SVGAVideoEntity +import com.tencent.qgame.animplayer.AnimConfig +import com.tencent.qgame.animplayer.AnimView +import com.tencent.qgame.animplayer.inter.IAnimListener +import com.tencent.qgame.animplayer.inter.IFetchResource +import com.tencent.qgame.animplayer.mix.Resource +import java.io.BufferedInputStream +import java.io.File +import java.io.FileInputStream + +class EffectView : FrameLayout { + + constructor(context: Context) : super(context){ + init(context) + } + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs){ + init(context) + } + + var mCallBack : CallBack? = null + var hasAnimImg = false; // 图片是否可能带 序列帧动图 + var mPlayerCount = 1; + + private var mResourceUrl = "" + private var mEffectType = EffectType.IMG + + private var mImgUrlMap: HashMap? = null + private var mTextMap: HashMap? = null + + private var mTextSize = 14f + + private var mNeedLog = false + + private var mImage : ImageView? = null + private var mSvga : SVGAView? = null + private var mVap : AnimView? = null + + private fun init(context: Context) { + + } + + fun load(url: String?=null,imgUrlMap: HashMap? = null,textMap: HashMap? = null) { + this.mImgUrlMap = imgUrlMap + this.mTextMap = textMap + if (url.isVerify()) { + loadUrl(url!!) + } + } + + + private fun loadUrl(url: String) { + "EffectView loadUrl() url = $url".doLog(mNeedLog) + mResourceUrl = url + GlideUtils.instance().downloadFromUrl2(context,url,object : RequestListener { + override fun onLoadFailed( + e: GlideException?, + model: Any?, + target: Target?, + isFirstResource: Boolean + ): Boolean { + "EffectView loadUrl() downloadFromUrl2 onLoadFailed e = ${e?.message}".doLog(mNeedLog) + playCallBack(false) + return true + } + + override fun onResourceReady( + resource: File?, + model: Any?, + target: Target?, + dataSource: DataSource?, + isFirstResource: Boolean + ): Boolean { + "EffectView loadUrl() downloadFromUrl2 onResourceReady name = ${resource?.name}".doLog(mNeedLog) + if (resource != null) { + val path = resource.path + if (mResourceUrl == url) { + if (AnimLoadUtil.isImageFile(path)) { + loadEffect(EffectType.IMG,resource) + } else { + AnimLoadUtil.isSvgaFile(path){ isSvga,videoItem -> + if (isSvga) { + loadSvga(videoItem) + } else { + loadEffect(EffectType.MP4,resource) + } + } + } + } + } else { + playCallBack(false) + } + return true + } + }) + } + + private fun loadEffect(effectType: Int, resource: File) { + "EffectView loadEffect() effectType = $effectType".doLog(mNeedLog) + mEffectType = effectType + this@EffectView.post{ + if (!this@EffectView.isAttachedToWindow) return@post + this@EffectView.removeAllViews() + when (effectType) { + EffectType.IMG -> { + loadImg(resource) + } + EffectType.MP4 -> { + loadMp4(resource) + } + EffectType.SVGA -> { + loadSvga(resource) + } + } + } + } + + //加载图片 + private fun loadImg(resource: File) { + "EffectView loadImg() ".doLog(mNeedLog) + try { + val imageView = createImageView() + mImage = imageView + + Glide.with(this) + .asBitmap() + .dontAnimate() + .dontTransform() + .load(mResourceUrl) + .listener(object : RequestListener { + override fun onLoadFailed( + e: GlideException?, + model: Any?, + target: Target?, + isFirstResource: Boolean + ): Boolean { + playCallBack(false) + "EffectView loadImg() false".doLog(mNeedLog) + return true + } + + override fun onResourceReady( + resource: Bitmap?, + model: Any?, + target: Target?, + dataSource: DataSource?, + isFirstResource: Boolean + ): Boolean { + imageView?.post { + if (!imageView.isAttachedToWindow) return@post + resource?.let { + mCallBack?.onCache(resource) + imgResourceLoad(imageView,resource) + } + } + return true + } + }).submit() + + } catch (e: Exception) { + playCallBack(false) + "EffectView loadImg() false".doLog(mNeedLog) + } + + } + private fun createImageView() : ImageView { + val imageView = ImageView(context) + this@EffectView.addView(imageView) + imageView.setViewWH( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT, + false + ) + imageView.scaleType = ImageView.ScaleType.FIT_XY + return imageView + } + private fun imgResourceLoad(imageView: ImageView, resource: Bitmap) { + if (hasAnimImg) { + val split: List = split(resource) + if (split.isVerify()) { + val animationDrawable = AnimationDrawable() + for (i in split.indices) { + animationDrawable.addFrame(split[i], 200) + } + imageView.setImageDrawable(animationDrawable) + animationDrawable.isOneShot = false + animationDrawable.start() + } else { + imageView.setImageBitmap(resource) + } + "EffectView loadImg() start".doLog(mNeedLog) + playCallBack(true) + } else { + "EffectView loadImg() start".doLog(mNeedLog) + playCallBack(true) + imageView.setImageBitmap(resource) + } + } + + private fun loadMp4(resource: File) { + "EffectView loadMp4() ".doLog(mNeedLog) + try { + val animView = AnimView(context) + mVap = animView + animView.setLoop(mPlayerCount) + this@EffectView.addView(animView) + animView.setViewWH(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT,false) + animView.setAnimListener(object : IAnimListener { + override fun onFailed(errorType: Int, errorMsg: String?) { + playCallBack(false) + "EffectView loadMp4() onFailed ".doLog(mNeedLog) + } + override fun onVideoComplete() { + "EffectView loadMp4() onVideoComplete ".doLog(mNeedLog) + } + override fun onVideoDestroy() { + "EffectView loadMp4() onVideoDestroy ".doLog(mNeedLog) + } + override fun onVideoRender(frameIndex: Int, config: AnimConfig?) { + } + override fun onVideoStart() { + playCallBack(true) + "EffectView loadMp4() onVideoStart ".doLog(mNeedLog) + } + }) + + if (mImgUrlMap.isVerify()) { + //有需要嵌入的图片, 会顺带处理嵌入文字 + loadMp4InImage(animView, resource) + }else if (mImgUrlMap.isVerify() && !mImgUrlMap.isVerify()) { + // 只需要 嵌入文字 + loadMp4InText(animView, resource) + }else if (!mImgUrlMap.isVerify() && !mImgUrlMap.isVerify()) { + //不需要嵌入资源 + animView.startPlay(resource) + "EffectView loadMp4() start".doLog(mNeedLog) + } + + } catch (e: Exception) { + "EffectView loadMp4() Exception = ${e?.message}".doLog(mNeedLog) + playCallBack(false) + } + } + + private fun loadMp4InImage(animView:AnimView,resource: File) { + "EffectView loadMp4InImage() ".doLog(mNeedLog) + try { + var index = 0 + val bitmapMap = hashMapOf() + + mImgUrlMap?.keys?.forEach { key -> + val imgUrl = mImgUrlMap?.get(key)?:"" + + if (!imgUrl.isVerify()){ + "EffectView loadMp4InImage() mImgUrlMap?.get(key)?.isVerify() == false 图片url 异常".doLog(mNeedLog) + playCallBack(false) + return + } + + downLoadAvatar(imgUrl) { bitmap -> + if (bitmap == null) { + "EffectView loadMp4InImage() downLoadAvatar bitmap=null 下载图片失败 imgUrl=$imgUrl".doLog(mNeedLog) + playCallBack(false) + } else { + index++ + bitmapMap[key] = bitmap + if (index == mImgUrlMap?.keys?.size) { + + animView.setFetchResource(object : IFetchResource { + override fun fetchImage(resource: Resource, result: (Bitmap?) -> Unit) { + "EffectView loadMp4InImage() animView.setFetchResource fetchImage resource.tag = ${resource.tag}".doLog(mNeedLog) + if (bitmapMap.isEmpty()) { + result(null) + } else { + var bitmap: Bitmap? = null + bitmapMap.keys.forEach { + if (resource.tag == it) { + bitmap = bitmapMap[it] + } + } + result(bitmap) + } + } + + override fun fetchText(resource: Resource, result: (String?) -> Unit) { + var text = " " + if (mTextMap?.isEmpty() == true) { + result(text) + } else { + mTextMap?.keys?.forEach { + if (resource.tag == it) { + text = mTextMap?.get(it)?:"" + } + } + result(text) + } + "EffectView loadMp4InImage() animView.setFetchResource fetchText text.key = ${resource.tag} text.value = $text".doLog(mNeedLog) + } + + override fun releaseResource(resources: List) { + resources?.forEach { + it?.bitmap?.recycle() + } + + bitmapMap?.forEach { t, u -> + u?.recycle() + } + } + }) + animView.startPlay(resource) + "EffectView loadMp4InImage() start".doLog(mNeedLog) + } + } + + } + } + } catch (e: Exception) { + "EffectView loadMp4InImage() Exception = ${e?.message} ".doLog(mNeedLog) + } + } + + private fun loadMp4InText(animView:AnimView,resource: File) { + "EffectView loadMp4InText() ".doLog(mNeedLog) + animView.setFetchResource(object : IFetchResource { + override fun fetchImage(resource: Resource, result: (Bitmap?) -> Unit) { + result(null) + } + + override fun fetchText(resource: Resource, result: (String?) -> Unit) { + var text = " " + if (mTextMap?.isEmpty() == true) { + result(text) + } else { + mTextMap?.keys?.forEach { + if (resource.tag == it) { + text = mTextMap?.get(it)?:"" + } + } + result(text) + } + "EffectView loadMp4InImage() animView.setFetchResource fetchText text.key = ${resource.tag} text.value = $text".doLog(mNeedLog) + } + + override fun releaseResource(resources: List) { + resources?.forEach { + it?.bitmap?.recycle() + } + } + }) + animView.startPlay(resource) + "EffectView loadMp4InText() start".doLog(mNeedLog) + } + + private fun loadSvga(resource: File) { + "EffectView loadSvga() ".doLog(mNeedLog) + try { + val svgaView = createSvgaView() + mSvga = svgaView + val inputStream = BufferedInputStream(FileInputStream(resource.path)) + shareParser().decodeFromInputStream( + inputStream, + resource.path, + object : SVGAParser.ParseCompletion { + override fun onComplete(videoItem: SVGAVideoEntity) { + playSvga(svgaView,videoItem) + } + + override fun onError() { + "EffectView loadSvga() false".doLog(mNeedLog) + playCallBack(false) + } + }, + true, + null, + null + ) + } catch (e: Exception) { + "EffectView loadSvga() false".doLog(mNeedLog) + playCallBack(false) + } + } + + private fun loadSvga(videoItem: SVGAVideoEntity?) { + "EffectView loadSvga() ".doLog(mNeedLog) + try { + var mSvgaImageIndex = 0; + if (videoItem == null) { + "EffectView loadSvga() Exception videoItem=null".doLog(mNeedLog) + playCallBack(false) + return + } + + val svgaView = createSvgaView() + mSvga = svgaView + val dynamicEntity = SVGADynamicEntity() + + if (mTextMap?.isNotEmpty() == true) { + mTextMap?.keys?.forEach { key -> + val text = mTextMap?.get(key) ?: "" + if (text.isVerify()) { + val textPaint = TextPaint() + textPaint.color = Color.WHITE //字体颜色 + textPaint.textSize = mTextSize //字体大小 + dynamicEntity.setDynamicText( + StaticLayout( + text, + 0, + text.length, + textPaint, + 0, + Layout.Alignment.ALIGN_CENTER, + 1.0f, + 0.0f, + false + ), key + ) + } + } + } + + if (mImgUrlMap?.isNotEmpty() == true) { + mImgUrlMap?.keys?.forEach { key -> + val imgUrl = mImgUrlMap?.get(key)?:"" + if (imgUrl.isVerify()) { + addDynamicImage( + svgaView, + dynamicEntity, + imgUrl, + key + ) { resource -> + mSvgaImageIndex ++; + dynamicEntity.setDynamicImage(resource,key) + if (mSvgaImageIndex == mImgUrlMap?.count()) { + playSvga(svgaView, videoItem, dynamicEntity) + } + } + } + } + } + + if (mImgUrlMap?.isNotEmpty() == true) { + // 有图片, 等待下载完毕再播放svga + } else { + playSvga(svgaView, videoItem, dynamicEntity) + } + + } catch (e: Exception) { + "EffectView loadSvga() Exception = ${e?.message}".doLog(mNeedLog) + playCallBack(false) + } + } + + + private fun split(bitmap: Bitmap?): List { + "EffectView split() ".doLog(mNeedLog) + val pieces: MutableList = ArrayList() + try { + if (bitmap!!.width == bitmap.height) { + pieces.add(BitmapDrawable(bitmap)) + } else { + val matrix = Matrix() + matrix.setScale(0.5f, 0.5f) + + val width = bitmap.width + val pieceWidth = bitmap.height + val pieceHeight = bitmap.height + val xPiece = width / pieceWidth + for (j in 0 until xPiece) { + val xValue = j * pieceWidth + pieces.add( + BitmapDrawable( + Bitmap.createBitmap( + bitmap, xValue, 0, + pieceWidth, pieceHeight, matrix, true + ) + ) + ) + } + } + } catch (e: java.lang.Exception) { + "EffectView split() Exception = ${e?.message}".doLog(mNeedLog) + } + return pieces + } + + private fun addDynamicImage( + view: View, + dynamicEntity: SVGADynamicEntity, + url: String?, + forKey: String?, + imageCallBack : (resource: Bitmap)->Unit + ) { + if (TextUtils.isEmpty(url) || TextUtils.isEmpty(forKey)) { + LogUtils.d("AnimLoadUtil drawEffect addDynamicImage: url or forKey is null or empty") + return + } + GlideApp.with(App.instance()) + .asBitmap() + .load(url) + .addListener(object : RequestListener { + override fun onLoadFailed( + e: GlideException?, + model: Any, + target: Target, + isFirstResource: Boolean + ): Boolean { + imageCallBack(BitmapFactory.decodeResource(view.resources, R.drawable.default_avatar)) + return false + } + + override fun onResourceReady( + resource: Bitmap?, + model: Any, + target: Target, + dataSource: DataSource, + isFirstResource: Boolean + ): Boolean { + if (resource != null) { + imageCallBack(resource) + } + return false + } + }) + .submit() + } + + + private fun createSvgaView() :SVGAView{ + val svgaView = SVGAView(context) + this@EffectView.addView(svgaView) + svgaView.setViewWH(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT,false) + svgaView.scaleType = ImageView.ScaleType.FIT_XY + svgaView.loops = mPlayerCount + svgaView.fillMode = SVGAImageView.FillMode.Forward + svgaView.callback = object : SVGACallback { + override fun onPause() { + "EffectView loadSvga() SVGACallback onPause()".doLog(mNeedLog) + } + + override fun onFinished() { + "EffectView loadSvga() SVGACallback onFinished()".doLog(mNeedLog) + } + + override fun onRepeat() { +// "EffectView loadSvga() SVGACallback onRepeat()".doLog(mNeedLog) + } + + override fun onStep(i: Int, v: Double) { + } + } + return svgaView + } + private fun playSvga(svgaView:SVGAView,videoItem: SVGAVideoEntity,dynamicEntity: SVGADynamicEntity?=null) { + val drawable = if (dynamicEntity != null) SVGADrawable(videoItem, dynamicEntity) else SVGADrawable(videoItem) + mCallBack?.onCache(drawable) + svgaView.post { + if (!svgaView.isAttachedToWindow) return@post + svgaView.setImageDrawable(drawable) + svgaView.stepToFrame(0, true) + playCallBack(true) + "EffectView playSvga() start".doLog(mNeedLog) + } + } + + + public fun loadUrlForCache() { + + } + + + public fun setTextView(textSize: Float) { + mTextSize = textSize + } + + private fun playCallBack(isSuccess: Boolean,type: Int? = -1) { + if (isSuccess) { + "EffectView playCallBack() 加载成功 url = $mResourceUrl".doLog(mNeedLog) + } else { + "EffectView playCallBack() 加载失败 url = $mResourceUrl".doLog(mNeedLog) + } + mCallBack?.onPlay(isSuccess,type) + } + + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + "EffectView 被销毁了 $mResourceUrl".doLog(mNeedLog) + + try { + mImage?.setImageBitmap(null) + mImage = null + + mSvga?.pauseAnimation() + mSvga?.stopAnimation() + mSvga?.clearAnimation() + mSvga?.clear() + mSvga = null + + mVap?.stopPlay() + mVap?.clearAnimation() + mVap=null + + removeAllViews() + } catch (e: Exception) { + "EffectView 被销毁了,回收资源异常 ${e.message}".doLog(mNeedLog) + } + } + + public interface CallBack{ + fun onPlay(isSuccess: Boolean,type: Int? = -1) + fun onCache(resource:Any){}; + } + + + + class EffectLruCache(maxSize: Int){ + val mLruCache = LruCache(maxSize) + fun get(key: String): Any? { + return mLruCache.get(key) + } + + fun put(key: String, entity: Any) { + mLruCache.put(key, entity) + } + + fun clear() { + mLruCache.evictAll() + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/view/GenderAgeTextView.kt b/app/src/main/java/com/chwl/app/view/GenderAgeTextView.kt new file mode 100644 index 0000000..afd104a --- /dev/null +++ b/app/src/main/java/com/chwl/app/view/GenderAgeTextView.kt @@ -0,0 +1,90 @@ +package com.chwl.app.view + +import android.content.Context +import android.graphics.Color +import android.util.AttributeSet +import android.view.Gravity +import androidx.appcompat.widget.AppCompatTextView +import androidx.core.content.ContextCompat +import com.chwl.app.R +import java.util.Calendar +import java.util.Date + +class GenderAgeTextView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyle: Int = 0 +) : AppCompatTextView(context, attrs, defStyle) { + + init { + val array = + context.obtainStyledAttributes(attrs, R.styleable.GenderAgeTextView) + val gender = array.getInt(R.styleable.GenderAgeTextView_gender, 0) + array.recycle() + + setTextColor(Color.WHITE) + + minWidth = resources.getDimensionPixelOffset(R.dimen.dp_34) + gravity = Gravity.CENTER_VERTICAL + setPadding( + resources.getDimensionPixelOffset(R.dimen.dp_3), + 0, + resources.getDimensionPixelOffset(R.dimen.dp_5), + 0 + ) +// compoundDrawablePadding = resources.getDimensionPixelOffset(R.dimen.dp_2) + + setGender(gender) + setBirthDay(System.currentTimeMillis()) + } + + fun setBirthDay(ts: Long) { + text = getAgeByBirthday(Date(ts)).toString() + } + + fun setGender(gender: Int) { + setCompoundDrawablesRelativeWithIntrinsicBounds( + if (gender == GENDER_MALE) R.drawable.ic_gender_male_t else R.drawable.ic_gender_female_t, + 0, + 0, + 0 + ) + + val drawable = ContextCompat.getDrawable( + context, + if (gender == GENDER_MALE) R.drawable.bg_gender_male else R.drawable.bg_gender_female + ) + background = drawable + } + + private fun getAgeByBirthday(birthday: Date): Int { + val cal: Calendar = Calendar.getInstance() + require(!cal.before(birthday)) { "The birthDay is before Now. It's unbelievable!" } + val yearNow: Int = cal.get(Calendar.YEAR) + val monthNow: Int = cal.get(Calendar.MONTH) + 1 + val dayOfMonthNow: Int = cal.get(Calendar.DAY_OF_MONTH) + cal.time = birthday + val yearBirth: Int = cal.get(Calendar.YEAR) + val monthBirth: Int = cal.get(Calendar.MONTH) + 1 + val dayOfMonthBirth: Int = cal.get(Calendar.DAY_OF_MONTH) + var age = yearNow - yearBirth + if (monthNow <= monthBirth) { + if (monthNow == monthBirth) { + // monthNow==monthBirth + if (dayOfMonthNow < dayOfMonthBirth) { + age-- + } + } else { + // monthNow>monthBirth + age-- + } + } + return age + } + + companion object { + const val GENDER_UNKNOWN = 0 + const val GENDER_MALE = 1 + const val GENDER_FEMALE = 2 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/view/MyCircleIndicator.java b/app/src/main/java/com/chwl/app/view/MyCircleIndicator.java new file mode 100644 index 0000000..50c563a --- /dev/null +++ b/app/src/main/java/com/chwl/app/view/MyCircleIndicator.java @@ -0,0 +1,78 @@ +package com.chwl.app.view; + +import android.content.Context; +import android.graphics.Canvas; +import android.util.AttributeSet; + +import com.chwl.library.common.util.OtherExtKt; +import com.youth.banner.config.IndicatorConfig; +import com.youth.banner.indicator.BaseIndicator; + +public class MyCircleIndicator extends BaseIndicator { + private int mNormalRadius; + private int mSelectedRadius; + private int maxRadius; + + + public MyCircleIndicator(Context context) { + this(context, null); + } + + public MyCircleIndicator(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public MyCircleIndicator(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + mNormalRadius = config.getNormalWidth() / 2; + mSelectedRadius = config.getSelectedWidth() / 2; + } + + public void initView(IndicatorConfig configs) { + config = configs; + mNormalRadius = config.getNormalWidth() / 2; + mSelectedRadius = config.getSelectedWidth() / 2; + this.post(() -> { + int width = config.getSelectedWidth() + (config.getNormalWidth() * (config.getIndicatorSize() - 1)) + (config.getIndicatorSpace() * ( config.getIndicatorSize() - 1)); + OtherExtKt.setViewWH(this,width,null,false); + invalidate(); + }); + + } + + +// @Override +// protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { +// super.onMeasure(widthMeasureSpec, heightMeasureSpec); +// int count = config.getIndicatorSize(); +// if (count <= 1) { +// return; +// } +// +// mNormalRadius = config.getNormalWidth() / 2; +// mSelectedRadius = config.getSelectedWidth() / 2; +// //考虑当 选中和默认 的大小不一样的情况 +// maxRadius = Math.max(mSelectedRadius, mNormalRadius); +// //间距*(总数-1)+选中宽度+默认宽度*(总数-1) +// int width = (count - 1) * config.getIndicatorSpace() + config.getSelectedWidth() + config.getNormalWidth() * (count - 1); +// setMeasuredDimension(width, Math.max(config.getNormalWidth(), config.getSelectedWidth())); +// } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + int count = config.getIndicatorSize(); + if (count <= 1) { + return; + } + float left = 0; + for (int i = 0; i < count; i++) { + mPaint.setColor(config.getCurrentPosition() == i ? config.getSelectedColor() : config.getNormalColor()); + int indicatorWidth = config.getCurrentPosition() == i ? config.getSelectedWidth() : config.getNormalWidth(); + int radius = config.getCurrentPosition() == i ? mSelectedRadius : mNormalRadius; + canvas.drawCircle(left + radius, indicatorWidth, radius, mPaint); + left += indicatorWidth + config.getIndicatorSpace(); + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/view/NestedScrollableHost.kt b/app/src/main/java/com/chwl/app/view/NestedScrollableHost.kt new file mode 100644 index 0000000..d19d6f5 --- /dev/null +++ b/app/src/main/java/com/chwl/app/view/NestedScrollableHost.kt @@ -0,0 +1,111 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.chwl.app.view + +import android.content.Context +import android.util.AttributeSet +import android.view.MotionEvent +import android.view.View +import android.view.ViewConfiguration +import android.widget.FrameLayout +import androidx.viewpager2.widget.ViewPager2 +import androidx.viewpager2.widget.ViewPager2.ORIENTATION_HORIZONTAL +import kotlin.math.absoluteValue +import kotlin.math.sign + +/** + * Layout to wrap a scrollable component inside a ViewPager2. Provided as a solution to the problem + * where pages of ViewPager2 have nested scrollable elements that scroll in the same direction as + * ViewPager2. The scrollable element needs to be the immediate and only child of this host layout. + * + * This solution has limitations when using multiple levels of nested scrollable elements + * (e.g. a horizontal RecyclerView in a vertical RecyclerView in a horizontal ViewPager2). + */ +class NestedScrollableHost : FrameLayout { + constructor(context: Context) : super(context) + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) + + private var touchSlop = 0 + private var initialX = 0f + private var initialY = 0f + private val parentViewPager: ViewPager2? + get() { + var v: View? = parent as? View + while (v != null && v !is ViewPager2) { + v = v.parent as? View + } + return v as? ViewPager2 + } + + private val child: View? get() = if (childCount > 0) getChildAt(0) else null + + init { + touchSlop = ViewConfiguration.get(context).scaledTouchSlop + } + + private fun canChildScroll(orientation: Int, delta: Float): Boolean { + val direction = -delta.sign.toInt() + return when (orientation) { + 0 -> child?.canScrollHorizontally(direction) ?: false + 1 -> child?.canScrollVertically(direction) ?: false + else -> throw IllegalArgumentException() + } + } + + override fun onInterceptTouchEvent(e: MotionEvent): Boolean { + handleInterceptTouchEvent(e) + return super.onInterceptTouchEvent(e) + } + + private fun handleInterceptTouchEvent(e: MotionEvent) { + val orientation = parentViewPager?.orientation ?: return + + // Early return if child can't scroll in same direction as parent + if (!canChildScroll(orientation, -1f) && !canChildScroll(orientation, 1f)) { + return + } + + if (e.action == MotionEvent.ACTION_DOWN) { + initialX = e.x + initialY = e.y + parent.requestDisallowInterceptTouchEvent(true) + } else if (e.action == MotionEvent.ACTION_MOVE) { + val dx = e.x - initialX + val dy = e.y - initialY + val isVpHorizontal = orientation == ORIENTATION_HORIZONTAL + + // assuming ViewPager2 touch-slop is 2x touch-slop of child + val scaledDx = dx.absoluteValue * if (isVpHorizontal) .5f else 1f + val scaledDy = dy.absoluteValue * if (isVpHorizontal) 1f else .5f + + if (scaledDx > touchSlop || scaledDy > touchSlop) { + if (isVpHorizontal == (scaledDy > scaledDx)) { + // Gesture is perpendicular, allow all parents to intercept + parent.requestDisallowInterceptTouchEvent(false) + } else { + // Gesture is parallel, query child if movement in that direction is possible + if (canChildScroll(orientation, if (isVpHorizontal) dx else dy)) { + // Child can scroll, disallow all parents to intercept + parent.requestDisallowInterceptTouchEvent(true) + } else { + // Child cannot scroll, allow all parents to intercept + parent.requestDisallowInterceptTouchEvent(false) + } + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/view/ShadowFrameLayout.java b/app/src/main/java/com/chwl/app/view/ShadowFrameLayout.java new file mode 100644 index 0000000..9f16530 --- /dev/null +++ b/app/src/main/java/com/chwl/app/view/ShadowFrameLayout.java @@ -0,0 +1,92 @@ +package com.chwl.app.view; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.RectF; +import android.util.AttributeSet; +import android.widget.FrameLayout; + +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; + +import com.chwl.app.R; + +/** + * @author wzq + */ +public class ShadowFrameLayout extends FrameLayout { + + private Paint mShadowPaint; + private float mCornerRadius; + /** + * 只有上面有阴影 + */ + private boolean mShadowTop; + + private float mShadowRadius; + + private RectF mRectF; + + public ShadowFrameLayout(@NonNull Context context) { + this(context, null); + } + + public ShadowFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + init(context, attrs); + } + + public ShadowFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context, attrs); + } + + private void init(Context context, AttributeSet attrs) { + TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ShadowFrameLayout); + int shadowColor = typedArray.getColor(R.styleable.ShadowFrameLayout_shadowColor, + ContextCompat.getColor(context, R.color.color_1E686868)); + int backgroundColor = typedArray.getColor(R.styleable.ShadowFrameLayout_backgroundColor, Color.WHITE); + mShadowRadius = typedArray.getDimension(R.styleable.ShadowFrameLayout_shadowRadius, 0); + mCornerRadius = typedArray.getDimension(R.styleable.ShadowFrameLayout_cornerRadius, 0); + mShadowTop = typedArray.getBoolean(R.styleable.ShadowFrameLayout_shadowTop, false); + typedArray.recycle(); + + mShadowPaint = new Paint(); + mShadowPaint.setShadowLayer(mShadowRadius, 0, 0, shadowColor); + mShadowPaint.setAntiAlias(true); + mShadowPaint.setColor(backgroundColor); + setLayerType(LAYER_TYPE_SOFTWARE, null); + + mRectF = new RectF(); + } + + @Override + public void setBackgroundColor(@ColorInt int color) { + mShadowPaint.setColor(color); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + int measuredWidth = getMeasuredWidth(); + int measuredHeight = getMeasuredHeight(); + if (mShadowTop) { + // 矩形只有上方有阴影 + mRectF.set(0, mShadowRadius, measuredWidth, measuredHeight + mCornerRadius); + } else { + // 环绕阴影 + mRectF.set(mShadowRadius, mShadowRadius, measuredWidth - mShadowRadius, measuredHeight - mShadowRadius); + } + } + + @Override + protected void dispatchDraw(Canvas canvas) { + canvas.drawRoundRect(mRectF, mCornerRadius, mCornerRadius, mShadowPaint); + super.dispatchDraw(canvas); + } +} diff --git a/app/src/main/java/com/chwl/app/view/WrapHeightViewPager.kt b/app/src/main/java/com/chwl/app/view/WrapHeightViewPager.kt new file mode 100644 index 0000000..ac5810d --- /dev/null +++ b/app/src/main/java/com/chwl/app/view/WrapHeightViewPager.kt @@ -0,0 +1,37 @@ +package com.chwl.app.view + +import android.content.Context +import android.util.AttributeSet +import android.view.View +import androidx.viewpager.widget.ViewPager + +/** + * Created by Max on 2022/10/10 15:30 + * 高度自适应(采用最大的子页面高度)-ViewPager + */ +class WrapHeightViewPager : ViewPager { + + constructor(context: Context) : this(context, null) + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + var height = 0 + for (i in 0 until childCount) { + val child: View = getChildAt(i) + child.measure( + widthMeasureSpec, + MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED) + ) + val h = child.measuredHeight + if (h > height) { + height = h + } + } + super.onMeasure( + widthMeasureSpec, MeasureSpec.makeMeasureSpec( + height, + MeasureSpec.EXACTLY + ) + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/view/layoutmanager/AutoPlayRecyclerView.java b/app/src/main/java/com/chwl/app/view/layoutmanager/AutoPlayRecyclerView.java new file mode 100644 index 0000000..f6f2011 --- /dev/null +++ b/app/src/main/java/com/chwl/app/view/layoutmanager/AutoPlayRecyclerView.java @@ -0,0 +1,88 @@ +package com.chwl.app.view.layoutmanager; + +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.view.MotionEvent; + +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.RecyclerView; + +import com.chwl.app.R; + +/** + * An implement of {@link RecyclerView} which support auto play. + */ + +public class AutoPlayRecyclerView extends RecyclerView { + private AutoPlaySnapHelper autoPlaySnapHelper; + + public boolean autoPlayEnabled = true; + public boolean touchMoveEnabled = true; + + public AutoPlayRecyclerView(Context context) { + this(context, null); + } + + public AutoPlayRecyclerView(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public AutoPlayRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.AutoPlayRecyclerView); + final int distance = typedArray.getInt(R.styleable.AutoPlayRecyclerView_distance, 1); + final int timeInterval = typedArray.getInt(R.styleable.AutoPlayRecyclerView_timeInterval, AutoPlaySnapHelper.TIME_INTERVAL); + final int direction = typedArray.getInt(R.styleable.AutoPlayRecyclerView_direction, AutoPlaySnapHelper.RIGHT); + typedArray.recycle(); + autoPlaySnapHelper = new AutoPlaySnapHelper(timeInterval, direction, distance); + } + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + if (ev.getAction() == MotionEvent.ACTION_MOVE && !touchMoveEnabled) { + return false; + } + boolean result = super.dispatchTouchEvent(ev); + switch (ev.getAction()) { + case MotionEvent.ACTION_DOWN: + if (autoPlaySnapHelper != null) { + autoPlaySnapHelper.pause(); + } + break; + case MotionEvent.ACTION_UP: + if (autoPlaySnapHelper != null && autoPlayEnabled) { + autoPlaySnapHelper.start(); + } + } + return result; + } + + public void disableTouchMove() { + touchMoveEnabled = false; + } + + public void enableTouchMove() { + touchMoveEnabled = true; + } + + public boolean isAutoPlayEnabled() { + return autoPlayEnabled; + } + + public void start() { + autoPlayEnabled = true; + autoPlaySnapHelper.start(); + } + + public void pause() { + autoPlayEnabled = false; + autoPlaySnapHelper.pause(); + } + + @Override + public void setLayoutManager(LayoutManager layout) { + super.setLayoutManager(layout); + autoPlaySnapHelper.attachToRecyclerView(this); + } +} diff --git a/app/src/main/java/com/chwl/app/view/layoutmanager/AutoPlaySnapHelper.java b/app/src/main/java/com/chwl/app/view/layoutmanager/AutoPlaySnapHelper.java new file mode 100644 index 0000000..f5e13a1 --- /dev/null +++ b/app/src/main/java/com/chwl/app/view/layoutmanager/AutoPlaySnapHelper.java @@ -0,0 +1,115 @@ +package com.chwl.app.view.layoutmanager; + +import android.os.Handler; +import android.os.Looper; +import android.view.animation.DecelerateInterpolator; +import android.widget.Scroller; + +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.RecyclerView; + + +/** + * Used by {@link AutoPlayRecyclerView} to implement auto play effect + */ + +class AutoPlaySnapHelper extends CenterSnapHelper { + final static int TIME_INTERVAL = 2000; + + final static int LEFT = 1; + final static int RIGHT = 2; + + private Handler handler; + private int timeInterval; + private Runnable autoPlayRunnable; + private boolean runnableAdded; + private int direction; + private int distance; + + AutoPlaySnapHelper(int timeInterval, int direction, int distance) { + checkTimeInterval(timeInterval); + checkDirection(direction); + handler = new Handler(Looper.getMainLooper()); + this.timeInterval = timeInterval; + this.direction = direction; + this.distance = distance; + } + + @Override + public void attachToRecyclerView(@Nullable RecyclerView recyclerView) throws IllegalStateException { + if (mRecyclerView == recyclerView) { + return; // nothing to do + } + if (mRecyclerView != null) { + destroyCallbacks(); + } + mRecyclerView = recyclerView; + if (mRecyclerView != null) { + final RecyclerView.LayoutManager layoutManager = mRecyclerView.getLayoutManager(); + if (!(layoutManager instanceof ViewPagerLayoutManager)) return; + + setupCallbacks(); + mGravityScroller = new Scroller(mRecyclerView.getContext(), + new DecelerateInterpolator()); + + snapToCenterView((ViewPagerLayoutManager) layoutManager, + ((ViewPagerLayoutManager) layoutManager).onPageChangeListener); + + ((ViewPagerLayoutManager) layoutManager).setInfinite(true); + + autoPlayRunnable = new Runnable() { + @Override + public void run() { + ScrollHelper.scrollBy(mRecyclerView, + (ViewPagerLayoutManager) layoutManager, direction == RIGHT ? distance : -distance); + handler.postDelayed(autoPlayRunnable, timeInterval); + } + }; + handler.postDelayed(autoPlayRunnable, timeInterval); + runnableAdded = true; + } + } + + @Override + void destroyCallbacks() { + super.destroyCallbacks(); + if (runnableAdded) { + handler.removeCallbacks(autoPlayRunnable); + runnableAdded = false; + } + } + + void pause() { + if (runnableAdded) { + handler.removeCallbacks(autoPlayRunnable); + runnableAdded = false; + } + } + + void start() { + if (!runnableAdded) { + handler.postDelayed(autoPlayRunnable, timeInterval); + runnableAdded = true; + } + } + + void setTimeInterval(int timeInterval) { + checkTimeInterval(timeInterval); + this.timeInterval = timeInterval; + } + + void setDirection(int direction) { + checkDirection(direction); + this.direction = direction; + } + + private void checkDirection(int direction) { + if (direction != LEFT && direction != RIGHT) + throw new IllegalArgumentException("direction should be one of left or right"); + } + + private void checkTimeInterval(int timeInterval) { + if (timeInterval <= 0) + throw new IllegalArgumentException("time interval should greater than 0"); + } +} diff --git a/app/src/main/java/com/chwl/app/view/layoutmanager/CarouselLayoutManager.java b/app/src/main/java/com/chwl/app/view/layoutmanager/CarouselLayoutManager.java new file mode 100644 index 0000000..d7e0d56 --- /dev/null +++ b/app/src/main/java/com/chwl/app/view/layoutmanager/CarouselLayoutManager.java @@ -0,0 +1,167 @@ +package com.chwl.app.view.layoutmanager; + +import android.content.Context; +import android.view.View; + +/** + * An implementation of {@link ViewPagerLayoutManager} + * which layouts items like carousel + */ + +@SuppressWarnings({"WeakerAccess", "unused"}) +public class CarouselLayoutManager extends ViewPagerLayoutManager { + + private int itemSpace; + private float minScale; + private float moveSpeed; + + public CarouselLayoutManager(Context context, int itemSpace) { + this(new Builder(context, itemSpace)); + } + + public CarouselLayoutManager(Context context, int itemSpace, int orientation) { + this(new Builder(context, itemSpace).setOrientation(orientation)); + } + + public CarouselLayoutManager(Context context, int itemSpace, int orientation, boolean reverseLayout) { + this(new Builder(context, itemSpace).setOrientation(orientation).setReverseLayout(reverseLayout)); + } + + public CarouselLayoutManager(Builder builder) { + this(builder.context, builder.itemSpace, builder.minScale, builder.orientation, + builder.maxVisibleItemCount, builder.moveSpeed, builder.distanceToBottom, + builder.reverseLayout); + } + + private CarouselLayoutManager(Context context, int itemSpace, float minScale, int orientation, + int maxVisibleItemCount, float moveSpeed, int distanceToBottom, + boolean reverseLayout) { + super(context, orientation, reverseLayout); + setEnableBringCenterToFront(true); + setDistanceToBottom(distanceToBottom); + setMaxVisibleItemCount(maxVisibleItemCount); + this.itemSpace = itemSpace; + this.minScale = minScale; + this.moveSpeed = moveSpeed; + } + + public int getItemSpace() { + return itemSpace; + } + + public float getMinScale() { + return minScale; + } + + public float getMoveSpeed() { + return moveSpeed; + } + + public void setItemSpace(int itemSpace) { + assertNotInLayoutOrScroll(null); + if (this.itemSpace == itemSpace) return; + this.itemSpace = itemSpace; + removeAllViews(); + } + + public void setMinScale(float minScale) { + assertNotInLayoutOrScroll(null); + if (minScale > 1f) minScale = 1f; + if (this.minScale == minScale) return; + this.minScale = minScale; + requestLayout(); + } + + public void setMoveSpeed(float moveSpeed) { + assertNotInLayoutOrScroll(null); + if (this.moveSpeed == moveSpeed) return; + this.moveSpeed = moveSpeed; + } + + @Override + protected float setInterval() { + return (mDecoratedMeasurement - itemSpace); + } + + @Override + protected void setItemViewProperty(View itemView, float targetOffset) { + float scale = calculateScale(targetOffset + mSpaceMain); + itemView.setScaleX(scale); + itemView.setScaleY(scale); + } + + @Override + protected float getDistanceRatio() { + if (moveSpeed == 0) return Float.MAX_VALUE; + return 1 / moveSpeed; + } + + @Override + protected float setViewElevation(View itemView, float targetOffset) { + return itemView.getScaleX() * 5; + } + + private float calculateScale(float x) { + float deltaX = Math.abs(x - (mOrientationHelper.getTotalSpace() - mDecoratedMeasurement) / 2f); + return (minScale - 1) * deltaX / (mOrientationHelper.getTotalSpace() / 2f) + 1f; + } + + public static class Builder { + private static final float DEFAULT_SPEED = 1f; + private static final float MIN_SCALE = 0.5f; + + private Context context; + private int itemSpace; + private int orientation; + private float minScale; + private float moveSpeed; + private int maxVisibleItemCount; + private boolean reverseLayout; + private int distanceToBottom; + + public Builder(Context context, int itemSpace) { + this.itemSpace = itemSpace; + this.context = context; + orientation = HORIZONTAL; + minScale = MIN_SCALE; + this.moveSpeed = DEFAULT_SPEED; + reverseLayout = false; + maxVisibleItemCount = ViewPagerLayoutManager.DETERMINE_BY_MAX_AND_MIN; + distanceToBottom = ViewPagerLayoutManager.INVALID_SIZE; + } + + public Builder setOrientation(int orientation) { + this.orientation = orientation; + return this; + } + + public Builder setMinScale(float minScale) { + this.minScale = minScale; + return this; + } + + public Builder setReverseLayout(boolean reverseLayout) { + this.reverseLayout = reverseLayout; + return this; + } + + public Builder setMoveSpeed(float moveSpeed) { + this.moveSpeed = moveSpeed; + return this; + } + + public Builder setMaxVisibleItemCount(int maxVisibleItemCount) { + this.maxVisibleItemCount = maxVisibleItemCount; + return this; + } + + public Builder setDistanceToBottom(int distanceToBottom) { + this.distanceToBottom = distanceToBottom; + return this; + } + + public CarouselLayoutManager build() { + return new CarouselLayoutManager(this); + } + } +} diff --git a/app/src/main/java/com/chwl/app/view/layoutmanager/CenterSnapHelper.java b/app/src/main/java/com/chwl/app/view/layoutmanager/CenterSnapHelper.java new file mode 100644 index 0000000..8a56256 --- /dev/null +++ b/app/src/main/java/com/chwl/app/view/layoutmanager/CenterSnapHelper.java @@ -0,0 +1,177 @@ +package com.chwl.app.view.layoutmanager; + +import android.view.animation.DecelerateInterpolator; +import android.widget.Scroller; + +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.RecyclerView; + +/** + * Class intended to support snapping for a {@link RecyclerView} + * which use {@link ViewPagerLayoutManager} as its {@link LayoutManager}. + *

+ * The implementation will snap the center of the target child view to the center of + * the attached {@link RecyclerView}. + */ +public class CenterSnapHelper extends RecyclerView.OnFlingListener { + + RecyclerView mRecyclerView; + Scroller mGravityScroller; + + /** + * when the dataSet is extremely large + * {@link #snapToCenterView(ViewPagerLayoutManager, ViewPagerLayoutManager.OnPageChangeListener)} + * may keep calling itself because the accuracy of float + */ + private boolean snapToCenter = false; + + // Handles the snap on scroll case. + private final RecyclerView.OnScrollListener mScrollListener = + new RecyclerView.OnScrollListener() { + + boolean mScrolled = false; + + @Override + public void onScrollStateChanged(RecyclerView recyclerView, int newState) { + super.onScrollStateChanged(recyclerView, newState); + + final ViewPagerLayoutManager layoutManager = + (ViewPagerLayoutManager) recyclerView.getLayoutManager(); + final ViewPagerLayoutManager.OnPageChangeListener onPageChangeListener = + layoutManager.onPageChangeListener; + if (onPageChangeListener != null) { + onPageChangeListener.onPageScrollStateChanged(newState); + } + + if (newState == RecyclerView.SCROLL_STATE_IDLE && mScrolled) { + mScrolled = false; + if (!snapToCenter) { + snapToCenter = true; + snapToCenterView(layoutManager, onPageChangeListener); + } else { + snapToCenter = false; + } + } + } + + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + if (dx != 0 || dy != 0) { + mScrolled = true; + } + } + }; + + @Override + public boolean onFling(int velocityX, int velocityY) { + ViewPagerLayoutManager layoutManager = (ViewPagerLayoutManager) mRecyclerView.getLayoutManager(); + if (layoutManager == null) { + return false; + } + RecyclerView.Adapter adapter = mRecyclerView.getAdapter(); + if (adapter == null) { + return false; + } + + if (!layoutManager.getInfinite() && + (layoutManager.mOffset == layoutManager.getMaxOffset() + || layoutManager.mOffset == layoutManager.getMinOffset())) { + return false; + } + + final int minFlingVelocity = mRecyclerView.getMinFlingVelocity(); + mGravityScroller.fling(0, 0, velocityX, velocityY, + Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE); + + if (layoutManager.mOrientation == ViewPagerLayoutManager.VERTICAL + && Math.abs(velocityY) > minFlingVelocity) { + final int currentPosition = layoutManager.getCurrentPositionOffset(); + final int offsetPosition = (int) (mGravityScroller.getFinalY() / + layoutManager.mInterval / layoutManager.getDistanceRatio()); + ScrollHelper.smoothScrollToPosition(mRecyclerView, layoutManager, layoutManager.getReverseLayout() ? + -currentPosition - offsetPosition : currentPosition + offsetPosition); + return true; + } else if (layoutManager.mOrientation == ViewPagerLayoutManager.HORIZONTAL + && Math.abs(velocityX) > minFlingVelocity) { + final int currentPosition = layoutManager.getCurrentPositionOffset(); + final int offsetPosition = (int) (mGravityScroller.getFinalX() / + layoutManager.mInterval / layoutManager.getDistanceRatio()); + ScrollHelper.smoothScrollToPosition(mRecyclerView, layoutManager, layoutManager.getReverseLayout() ? + -currentPosition - offsetPosition : currentPosition + offsetPosition); + return true; + } + + return true; + } + + /** + * Please attach after {{@link LayoutManager} is setting} + * Attaches the {@link CenterSnapHelper} to the provided RecyclerView, by calling + * {@link RecyclerView#setOnFlingListener(RecyclerView.OnFlingListener)}. + * You can call this method with {@code null} to detach it from the current RecyclerView. + * + * @param recyclerView The RecyclerView instance to which you want to add this helper or + * {@code null} if you want to remove CenterSnapHelper from the current + * RecyclerView. + * @throws IllegalArgumentException if there is already a {@link RecyclerView.OnFlingListener} + * attached to the provided {@link RecyclerView}. + */ + public void attachToRecyclerView(@Nullable RecyclerView recyclerView) + throws IllegalStateException { + if (mRecyclerView == recyclerView) { + return; // nothing to do + } + if (mRecyclerView != null) { + destroyCallbacks(); + } + mRecyclerView = recyclerView; + if (mRecyclerView != null) { + final RecyclerView.LayoutManager layoutManager = mRecyclerView.getLayoutManager(); + if (!(layoutManager instanceof ViewPagerLayoutManager)) return; + + setupCallbacks(); + mGravityScroller = new Scroller(mRecyclerView.getContext(), + new DecelerateInterpolator()); + + snapToCenterView((ViewPagerLayoutManager) layoutManager, + ((ViewPagerLayoutManager) layoutManager).onPageChangeListener); + } + } + + void snapToCenterView(ViewPagerLayoutManager layoutManager, + ViewPagerLayoutManager.OnPageChangeListener listener) { + final int delta = layoutManager.getOffsetToCenter(); + if (delta != 0) { + if (layoutManager.getOrientation() + == ViewPagerLayoutManager.VERTICAL) + mRecyclerView.smoothScrollBy(0, delta); + else + mRecyclerView.smoothScrollBy(delta, 0); + } else { + // set it false to make smoothScrollToPosition keep trigger the listener + snapToCenter = false; + } + + if (listener != null) + listener.onPageSelected(layoutManager.getCurrentPosition()); + } + + /** + * Called when an instance of a {@link RecyclerView} is attached. + */ + void setupCallbacks() throws IllegalStateException { + if (mRecyclerView.getOnFlingListener() != null) { + throw new IllegalStateException("An instance of OnFlingListener already set."); + } + mRecyclerView.addOnScrollListener(mScrollListener); + mRecyclerView.setOnFlingListener(this); + } + + /** + * Called when the instance of a {@link RecyclerView} is detached. + */ + void destroyCallbacks() { + mRecyclerView.removeOnScrollListener(mScrollListener); + mRecyclerView.setOnFlingListener(null); + } +} diff --git a/app/src/main/java/com/chwl/app/view/layoutmanager/CircleLayoutManager.java b/app/src/main/java/com/chwl/app/view/layoutmanager/CircleLayoutManager.java new file mode 100644 index 0000000..1a17c8c --- /dev/null +++ b/app/src/main/java/com/chwl/app/view/layoutmanager/CircleLayoutManager.java @@ -0,0 +1,376 @@ +package com.chwl.app.view.layoutmanager; + +import android.content.Context; +import android.view.View; + +/** + * An implementation of {@link ViewPagerLayoutManager} + * which layouts item in a circle + */ + +@SuppressWarnings({"WeakerAccess", "unused"}) +public class CircleLayoutManager extends ViewPagerLayoutManager { + public static final int LEFT = 10; + public static final int RIGHT = 11; + public static final int TOP = 12; + public static final int BOTTOM = 13; + + public static final int LEFT_ON_TOP = 4; + public static final int RIGHT_ON_TOP = 5; + public static final int CENTER_ON_TOP = 6; + + private int radius; + private int angleInterval; + private float moveSpeed; + private float maxRemoveAngle; + private float minRemoveAngle; + private int gravity; + private boolean flipRotate; + private int zAlignment; + private boolean angleRotate; + + public CircleLayoutManager(Context context) { + this(new Builder(context)); + } + + public CircleLayoutManager(Context context, boolean reverseLayout) { + this(new Builder(context).setReverseLayout(reverseLayout)); + } + + public CircleLayoutManager(Context context, int gravity, boolean reverseLayout) { + this(new Builder(context).setGravity(gravity).setReverseLayout(reverseLayout)); + } + + public CircleLayoutManager(Builder builder) { + this(builder.context, builder.radius, builder.angleInterval, builder.moveSpeed, builder.maxRemoveAngle, + builder.minRemoveAngle, builder.gravity, builder.zAlignment, builder.flipRotate, builder.angleRotate, + builder.maxVisibleItemCount, builder.distanceToBottom, builder.reverseLayout); + } + + private CircleLayoutManager(Context context, int radius, int angleInterval, float moveSpeed, + float max, float min, int gravity, int zAlignment, boolean flipRotate, boolean angleRotate, + int maxVisibleItemCount, int distanceToBottom, boolean reverseLayout) { + super(context, (gravity == LEFT || gravity == RIGHT) ? VERTICAL : HORIZONTAL, reverseLayout); + setEnableBringCenterToFront(true); + setMaxVisibleItemCount(maxVisibleItemCount); + setDistanceToBottom(distanceToBottom); + this.radius = radius; + this.angleInterval = angleInterval; + this.moveSpeed = moveSpeed; + this.maxRemoveAngle = max; + this.minRemoveAngle = min; + this.gravity = gravity; + this.flipRotate = flipRotate; + this.angleRotate = angleRotate; + this.zAlignment = zAlignment; + } + + public int getRadius() { + return radius; + } + + public int getAngleInterval() { + return angleInterval; + } + + public float getMoveSpeed() { + return moveSpeed; + } + + public float getMaxRemoveAngle() { + return maxRemoveAngle; + } + + public float getMinRemoveAngle() { + return minRemoveAngle; + } + + public int getGravity() { + return gravity; + } + + public boolean getFlipRotate() { + return flipRotate; + } + + public boolean getAngleRotate() { + return angleRotate; + } + + + public int getZAlignment() { + return zAlignment; + } + + public void setRadius(int radius) { + assertNotInLayoutOrScroll(null); + if (this.radius == radius) return; + this.radius = radius; + removeAllViews(); + } + + public void setAngleInterval(int angleInterval) { + assertNotInLayoutOrScroll(null); + if (this.angleInterval == angleInterval) return; + this.angleInterval = angleInterval; + removeAllViews(); + } + + public void setMoveSpeed(float moveSpeed) { + assertNotInLayoutOrScroll(null); + if (this.moveSpeed == moveSpeed) return; + this.moveSpeed = moveSpeed; + } + + public void setMaxRemoveAngle(float maxRemoveAngle) { + assertNotInLayoutOrScroll(null); + if (this.maxRemoveAngle == maxRemoveAngle) return; + this.maxRemoveAngle = maxRemoveAngle; + requestLayout(); + } + + public void setMinRemoveAngle(float minRemoveAngle) { + assertNotInLayoutOrScroll(null); + if (this.minRemoveAngle == minRemoveAngle) return; + this.minRemoveAngle = minRemoveAngle; + requestLayout(); + } + + public void setGravity(int gravity) { + assertNotInLayoutOrScroll(null); + assertGravity(gravity); + if (this.gravity == gravity) return; + this.gravity = gravity; + if (gravity == LEFT || gravity == RIGHT) { + setOrientation(VERTICAL); + } else { + setOrientation(HORIZONTAL); + } + requestLayout(); + } + + public void setFlipRotate(boolean flipRotate) { + assertNotInLayoutOrScroll(null); + if (this.flipRotate == flipRotate) return; + this.flipRotate = flipRotate; + requestLayout(); + } + + public void setAngleRotate(boolean angleRotate) { + assertNotInLayoutOrScroll(null); + if (this.angleRotate == angleRotate) return; + this.angleRotate = angleRotate; + requestLayout(); + } + + public void setZAlignment(int zAlignment) { + assertNotInLayoutOrScroll(null); + assertZAlignmentState(zAlignment); + if (this.zAlignment == zAlignment) return; + this.zAlignment = zAlignment; + requestLayout(); + } + + @Override + protected float setInterval() { + return angleInterval; + } + + @Override + protected void setUp() { + radius = radius == Builder.INVALID_VALUE ? mDecoratedMeasurementInOther : radius; + } + + @Override + protected float maxRemoveOffset() { + return maxRemoveAngle; + } + + @Override + protected float minRemoveOffset() { + return minRemoveAngle; + } + + @Override + protected int calItemLeft(View itemView, float targetOffset) { + switch (gravity) { + case LEFT: + return (int) (radius * Math.sin(Math.toRadians(90 - targetOffset)) - radius); + case RIGHT: + return (int) (radius - radius * Math.sin(Math.toRadians(90 - targetOffset))); + case TOP: + case BOTTOM: + default: + return (int) (radius * Math.cos(Math.toRadians(90 - targetOffset))); + } + } + + @Override + protected int calItemTop(View itemView, float targetOffset) { + switch (gravity) { + case LEFT: + case RIGHT: + return (int) (radius * Math.cos(Math.toRadians(90 - targetOffset))); + case TOP: + return (int) (radius * Math.sin(Math.toRadians(90 - targetOffset)) - radius); + case BOTTOM: + default: + return (int) (radius - radius * Math.sin(Math.toRadians(90 - targetOffset))); + } + } + + @Override + protected void setItemViewProperty(View itemView, float targetOffset) { + switch (gravity) { + case RIGHT: + case TOP: + if (flipRotate) { + itemView.setRotation(targetOffset); + } else if (angleRotate) { + itemView.setRotation(360 - targetOffset); + } + break; + case LEFT: + case BOTTOM: + default: + if (flipRotate) { + itemView.setRotation(360 - targetOffset); + } else if (angleRotate) { + itemView.setRotation(targetOffset); + } + break; + } + } + + @Override + protected float setViewElevation(View itemView, float targetOffset) { + if (zAlignment == LEFT_ON_TOP) + return (540 - targetOffset) / 72; + else if (zAlignment == RIGHT_ON_TOP) + return (targetOffset - 540) / 72; + else + return (360 - Math.abs(targetOffset)) / 72; + } + + @Override + protected float getDistanceRatio() { + if (moveSpeed == 0) return Float.MAX_VALUE; + return 1 / moveSpeed; + } + + private static void assertGravity(int gravity) { + if (gravity != LEFT && gravity != RIGHT && gravity != TOP && gravity != BOTTOM) { + throw new IllegalArgumentException("gravity must be one of LEFT RIGHT TOP and BOTTOM"); + } + } + + private static void assertZAlignmentState(int zAlignment) { + if (zAlignment != LEFT_ON_TOP && zAlignment != RIGHT_ON_TOP && zAlignment != CENTER_ON_TOP) { + throw new IllegalArgumentException("zAlignment must be one of LEFT_ON_TOP RIGHT_ON_TOP and CENTER_ON_TOP"); + } + } + + public static class Builder { + private static int INTERVAL_ANGLE = 30;// The default mInterval angle between each items + private static float DISTANCE_RATIO = 10f; // Finger swipe distance divide item rotate angle + private static int INVALID_VALUE = Integer.MIN_VALUE; + private static int MAX_REMOVE_ANGLE = 90; + private static int MIN_REMOVE_ANGLE = -90; + + private int radius; + private int angleInterval; + private float moveSpeed; + private float maxRemoveAngle; + private float minRemoveAngle; + private boolean reverseLayout; + private Context context; + private int gravity; + private boolean flipRotate; + private boolean angleRotate; + private int zAlignment; + private int maxVisibleItemCount; + private int distanceToBottom; + + public Builder(Context context) { + this.context = context; + radius = INVALID_VALUE; + angleInterval = INTERVAL_ANGLE; + moveSpeed = 1 / DISTANCE_RATIO; + maxRemoveAngle = MAX_REMOVE_ANGLE; + minRemoveAngle = MIN_REMOVE_ANGLE; + reverseLayout = false; + flipRotate = false; + angleRotate = true; + gravity = BOTTOM; + zAlignment = LEFT_ON_TOP; + maxVisibleItemCount = ViewPagerLayoutManager.DETERMINE_BY_MAX_AND_MIN; + distanceToBottom = ViewPagerLayoutManager.INVALID_SIZE; + } + + public Builder setRadius(int radius) { + this.radius = radius; + return this; + } + + public Builder setAngleInterval(int angleInterval) { + this.angleInterval = angleInterval; + return this; + } + + public Builder setMoveSpeed(int moveSpeed) { + this.moveSpeed = moveSpeed; + return this; + } + + public Builder setMaxRemoveAngle(float maxRemoveAngle) { + this.maxRemoveAngle = maxRemoveAngle; + return this; + } + + public Builder setMinRemoveAngle(float minRemoveAngle) { + this.minRemoveAngle = minRemoveAngle; + return this; + } + + public Builder setReverseLayout(boolean reverseLayout) { + this.reverseLayout = reverseLayout; + return this; + } + + public Builder setGravity(int gravity) { + assertGravity(gravity); + this.gravity = gravity; + return this; + } + + public Builder setFlipRotate(boolean flipRotate) { + this.flipRotate = flipRotate; + return this; + } + + public Builder setAngleRotate(boolean angleRotate) { + this.angleRotate = angleRotate; + return this; + } + + public Builder setZAlignment(int zAlignment) { + assertZAlignmentState(zAlignment); + this.zAlignment = zAlignment; + return this; + } + + public Builder setMaxVisibleItemCount(int maxVisibleItemCount) { + this.maxVisibleItemCount = maxVisibleItemCount; + return this; + } + + public Builder setDistanceToBottom(int distanceToBottom) { + this.distanceToBottom = distanceToBottom; + return this; + } + + public CircleLayoutManager build() { + return new CircleLayoutManager(this); + } + } +} diff --git a/app/src/main/java/com/chwl/app/view/layoutmanager/CircleScaleLayoutManager.java b/app/src/main/java/com/chwl/app/view/layoutmanager/CircleScaleLayoutManager.java new file mode 100644 index 0000000..1ec131b --- /dev/null +++ b/app/src/main/java/com/chwl/app/view/layoutmanager/CircleScaleLayoutManager.java @@ -0,0 +1,393 @@ +package com.chwl.app.view.layoutmanager; + +import android.content.Context; +import android.view.View; + +/** + * An implementation of {@link ViewPagerLayoutManager} + * which layouts item in a circle and will change the child's centerScale while scrolling + */ + +@SuppressWarnings({"WeakerAccess", "unused"}) +public class CircleScaleLayoutManager extends ViewPagerLayoutManager { + public static final int LEFT = 10; + public static final int RIGHT = 11; + public static final int TOP = 12; + public static final int BOTTOM = 13; + + public static final int LEFT_ON_TOP = 4; + public static final int RIGHT_ON_TOP = 5; + public static final int CENTER_ON_TOP = 6; + + private int radius; + private int angleInterval; + private float moveSpeed; + private float centerScale; + private float maxRemoveAngle; + private float minRemoveAngle; + private int gravity; + private boolean flipRotate; + private int zAlignment; + + public CircleScaleLayoutManager(Context context) { + this(new Builder(context)); + } + + public CircleScaleLayoutManager(Context context, int gravity, boolean reverseLayout) { + this(new Builder(context).setGravity(gravity).setReverseLayout(reverseLayout)); + } + + public CircleScaleLayoutManager(Context context, boolean reverseLayout) { + this(new Builder(context).setReverseLayout(reverseLayout)); + } + + public CircleScaleLayoutManager(Builder builder) { + this(builder.context, builder.radius, builder.angleInterval, builder.centerScale, builder.moveSpeed, + builder.maxRemoveAngle, builder.minRemoveAngle, builder.gravity, builder.zAlignment, + builder.flipRotate, builder.maxVisibleItemCount, builder.distanceToBottom, builder.reverseLayout); + } + + private CircleScaleLayoutManager(Context context, int radius, int angleInterval, float centerScale, + float moveSpeed, float max, float min, int gravity, int zAlignment, + boolean flipRotate, int maxVisibleItemCount, int distanceToBottom, boolean reverseLayout) { + super(context, HORIZONTAL, reverseLayout); + setEnableBringCenterToFront(true); + setMaxVisibleItemCount(maxVisibleItemCount); + setDistanceToBottom(distanceToBottom); + this.radius = radius; + this.angleInterval = angleInterval; + this.centerScale = centerScale; + this.moveSpeed = moveSpeed; + this.maxRemoveAngle = max; + this.minRemoveAngle = min; + this.gravity = gravity; + this.flipRotate = flipRotate; + this.zAlignment = zAlignment; + } + + public int getRadius() { + return radius; + } + + public int getAngleInterval() { + return angleInterval; + } + + public float getCenterScale() { + return centerScale; + } + + public float getMoveSpeed() { + return moveSpeed; + } + + public float getMaxRemoveAngle() { + return maxRemoveAngle; + } + + public float getMinRemoveAngle() { + return minRemoveAngle; + } + + public int getGravity() { + return gravity; + } + + public boolean getFlipRotate() { + return flipRotate; + } + + public int getZAlignment() { + return zAlignment; + } + + public void setRadius(int radius) { + assertNotInLayoutOrScroll(null); + if (this.radius == radius) return; + this.radius = radius; + removeAllViews(); + } + + public void setAngleInterval(int angleInterval) { + assertNotInLayoutOrScroll(null); + if (this.angleInterval == angleInterval) return; + this.angleInterval = angleInterval; + removeAllViews(); + } + + public void setCenterScale(float centerScale) { + assertNotInLayoutOrScroll(null); + if (this.centerScale == centerScale) return; + this.centerScale = centerScale; + requestLayout(); + } + + public void setMoveSpeed(float moveSpeed) { + assertNotInLayoutOrScroll(null); + if (this.moveSpeed == moveSpeed) return; + this.moveSpeed = moveSpeed; + } + + public void setMaxRemoveAngle(float maxRemoveAngle) { + assertNotInLayoutOrScroll(null); + if (this.maxRemoveAngle == maxRemoveAngle) return; + this.maxRemoveAngle = maxRemoveAngle; + requestLayout(); + } + + public void setMinRemoveAngle(float minRemoveAngle) { + assertNotInLayoutOrScroll(null); + if (this.minRemoveAngle == minRemoveAngle) return; + this.minRemoveAngle = minRemoveAngle; + requestLayout(); + } + + public void setGravity(int gravity) { + assertNotInLayoutOrScroll(null); + assertGravity(gravity); + if (this.gravity == gravity) return; + this.gravity = gravity; + if (gravity == LEFT || gravity == RIGHT) { + setOrientation(VERTICAL); + } else { + setOrientation(HORIZONTAL); + } + requestLayout(); + } + + public void setFlipRotate(boolean flipRotate) { + assertNotInLayoutOrScroll(null); + if (this.flipRotate == flipRotate) return; + this.flipRotate = flipRotate; + requestLayout(); + } + + public void setZAlignment(int zAlignment) { + assertNotInLayoutOrScroll(null); + assertZAlignmentState(zAlignment); + if (this.zAlignment == zAlignment) return; + this.zAlignment = zAlignment; + requestLayout(); + } + + @Override + protected float setInterval() { + return angleInterval; + } + + @Override + protected void setUp() { + radius = radius == Builder.INVALID_VALUE ? mDecoratedMeasurementInOther : radius; + } + + @Override + protected float maxRemoveOffset() { + return maxRemoveAngle; + } + + @Override + protected float minRemoveOffset() { + return minRemoveAngle; + } + + @Override + protected int calItemLeft(View itemView, float targetOffset) { + switch (gravity) { + case LEFT: + return (int) (radius * Math.sin(Math.toRadians(90 - targetOffset)) - radius); + case RIGHT: + return (int) (radius - radius * Math.sin(Math.toRadians(90 - targetOffset))); + case TOP: + case BOTTOM: + default: + return (int) (radius * Math.cos(Math.toRadians(90 - targetOffset))); + } + } + + @Override + protected int calItemTop(View itemView, float targetOffset) { + switch (gravity) { + case LEFT: + case RIGHT: + return (int) (radius * Math.cos(Math.toRadians(90 - targetOffset))); + case TOP: + return (int) (radius * Math.sin(Math.toRadians(90 - targetOffset)) - radius); + case BOTTOM: + default: + return (int) (radius - radius * Math.sin(Math.toRadians(90 - targetOffset))); + } + } + + @Override + protected void setItemViewProperty(View itemView, float targetOffset) { + float scale = 1f; + switch (gravity) { + case RIGHT: + case TOP: + if (flipRotate) { + itemView.setRotation(targetOffset); + if (targetOffset < angleInterval && targetOffset > -angleInterval) { + float diff = Math.abs(Math.abs(itemView.getRotation() - angleInterval) - angleInterval); + scale = (centerScale - 1f) / -angleInterval * diff + centerScale; + } + } else { + itemView.setRotation(360 - targetOffset); + if (targetOffset < angleInterval && targetOffset > -angleInterval) { + float diff = Math.abs(Math.abs(360 - itemView.getRotation() - angleInterval) - angleInterval); + scale = (centerScale - 1f) / -angleInterval * diff + centerScale; + } + } + break; + case LEFT: + case BOTTOM: + default: + if (flipRotate) { + itemView.setRotation(360 - targetOffset); + if (targetOffset < angleInterval && targetOffset > -angleInterval) { + float diff = Math.abs(Math.abs(360 - itemView.getRotation() - angleInterval) - angleInterval); + scale = (centerScale - 1f) / -angleInterval * diff + centerScale; + } + } else { + itemView.setRotation(targetOffset); + if (targetOffset < angleInterval && targetOffset > -angleInterval) { + float diff = Math.abs(Math.abs(itemView.getRotation() - angleInterval) - angleInterval); + scale = (centerScale - 1f) / -angleInterval * diff + centerScale; + } + } + break; + } + itemView.setScaleX(scale); + itemView.setScaleY(scale); + } + + @Override + protected float setViewElevation(View itemView, float targetOffset) { + if (zAlignment == LEFT_ON_TOP) + return (540 - targetOffset) / 72; + else if (zAlignment == RIGHT_ON_TOP) + return (targetOffset - 540) / 72; + else + return (360 - Math.abs(targetOffset)) / 72; + } + + @Override + protected float getDistanceRatio() { + if (moveSpeed == 0) return Float.MAX_VALUE; + return 1 / moveSpeed; + } + + private static void assertGravity(int gravity) { + if (gravity != LEFT && gravity != RIGHT && gravity != TOP && gravity != BOTTOM) { + throw new IllegalArgumentException("gravity must be one of LEFT RIGHT TOP and BOTTOM"); + } + } + + private static void assertZAlignmentState(int zAlignment) { + if (zAlignment != LEFT_ON_TOP && zAlignment != RIGHT_ON_TOP && zAlignment != CENTER_ON_TOP) { + throw new IllegalArgumentException("zAlignment must be one of LEFT_ON_TOP RIGHT_ON_TOP and CENTER_ON_TOP"); + } + } + + public static class Builder { + private static int INTERVAL_ANGLE = 30;// The default mInterval angle between each items + private static float DISTANCE_RATIO = 10f; // Finger swipe distance divide item rotate angle + private static final float SCALE_RATE = 1.2f; + private static int INVALID_VALUE = Integer.MIN_VALUE; + + private int radius; + private int angleInterval; + private float centerScale; + private float moveSpeed; + private float maxRemoveAngle; + private float minRemoveAngle; + private boolean reverseLayout; + private Context context; + private int gravity; + private boolean flipRotate; + private int zAlignment; + private int maxVisibleItemCount; + private int distanceToBottom; + + public Builder(Context context) { + this.context = context; + radius = INVALID_VALUE; + angleInterval = INTERVAL_ANGLE; + centerScale = SCALE_RATE; + moveSpeed = 1 / DISTANCE_RATIO; + maxRemoveAngle = 90; + minRemoveAngle = -90; + reverseLayout = false; + flipRotate = false; + gravity = BOTTOM; + zAlignment = CENTER_ON_TOP; + distanceToBottom = ViewPagerLayoutManager.INVALID_SIZE; + maxVisibleItemCount = ViewPagerLayoutManager.DETERMINE_BY_MAX_AND_MIN; + } + + public Builder setRadius(int radius) { + this.radius = radius; + return this; + } + + public Builder setAngleInterval(int angleInterval) { + this.angleInterval = angleInterval; + return this; + } + + public Builder setCenterScale(float centerScale) { + this.centerScale = centerScale; + return this; + } + + public Builder setMoveSpeed(int moveSpeed) { + this.moveSpeed = moveSpeed; + return this; + } + + public Builder setMaxRemoveAngle(float maxRemoveAngle) { + this.maxRemoveAngle = maxRemoveAngle; + return this; + } + + public Builder setMinRemoveAngle(float minRemoveAngle) { + this.minRemoveAngle = minRemoveAngle; + return this; + } + + public Builder setReverseLayout(boolean reverseLayout) { + this.reverseLayout = reverseLayout; + return this; + } + + public Builder setGravity(int gravity) { + assertGravity(gravity); + this.gravity = gravity; + return this; + } + + public Builder setFlipRotate(boolean flipRotate) { + this.flipRotate = flipRotate; + return this; + } + + public Builder setZAlignment(int zAlignment) { + assertZAlignmentState(zAlignment); + this.zAlignment = zAlignment; + return this; + } + + public Builder setMaxVisibleItemCount(int maxVisibleItemCount) { + this.maxVisibleItemCount = maxVisibleItemCount; + return this; + } + + public Builder setDistanceToBottom(int distanceToBottom) { + this.distanceToBottom = distanceToBottom; + return this; + } + + public CircleScaleLayoutManager build() { + return new CircleScaleLayoutManager(this); + } + } +} diff --git a/app/src/main/java/com/chwl/app/view/layoutmanager/GalleryLayoutManager.java b/app/src/main/java/com/chwl/app/view/layoutmanager/GalleryLayoutManager.java new file mode 100644 index 0000000..23521e0 --- /dev/null +++ b/app/src/main/java/com/chwl/app/view/layoutmanager/GalleryLayoutManager.java @@ -0,0 +1,286 @@ +package com.chwl.app.view.layoutmanager; + +import android.content.Context; +import android.view.View; + +/** + * An implementation of {@link ViewPagerLayoutManager} + * which will change rotate x or rotate y + */ + +@SuppressWarnings({"WeakerAccess", "unused"}) +public class GalleryLayoutManager extends ViewPagerLayoutManager { + private final float MAX_ELEVATION = 5F; + + private int itemSpace; + private float moveSpeed; + private float maxAlpha; + private float minAlpha; + private float angle; + private boolean flipRotate; + private boolean rotateFromEdge; + + public GalleryLayoutManager(Context context, int itemSpace) { + this(new Builder(context, itemSpace)); + } + + public GalleryLayoutManager(Context context, int itemSpace, int orientation) { + this(new Builder(context, itemSpace).setOrientation(orientation)); + } + + public GalleryLayoutManager(Context context, int itemSpace, int orientation, boolean reverseLayout) { + this(new Builder(context, itemSpace).setOrientation(orientation).setReverseLayout(reverseLayout)); + } + + public GalleryLayoutManager(Builder builder) { + this(builder.context, builder.itemSpace, builder.angle, builder.maxAlpha, builder.minAlpha, + builder.orientation, builder.moveSpeed, builder.flipRotate, builder.rotateFromEdge, + builder.maxVisibleItemCount, builder.distanceToBottom, builder.reverseLayout); + } + + private GalleryLayoutManager(Context context, int itemSpace, float angle, float maxAlpha, float minAlpha, + int orientation, float moveSpeed, boolean flipRotate, boolean rotateFromEdge, + int maxVisibleItemCount, int distanceToBottom, boolean reverseLayout) { + super(context, orientation, reverseLayout); + setDistanceToBottom(distanceToBottom); + setMaxVisibleItemCount(maxVisibleItemCount); + this.itemSpace = itemSpace; + this.moveSpeed = moveSpeed; + this.angle = angle; + this.maxAlpha = maxAlpha; + this.minAlpha = minAlpha; + this.flipRotate = flipRotate; + this.rotateFromEdge = rotateFromEdge; + } + + public int getItemSpace() { + return itemSpace; + } + + public float getMaxAlpha() { + return maxAlpha; + } + + public float getMinAlpha() { + return minAlpha; + } + + public float getAngle() { + return angle; + } + + public float getMoveSpeed() { + return moveSpeed; + } + + public boolean getFlipRotate() { + return flipRotate; + } + + public boolean getRotateFromEdge() { + return rotateFromEdge; + } + + public void setItemSpace(int itemSpace) { + assertNotInLayoutOrScroll(null); + if (this.itemSpace == itemSpace) return; + this.itemSpace = itemSpace; + removeAllViews(); + } + + public void setMoveSpeed(float moveSpeed) { + assertNotInLayoutOrScroll(null); + if (this.moveSpeed == moveSpeed) return; + this.moveSpeed = moveSpeed; + } + + public void setMaxAlpha(float maxAlpha) { + assertNotInLayoutOrScroll(null); + if (maxAlpha > 1) maxAlpha = 1; + if (this.maxAlpha == maxAlpha) return; + this.maxAlpha = maxAlpha; + requestLayout(); + } + + public void setMinAlpha(float minAlpha) { + assertNotInLayoutOrScroll(null); + if (minAlpha < 0) minAlpha = 0; + if (this.minAlpha == minAlpha) return; + this.minAlpha = minAlpha; + requestLayout(); + } + + public void setAngle(float angle) { + assertNotInLayoutOrScroll(null); + if (this.angle == angle) return; + this.angle = angle; + requestLayout(); + } + + public void setFlipRotate(boolean flipRotate) { + assertNotInLayoutOrScroll(null); + if (this.flipRotate == flipRotate) return; + this.flipRotate = flipRotate; + requestLayout(); + } + + public void setRotateFromEdge(boolean rotateFromEdge) { + assertNotInLayoutOrScroll(null); + if (this.rotateFromEdge == rotateFromEdge) return; + this.rotateFromEdge = rotateFromEdge; + removeAllViews(); + } + + @Override + protected float setInterval() { + return mDecoratedMeasurement + itemSpace; + } + + @Override + protected void setItemViewProperty(View itemView, float targetOffset) { + final float rotation = calRotation(targetOffset); + if (getOrientation() == HORIZONTAL) { + if (rotateFromEdge) { + itemView.setPivotX(rotation > 0 ? 0 : mDecoratedMeasurement); + itemView.setPivotY(mDecoratedMeasurementInOther * 0.5f); + } + if (flipRotate) { + itemView.setRotationX(rotation); + } else { + itemView.setRotationY(rotation); + } + } else { + if (rotateFromEdge) { + itemView.setPivotY(rotation > 0 ? 0 : mDecoratedMeasurement); + itemView.setPivotX(mDecoratedMeasurementInOther * 0.5f); + + } + if (flipRotate) { + itemView.setRotationY(-rotation); + } else { + itemView.setRotationX(-rotation); + } + } + final float alpha = calAlpha(targetOffset); + itemView.setAlpha(alpha); + } + + @Override + protected float setViewElevation(View itemView, float targetOffset) { + final float ele = Math.max(Math.abs(itemView.getRotationX()), Math.abs(itemView.getRotationY())) * MAX_ELEVATION / 360; + return MAX_ELEVATION - ele; + } + + @Override + protected float getDistanceRatio() { + if (moveSpeed == 0) return Float.MAX_VALUE; + return 1 / moveSpeed; + } + + private float calRotation(float targetOffset) { + return -angle / mInterval * targetOffset; + } + + private float calAlpha(float targetOffset) { + final float offset = Math.abs(targetOffset); + float alpha = (minAlpha - maxAlpha) / mInterval * offset + maxAlpha; + if (offset >= mInterval) alpha = minAlpha; + return alpha; + } + + public static class Builder { + private static float INTERVAL_ANGLE = 30f; + private static final float DEFAULT_SPEED = 1f; + private static float MIN_ALPHA = 0.5f; + private static float MAX_ALPHA = 1f; + + private int itemSpace; + private float moveSpeed; + private int orientation; + private float maxAlpha; + private float minAlpha; + private float angle; + private boolean flipRotate; + private boolean reverseLayout; + private Context context; + private int maxVisibleItemCount; + private int distanceToBottom; + private boolean rotateFromEdge; + + public Builder(Context context, int itemSpace) { + this.itemSpace = itemSpace; + this.context = context; + orientation = HORIZONTAL; + angle = INTERVAL_ANGLE; + maxAlpha = MAX_ALPHA; + minAlpha = MIN_ALPHA; + this.moveSpeed = DEFAULT_SPEED; + reverseLayout = false; + flipRotate = false; + rotateFromEdge = false; + distanceToBottom = ViewPagerLayoutManager.INVALID_SIZE; + maxVisibleItemCount = ViewPagerLayoutManager.DETERMINE_BY_MAX_AND_MIN; + } + + public Builder setItemSpace(int itemSpace) { + this.itemSpace = itemSpace; + return this; + } + + public Builder setMoveSpeed(float moveSpeed) { + this.moveSpeed = moveSpeed; + return this; + } + + public Builder setOrientation(int orientation) { + this.orientation = orientation; + return this; + } + + public Builder setMaxAlpha(float maxAlpha) { + if (maxAlpha > 1) maxAlpha = 1; + this.maxAlpha = maxAlpha; + return this; + } + + public Builder setMinAlpha(float minAlpha) { + if (minAlpha < 0) minAlpha = 0; + this.minAlpha = minAlpha; + return this; + } + + public Builder setAngle(float angle) { + this.angle = angle; + return this; + } + + public Builder setFlipRotate(boolean flipRotate) { + this.flipRotate = flipRotate; + return this; + } + + public Builder setReverseLayout(boolean reverseLayout) { + this.reverseLayout = reverseLayout; + return this; + } + + public Builder setMaxVisibleItemCount(int maxVisibleItemCount) { + this.maxVisibleItemCount = maxVisibleItemCount; + return this; + } + + public Builder setDistanceToBottom(int distanceToBottom) { + this.distanceToBottom = distanceToBottom; + return this; + } + + public Builder setRotateFromEdge(boolean rotateFromEdge) { + this.rotateFromEdge = rotateFromEdge; + return this; + } + + public GalleryLayoutManager build() { + return new GalleryLayoutManager(this); + } + } +} diff --git a/app/src/main/java/com/chwl/app/view/layoutmanager/OrientationHelper.java b/app/src/main/java/com/chwl/app/view/layoutmanager/OrientationHelper.java new file mode 100644 index 0000000..e79f832 --- /dev/null +++ b/app/src/main/java/com/chwl/app/view/layoutmanager/OrientationHelper.java @@ -0,0 +1,423 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.chwl.app.view.layoutmanager; + +import android.graphics.Rect; +import android.view.View; +import android.widget.LinearLayout; + +import androidx.recyclerview.widget.RecyclerView; + +/** + * Helper class for LayoutManagers to abstract measurements depending on the View's orientation. + *

+ * It is developed to easily support vertical and horizontal orientations in a LayoutManager but + * can also be used to abstract calls around view bounds and child measurements with margins and + * decorations. + * + * @see #createHorizontalHelper(RecyclerView.LayoutManager) + * @see #createVerticalHelper(RecyclerView.LayoutManager) + */ +@SuppressWarnings({"WeakerAccess","unused"}) +public abstract class OrientationHelper { + + private static final int INVALID_SIZE = Integer.MIN_VALUE; + + protected final RecyclerView.LayoutManager mLayoutManager; + + public static final int HORIZONTAL = LinearLayout.HORIZONTAL; + + public static final int VERTICAL = LinearLayout.VERTICAL; + + private int mLastTotalSpace = INVALID_SIZE; + + final Rect mTmpRect = new Rect(); + + private OrientationHelper(RecyclerView.LayoutManager layoutManager) { + mLayoutManager = layoutManager; + } + + /** + * Call this method after onLayout method is complete if state is NOT pre-layout. + * This method records information like layout bounds that might be useful in the next layout + * calculations. + */ + public void onLayoutComplete() { + mLastTotalSpace = getTotalSpace(); + } + + /** + * Returns the layout space change between the previous layout pass and current layout pass. + *

+ * Make sure you call {@link #onLayoutComplete()} at the end of your LayoutManager's + * {@link RecyclerView.LayoutManager#onLayoutChildren(RecyclerView.Recycler, + * RecyclerView.State)} method. + * + * @return The difference between the current total space and previous layout's total space. + * @see #onLayoutComplete() + */ + public int getTotalSpaceChange() { + return INVALID_SIZE == mLastTotalSpace ? 0 : getTotalSpace() - mLastTotalSpace; + } + + /** + * Returns the start of the view including its decoration and margin. + *

+ * For example, for the horizontal helper, if a View's left is at pixel 20, has 2px left + * decoration and 3px left margin, returned value will be 15px. + * + * @param view The view element to check + * @return The first pixel of the element + * @see #getDecoratedEnd(View) + */ + public abstract int getDecoratedStart(View view); + + /** + * Returns the end of the view including its decoration and margin. + *

+ * For example, for the horizontal helper, if a View's right is at pixel 200, has 2px right + * decoration and 3px right margin, returned value will be 205. + * + * @param view The view element to check + * @return The last pixel of the element + * @see #getDecoratedStart(View) + */ + public abstract int getDecoratedEnd(View view); + + /** + * Returns the end of the View after its matrix transformations are applied to its layout + * position. + *

+ * This method is useful when trying to detect the visible edge of a View. + *

+ * It includes the decorations but does not include the margins. + * + * @param view The view whose transformed end will be returned + * @return The end of the View after its decor insets and transformation matrix is applied to + * its position + * @see RecyclerView.LayoutManager#getTransformedBoundingBox(View, boolean, Rect) + */ + public abstract int getTransformedEndWithDecoration(View view); + + /** + * Returns the start of the View after its matrix transformations are applied to its layout + * position. + *

+ * This method is useful when trying to detect the visible edge of a View. + *

+ * It includes the decorations but does not include the margins. + * + * @param view The view whose transformed start will be returned + * @return The start of the View after its decor insets and transformation matrix is applied to + * its position + * @see RecyclerView.LayoutManager#getTransformedBoundingBox(View, boolean, Rect) + */ + public abstract int getTransformedStartWithDecoration(View view); + + /** + * Returns the space occupied by this View in the current orientation including decorations and + * margins. + * + * @param view The view element to check + * @return Total space occupied by this view + * @see #getDecoratedMeasurementInOther(View) + */ + public abstract int getDecoratedMeasurement(View view); + + /** + * Returns the space occupied by this View in the perpendicular orientation including + * decorations and margins. + * + * @param view The view element to check + * @return Total space occupied by this view in the perpendicular orientation to current one + * @see #getDecoratedMeasurement(View) + */ + public abstract int getDecoratedMeasurementInOther(View view); + + /** + * Returns the start position of the layout after the start padding is added. + * + * @return The very first pixel we can draw. + */ + public abstract int getStartAfterPadding(); + + /** + * Returns the end position of the layout after the end padding is removed. + * + * @return The end boundary for this layout. + */ + public abstract int getEndAfterPadding(); + + /** + * Returns the end position of the layout without taking padding into account. + * + * @return The end boundary for this layout without considering padding. + */ + public abstract int getEnd(); + + /** + * Returns the total space to layout. This number is the difference between + * {@link #getEndAfterPadding()} and {@link #getStartAfterPadding()}. + * + * @return Total space to layout children + */ + public abstract int getTotalSpace(); + + /** + * Returns the total space in other direction to layout. This number is the difference between + * {@link #getEndAfterPadding()} and {@link #getStartAfterPadding()}. + * + * @return Total space to layout children + */ + public abstract int getTotalSpaceInOther(); + + /** + * Returns the padding at the end of the layout. For horizontal helper, this is the right + * padding and for vertical helper, this is the bottom padding. This method does not check + * whether the layout is RTL or not. + * + * @return The padding at the end of the layout. + */ + public abstract int getEndPadding(); + + /** + * Returns the MeasureSpec mode for the current orientation from the LayoutManager. + * + * @return The current measure spec mode. + * @see View.MeasureSpec + * @see RecyclerView.LayoutManager#getWidthMode() + * @see RecyclerView.LayoutManager#getHeightMode() + */ + public abstract int getMode(); + + /** + * Returns the MeasureSpec mode for the perpendicular orientation from the LayoutManager. + * + * @return The current measure spec mode. + * @see View.MeasureSpec + * @see RecyclerView.LayoutManager#getWidthMode() + * @see RecyclerView.LayoutManager#getHeightMode() + */ + public abstract int getModeInOther(); + + /** + * Creates an OrientationHelper for the given LayoutManager and orientation. + * + * @param layoutManager LayoutManager to attach to + * @param orientation Desired orientation. Should be {@link #HORIZONTAL} or {@link #VERTICAL} + * @return A new OrientationHelper + */ + public static OrientationHelper createOrientationHelper( + RecyclerView.LayoutManager layoutManager, int orientation) { + switch (orientation) { + case HORIZONTAL: + return createHorizontalHelper(layoutManager); + case VERTICAL: + return createVerticalHelper(layoutManager); + } + throw new IllegalArgumentException("invalid orientation"); + } + + /** + * Creates a horizontal OrientationHelper for the given LayoutManager. + * + * @param layoutManager The LayoutManager to attach to. + * @return A new OrientationHelper + */ + public static OrientationHelper createHorizontalHelper( + RecyclerView.LayoutManager layoutManager) { + return new OrientationHelper(layoutManager) { + @Override + public int getEndAfterPadding() { + return mLayoutManager.getWidth() - mLayoutManager.getPaddingRight(); + } + + @Override + public int getEnd() { + return mLayoutManager.getWidth(); + } + + @Override + public int getStartAfterPadding() { + return mLayoutManager.getPaddingLeft(); + } + + @Override + public int getDecoratedMeasurement(View view) { + final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) + view.getLayoutParams(); + return mLayoutManager.getDecoratedMeasuredWidth(view) + params.leftMargin + + params.rightMargin; + } + + @Override + public int getDecoratedMeasurementInOther(View view) { + final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) + view.getLayoutParams(); + return mLayoutManager.getDecoratedMeasuredHeight(view) + params.topMargin + + params.bottomMargin; + } + + @Override + public int getDecoratedEnd(View view) { + final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) + view.getLayoutParams(); + return mLayoutManager.getDecoratedRight(view) + params.rightMargin; + } + + @Override + public int getDecoratedStart(View view) { + final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) + view.getLayoutParams(); + return mLayoutManager.getDecoratedLeft(view) - params.leftMargin; + } + + @Override + public int getTransformedEndWithDecoration(View view) { + mLayoutManager.getTransformedBoundingBox(view, true, mTmpRect); + return mTmpRect.right; + } + + @Override + public int getTransformedStartWithDecoration(View view) { + mLayoutManager.getTransformedBoundingBox(view, true, mTmpRect); + return mTmpRect.left; + } + + @Override + public int getTotalSpace() { + return mLayoutManager.getWidth() - mLayoutManager.getPaddingLeft() + - mLayoutManager.getPaddingRight(); + } + + @Override + public int getTotalSpaceInOther() { + return mLayoutManager.getHeight() - mLayoutManager.getPaddingTop() + - mLayoutManager.getPaddingBottom(); + } + + @Override + public int getEndPadding() { + return mLayoutManager.getPaddingRight(); + } + + @Override + public int getMode() { + return mLayoutManager.getWidthMode(); + } + + @Override + public int getModeInOther() { + return mLayoutManager.getHeightMode(); + } + }; + } + + /** + * Creates a vertical OrientationHelper for the given LayoutManager. + * + * @param layoutManager The LayoutManager to attach to. + * @return A new OrientationHelper + */ + public static OrientationHelper createVerticalHelper(RecyclerView.LayoutManager layoutManager) { + return new OrientationHelper(layoutManager) { + @Override + public int getEndAfterPadding() { + return mLayoutManager.getHeight() - mLayoutManager.getPaddingBottom(); + } + + @Override + public int getEnd() { + return mLayoutManager.getHeight(); + } + + @Override + public int getStartAfterPadding() { + return mLayoutManager.getPaddingTop(); + } + + @Override + public int getDecoratedMeasurement(View view) { + final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) + view.getLayoutParams(); + return mLayoutManager.getDecoratedMeasuredHeight(view) + params.topMargin + + params.bottomMargin; + } + + @Override + public int getDecoratedMeasurementInOther(View view) { + final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) + view.getLayoutParams(); + return mLayoutManager.getDecoratedMeasuredWidth(view) + params.leftMargin + + params.rightMargin; + } + + @Override + public int getDecoratedEnd(View view) { + final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) + view.getLayoutParams(); + return mLayoutManager.getDecoratedBottom(view) + params.bottomMargin; + } + + @Override + public int getDecoratedStart(View view) { + final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) + view.getLayoutParams(); + return mLayoutManager.getDecoratedTop(view) - params.topMargin; + } + + @Override + public int getTransformedEndWithDecoration(View view) { + mLayoutManager.getTransformedBoundingBox(view, true, mTmpRect); + return mTmpRect.bottom; + } + + @Override + public int getTransformedStartWithDecoration(View view) { + mLayoutManager.getTransformedBoundingBox(view, true, mTmpRect); + return mTmpRect.top; + } + + @Override + public int getTotalSpace() { + return mLayoutManager.getHeight() - mLayoutManager.getPaddingTop() + - mLayoutManager.getPaddingBottom(); + } + + @Override + public int getTotalSpaceInOther() { + return mLayoutManager.getWidth() - mLayoutManager.getPaddingLeft() + - mLayoutManager.getPaddingRight(); + } + + @Override + public int getEndPadding() { + return mLayoutManager.getPaddingBottom(); + } + + @Override + public int getMode() { + return mLayoutManager.getHeightMode(); + } + + @Override + public int getModeInOther() { + return mLayoutManager.getWidthMode(); + } + }; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/view/layoutmanager/PageSnapHelper.java b/app/src/main/java/com/chwl/app/view/layoutmanager/PageSnapHelper.java new file mode 100644 index 0000000..4446ee5 --- /dev/null +++ b/app/src/main/java/com/chwl/app/view/layoutmanager/PageSnapHelper.java @@ -0,0 +1,51 @@ +package com.chwl.app.view.layoutmanager; + +import androidx.recyclerview.widget.RecyclerView; + +/** + * The implementation will snap the center of the target child view to the center of + * the attached {@link RecyclerView}. And per Child per fling. + */ + +public class PageSnapHelper extends CenterSnapHelper { + + @Override + public boolean onFling(int velocityX, int velocityY) { + ViewPagerLayoutManager layoutManager = (ViewPagerLayoutManager) mRecyclerView.getLayoutManager(); + if (layoutManager == null) { + return false; + } + RecyclerView.Adapter adapter = mRecyclerView.getAdapter(); + if (adapter == null) { + return false; + } + + if (!layoutManager.getInfinite() && + (layoutManager.mOffset == layoutManager.getMaxOffset() + || layoutManager.mOffset == layoutManager.getMinOffset())) { + return false; + } + + final int minFlingVelocity = mRecyclerView.getMinFlingVelocity(); + mGravityScroller.fling(0, 0, velocityX, velocityY, + Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE); + + if (layoutManager.mOrientation == ViewPagerLayoutManager.VERTICAL + && Math.abs(velocityY) > minFlingVelocity) { + final int currentPosition = layoutManager.getCurrentPositionOffset(); + final int offsetPosition = mGravityScroller.getFinalY() * layoutManager.getDistanceRatio() > layoutManager.mInterval ? 1 : 0; + ScrollHelper.smoothScrollToPosition(mRecyclerView, layoutManager, layoutManager.getReverseLayout() ? + -currentPosition - offsetPosition : currentPosition + offsetPosition); + return true; + } else if (layoutManager.mOrientation == ViewPagerLayoutManager.HORIZONTAL + && Math.abs(velocityX) > minFlingVelocity) { + final int currentPosition = layoutManager.getCurrentPositionOffset(); + final int offsetPosition = mGravityScroller.getFinalX() * layoutManager.getDistanceRatio() > layoutManager.mInterval ? 1 : 0; + ScrollHelper.smoothScrollToPosition(mRecyclerView, layoutManager, layoutManager.getReverseLayout() ? + -currentPosition - offsetPosition : currentPosition + offsetPosition); + return true; + } + + return true; + } +} diff --git a/app/src/main/java/com/chwl/app/view/layoutmanager/RotateLayoutManager.java b/app/src/main/java/com/chwl/app/view/layoutmanager/RotateLayoutManager.java new file mode 100644 index 0000000..bab5b24 --- /dev/null +++ b/app/src/main/java/com/chwl/app/view/layoutmanager/RotateLayoutManager.java @@ -0,0 +1,178 @@ +package com.chwl.app.view.layoutmanager; + +import android.content.Context; +import android.view.View; + +/** + * An implementation of {@link ViewPagerLayoutManager} + * which rotates items + */ + +@SuppressWarnings({"WeakerAccess", "unused"}) +public class RotateLayoutManager extends ViewPagerLayoutManager { + + private int itemSpace; + private float angle; + private float moveSpeed; + private boolean reverseRotate; + + public RotateLayoutManager(Context context, int itemSpace) { + this(new Builder(context, itemSpace)); + } + + public RotateLayoutManager(Context context, int itemSpace, int orientation) { + this(new Builder(context, itemSpace).setOrientation(orientation)); + } + + public RotateLayoutManager(Context context, int itemSpace, int orientation, boolean reverseLayout) { + this(new Builder(context, itemSpace).setOrientation(orientation).setReverseLayout(reverseLayout)); + } + + public RotateLayoutManager(Builder builder) { + this(builder.context, builder.itemSpace, builder.angle, builder.orientation, builder.moveSpeed, + builder.reverseRotate, builder.maxVisibleItemCount, builder.distanceToBottom, + builder.reverseLayout); + } + + private RotateLayoutManager(Context context, int itemSpace, float angle, int orientation, float moveSpeed, + boolean reverseRotate, int maxVisibleItemCount, int distanceToBottom, + boolean reverseLayout) { + super(context, orientation, reverseLayout); + setDistanceToBottom(distanceToBottom); + setMaxVisibleItemCount(maxVisibleItemCount); + this.itemSpace = itemSpace; + this.angle = angle; + this.moveSpeed = moveSpeed; + this.reverseRotate = reverseRotate; + } + + public int getItemSpace() { + return itemSpace; + } + + public float getAngle() { + return angle; + } + + public float getMoveSpeed() { + return moveSpeed; + } + + public boolean getReverseRotate() { + return reverseRotate; + } + + public void setItemSpace(int itemSpace) { + assertNotInLayoutOrScroll(null); + if (this.itemSpace == itemSpace) return; + this.itemSpace = itemSpace; + removeAllViews(); + } + + public void setAngle(float centerScale) { + assertNotInLayoutOrScroll(null); + if (this.angle == centerScale) return; + this.angle = centerScale; + requestLayout(); + } + + public void setMoveSpeed(float moveSpeed) { + assertNotInLayoutOrScroll(null); + if (this.moveSpeed == moveSpeed) return; + this.moveSpeed = moveSpeed; + } + + public void setReverseRotate(boolean reverseRotate) { + assertNotInLayoutOrScroll(null); + if (this.reverseRotate == reverseRotate) return; + this.reverseRotate = reverseRotate; + requestLayout(); + } + + @Override + protected float setInterval() { + return mDecoratedMeasurement + itemSpace; + } + + @Override + protected void setItemViewProperty(View itemView, float targetOffset) { + itemView.setRotation(calRotation(targetOffset)); + } + + @Override + protected float getDistanceRatio() { + if (moveSpeed == 0) return Float.MAX_VALUE; + return 1 / moveSpeed; + } + + private float calRotation(float targetOffset) { + final float realAngle = reverseRotate ? angle : -angle; + return realAngle / mInterval * targetOffset; + } + + public static class Builder { + private static float INTERVAL_ANGLE = 360f; + private static final float DEFAULT_SPEED = 1f; + + private int itemSpace; + private int orientation; + private float angle; + private float moveSpeed; + private boolean reverseRotate; + private boolean reverseLayout; + private Context context; + private int maxVisibleItemCount; + private int distanceToBottom; + + public Builder(Context context, int itemSpace) { + this.context = context; + this.itemSpace = itemSpace; + orientation = HORIZONTAL; + angle = INTERVAL_ANGLE; + this.moveSpeed = DEFAULT_SPEED; + reverseRotate = false; + reverseLayout = false; + distanceToBottom = ViewPagerLayoutManager.INVALID_SIZE; + maxVisibleItemCount = ViewPagerLayoutManager.DETERMINE_BY_MAX_AND_MIN; + } + + public Builder setOrientation(int orientation) { + this.orientation = orientation; + return this; + } + + public Builder setAngle(float angle) { + this.angle = angle; + return this; + } + + public Builder setReverseLayout(boolean reverseLayout) { + this.reverseLayout = reverseLayout; + return this; + } + + public Builder setMoveSpeed(float moveSpeed) { + this.moveSpeed = moveSpeed; + return this; + } + + public Builder setReverseRotate(boolean reverseRotate) { + this.reverseRotate = reverseRotate; + return this; + } + + public Builder setMaxVisibleItemCount(int maxVisibleItemCount) { + this.maxVisibleItemCount = maxVisibleItemCount; + return this; + } + + public Builder setDistanceToBottom(int distanceToBottom) { + this.distanceToBottom = distanceToBottom; + return this; + } + + public RotateLayoutManager build() { + return new RotateLayoutManager(this); + } + } +} diff --git a/app/src/main/java/com/chwl/app/view/layoutmanager/ScaleLayoutManager.java b/app/src/main/java/com/chwl/app/view/layoutmanager/ScaleLayoutManager.java new file mode 100644 index 0000000..e92f6f3 --- /dev/null +++ b/app/src/main/java/com/chwl/app/view/layoutmanager/ScaleLayoutManager.java @@ -0,0 +1,221 @@ +package com.chwl.app.view.layoutmanager; + +import android.content.Context; +import android.view.View; + +/** + * An implementation of {@link ViewPagerLayoutManager} + * which zooms the center item + */ + +@SuppressWarnings({"WeakerAccess", "unused"}) +public class ScaleLayoutManager extends ViewPagerLayoutManager { + + private int itemSpace; + private float minScale; + private float moveSpeed; + private float maxAlpha; + private float minAlpha; + + public ScaleLayoutManager(Context context, int itemSpace) { + this(new Builder(context, itemSpace)); + } + + public ScaleLayoutManager(Context context, int itemSpace, int orientation) { + this(new Builder(context, itemSpace).setOrientation(orientation)); + } + + public ScaleLayoutManager(Context context, int itemSpace, int orientation, boolean reverseLayout) { + this(new Builder(context, itemSpace).setOrientation(orientation).setReverseLayout(reverseLayout)); + } + + public ScaleLayoutManager(Builder builder) { + this(builder.context, builder.itemSpace, builder.minScale, builder.maxAlpha, builder.minAlpha, + builder.orientation, builder.moveSpeed, builder.maxVisibleItemCount, builder.distanceToBottom, + builder.reverseLayout); + } + + private ScaleLayoutManager(Context context, int itemSpace, float minScale, float maxAlpha, float minAlpha, + int orientation, float moveSpeed, int maxVisibleItemCount, int distanceToBottom, + boolean reverseLayout) { + super(context, orientation, reverseLayout); + setDistanceToBottom(distanceToBottom); + setMaxVisibleItemCount(maxVisibleItemCount); + this.itemSpace = itemSpace; + this.minScale = minScale; + this.moveSpeed = moveSpeed; + this.maxAlpha = maxAlpha; + this.minAlpha = minAlpha; + } + + public int getItemSpace() { + return itemSpace; + } + + public float getMinScale() { + return minScale; + } + + public float getMoveSpeed() { + return moveSpeed; + } + + public float getMaxAlpha() { + return maxAlpha; + } + + public float getMinAlpha() { + return minAlpha; + } + + public void setItemSpace(int itemSpace) { + assertNotInLayoutOrScroll(null); + if (this.itemSpace == itemSpace) return; + this.itemSpace = itemSpace; + removeAllViews(); + } + + public void setMinScale(float minScale) { + assertNotInLayoutOrScroll(null); + if (this.minScale == minScale) return; + this.minScale = minScale; + removeAllViews(); + } + + public void setMaxAlpha(float maxAlpha) { + assertNotInLayoutOrScroll(null); + if (maxAlpha > 1) maxAlpha = 1; + if (this.maxAlpha == maxAlpha) return; + this.maxAlpha = maxAlpha; + requestLayout(); + } + + public void setMinAlpha(float minAlpha) { + assertNotInLayoutOrScroll(null); + if (minAlpha < 0) minAlpha = 0; + if (this.minAlpha == minAlpha) return; + this.minAlpha = minAlpha; + requestLayout(); + } + + public void setMoveSpeed(float moveSpeed) { + assertNotInLayoutOrScroll(null); + if (this.moveSpeed == moveSpeed) return; + this.moveSpeed = moveSpeed; + } + + @Override + protected float setInterval() { + return itemSpace + mDecoratedMeasurement; + } + + @Override + protected void setItemViewProperty(View itemView, float targetOffset) { + float scale = calculateScale(targetOffset + mSpaceMain); + itemView.setScaleX(scale); + itemView.setScaleY(scale); + final float alpha = calAlpha(targetOffset); + itemView.setAlpha(alpha); + } + + private float calAlpha(float targetOffset) { + final float offset = Math.abs(targetOffset); + float alpha = (minAlpha - maxAlpha) / mInterval * offset + maxAlpha; + if (offset >= mInterval) alpha = minAlpha; + return alpha; + } + + @Override + protected float getDistanceRatio() { + if (moveSpeed == 0) return Float.MAX_VALUE; + return 1 / moveSpeed; + } + + /** + * @param x start positon of the view you want scale + * @return the scale rate of current scroll mOffset + */ + private float calculateScale(float x) { + float deltaX = Math.abs(x - mSpaceMain); + if (deltaX - mDecoratedMeasurement > 0) deltaX = mDecoratedMeasurement; + return 1f - deltaX / mDecoratedMeasurement * (1f - minScale); + } + + public static class Builder { + private static final float SCALE_RATE = 0.8f; + private static final float DEFAULT_SPEED = 1f; + private static float MIN_ALPHA = 1f; + private static float MAX_ALPHA = 1f; + + private int itemSpace; + private int orientation; + private float minScale; + private float moveSpeed; + private float maxAlpha; + private float minAlpha; + private boolean reverseLayout; + private Context context; + private int maxVisibleItemCount; + private int distanceToBottom; + + public Builder(Context context, int itemSpace) { + this.itemSpace = itemSpace; + this.context = context; + orientation = HORIZONTAL; + minScale = SCALE_RATE; + this.moveSpeed = DEFAULT_SPEED; + maxAlpha = MAX_ALPHA; + minAlpha = MIN_ALPHA; + reverseLayout = false; + distanceToBottom = ViewPagerLayoutManager.INVALID_SIZE; + maxVisibleItemCount = ViewPagerLayoutManager.DETERMINE_BY_MAX_AND_MIN; + } + + public Builder setOrientation(int orientation) { + this.orientation = orientation; + return this; + } + + public Builder setMinScale(float minScale) { + this.minScale = minScale; + return this; + } + + public Builder setReverseLayout(boolean reverseLayout) { + this.reverseLayout = reverseLayout; + return this; + } + + public Builder setMaxAlpha(float maxAlpha) { + if (maxAlpha > 1) maxAlpha = 1; + this.maxAlpha = maxAlpha; + return this; + } + + public Builder setMinAlpha(float minAlpha) { + if (minAlpha < 0) minAlpha = 0; + this.minAlpha = minAlpha; + return this; + } + + public Builder setMoveSpeed(float moveSpeed) { + this.moveSpeed = moveSpeed; + return this; + } + + public Builder setMaxVisibleItemCount(int maxVisibleItemCount) { + this.maxVisibleItemCount = maxVisibleItemCount; + return this; + } + + public Builder setDistanceToBottom(int distanceToBottom) { + this.distanceToBottom = distanceToBottom; + return this; + } + + public ScaleLayoutManager build() { + return new ScaleLayoutManager(this); + } + } +} + diff --git a/app/src/main/java/com/chwl/app/view/layoutmanager/ScrollHelper.java b/app/src/main/java/com/chwl/app/view/layoutmanager/ScrollHelper.java new file mode 100644 index 0000000..6732fac --- /dev/null +++ b/app/src/main/java/com/chwl/app/view/layoutmanager/ScrollHelper.java @@ -0,0 +1,32 @@ +package com.chwl.app.view.layoutmanager; + +import android.view.View; + +import androidx.recyclerview.widget.RecyclerView; + +public class ScrollHelper { + + /* package */ static void scrollBy(RecyclerView recyclerView, ViewPagerLayoutManager viewPagerLayoutManager, int delta) { + if (viewPagerLayoutManager.getOrientation() == ViewPagerLayoutManager.VERTICAL) { + recyclerView.scrollBy(0, delta); + } else { + recyclerView.scrollBy(delta, 0); + } + } + + /* package */ static void smoothScrollToPosition(RecyclerView recyclerView, ViewPagerLayoutManager viewPagerLayoutManager, int targetPosition) { + final int delta = viewPagerLayoutManager.getOffsetToPosition(targetPosition); + if (viewPagerLayoutManager.getOrientation() == ViewPagerLayoutManager.VERTICAL) { + recyclerView.smoothScrollBy(0, delta); + } else { + recyclerView.smoothScrollBy(delta, 0); + } + } + + public static void smoothScrollToTargetView(RecyclerView recyclerView, View targetView) { + final RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); + if (!(layoutManager instanceof ViewPagerLayoutManager)) return; + final int targetPosition = ((ViewPagerLayoutManager) layoutManager).getLayoutPositionOfView(targetView); + smoothScrollToPosition(recyclerView, (ViewPagerLayoutManager) layoutManager, targetPosition); + } +} diff --git a/app/src/main/java/com/chwl/app/view/layoutmanager/ViewPagerLayoutManager.java b/app/src/main/java/com/chwl/app/view/layoutmanager/ViewPagerLayoutManager.java new file mode 100644 index 0000000..f83a562 --- /dev/null +++ b/app/src/main/java/com/chwl/app/view/layoutmanager/ViewPagerLayoutManager.java @@ -0,0 +1,973 @@ +package com.chwl.app.view.layoutmanager; + + +import static androidx.recyclerview.widget.RecyclerView.NO_POSITION; + +import android.content.Context; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.SparseArray; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.Interpolator; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import java.util.ArrayList; + +/** + * An implementation of {@link RecyclerView.LayoutManager} which behaves like view pager. + * Please make sure your child view have the same size. + */ + +@SuppressWarnings({"WeakerAccess", "unused", "SameParameterValue"}) +public abstract class ViewPagerLayoutManager extends LinearLayoutManager { + + public static final int DETERMINE_BY_MAX_AND_MIN = -1; + + public static final int HORIZONTAL = OrientationHelper.HORIZONTAL; + + public static final int VERTICAL = OrientationHelper.VERTICAL; + + private static final int DIRECTION_NO_WHERE = -1; + + private static final int DIRECTION_FORWARD = 0; + + private static final int DIRECTION_BACKWARD = 1; + + protected static final int INVALID_SIZE = Integer.MAX_VALUE; + + private SparseArray positionCache = new SparseArray<>(); + + protected int mDecoratedMeasurement; + + protected int mDecoratedMeasurementInOther; + + /** + * Current orientation. Either {@link #HORIZONTAL} or {@link #VERTICAL} + */ + int mOrientation; + + protected int mSpaceMain; + + protected int mSpaceInOther; + + /** + * The offset of property which will change while scrolling + */ + protected float mOffset; + + /** + * Many calculations are made depending on orientation. To keep it clean, this interface + * helps {@link LinearLayoutManager} make those decisions. + * Based on {@link #mOrientation}, an implementation is lazily created in + * {@link #ensureLayoutState} method. + */ + protected OrientationHelper mOrientationHelper; + + /** + * Defines if layout should be calculated from end to start. + */ + private boolean mReverseLayout = false; + + /** + * This keeps the final value for how LayoutManager should start laying out views. + * It is calculated by checking {@link #getReverseLayout()} and View's layout direction. + * {@link #onLayoutChildren(RecyclerView.Recycler, RecyclerView.State)} is run. + */ + private boolean mShouldReverseLayout = false; + + /** + * Works the same way as {@link android.widget.AbsListView#setSmoothScrollbarEnabled(boolean)}. + * see {@link android.widget.AbsListView#setSmoothScrollbarEnabled(boolean)} + */ + private boolean mSmoothScrollbarEnabled = true; + + /** + * When LayoutManager needs to scroll to a position, it sets this variable and requests a + * layout which will check this variable and re-layout accordingly. + */ + private int mPendingScrollPosition = NO_POSITION; + + private SavedState mPendingSavedState = null; + + protected float mInterval; //the mInterval of each item's mOffset + + /* package */ OnPageChangeListener onPageChangeListener; + + private boolean mRecycleChildrenOnDetach; + + private boolean mInfinite = false; + + private boolean mEnableBringCenterToFront; + + private int mLeftItems; + + private int mRightItems; + + /** + * max visible item count + */ + private int mMaxVisibleItemCount = DETERMINE_BY_MAX_AND_MIN; + + private Interpolator mSmoothScrollInterpolator; + + private int mDistanceToBottom = INVALID_SIZE; + + /** + * use for handle focus + */ + private View currentFocusView; + + /** + * @return the mInterval of each item's mOffset + */ + protected abstract float setInterval(); + + protected abstract void setItemViewProperty(View itemView, float targetOffset); + + /** + * cause elevation is not support below api 21, + * so you can set your elevation here for supporting it below api 21 + * or you can just setElevation in {@link #setItemViewProperty(View, float)} + */ + protected float setViewElevation(View itemView, float targetOffset) { + return 0; + } + + /** + * Creates a horizontal ViewPagerLayoutManager + */ + public ViewPagerLayoutManager(Context context) { + this(context, HORIZONTAL, false); + } + + /** + * @param orientation Layout orientation. Should be {@link #HORIZONTAL} or {@link #VERTICAL} + * @param reverseLayout When set to true, layouts from end to start + */ + public ViewPagerLayoutManager(Context context, int orientation, boolean reverseLayout) { + super(context); + setOrientation(orientation); + setReverseLayout(reverseLayout); + setAutoMeasureEnabled(true); + setItemPrefetchEnabled(false); + } + + @Override + public RecyclerView.LayoutParams generateDefaultLayoutParams() { + return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT); + } + + /** + * Returns whether LayoutManager will recycle its children when it is detached from + * RecyclerView. + * + * @return true if LayoutManager will recycle its children when it is detached from + * RecyclerView. + */ + public boolean getRecycleChildrenOnDetach() { + return mRecycleChildrenOnDetach; + } + + /** + * Set whether LayoutManager will recycle its children when it is detached from + * RecyclerView. + *

+ * If you are using a {@link RecyclerView.RecycledViewPool}, it might be a good idea to set + * this flag to true so that views will be available to other RecyclerViews + * immediately. + *

+ * Note that, setting this flag will result in a performance drop if RecyclerView + * is restored. + * + * @param recycleChildrenOnDetach Whether children should be recycled in detach or not. + */ + public void setRecycleChildrenOnDetach(boolean recycleChildrenOnDetach) { + mRecycleChildrenOnDetach = recycleChildrenOnDetach; + } + + @Override + public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) { + super.onDetachedFromWindow(view, recycler); + if (mRecycleChildrenOnDetach) { + removeAndRecycleAllViews(recycler); + recycler.clear(); + } + } + + @Override + public Parcelable onSaveInstanceState() { + if (mPendingSavedState != null) { + return new SavedState(mPendingSavedState); + } + SavedState savedState = new SavedState(); + savedState.position = mPendingScrollPosition; + savedState.offset = mOffset; + savedState.isReverseLayout = mShouldReverseLayout; + return savedState; + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + if (state instanceof SavedState) { + mPendingSavedState = new SavedState((SavedState) state); + requestLayout(); + } + } + + /** + * @return true if {@link #getOrientation()} is {@link #HORIZONTAL} + */ + @Override + public boolean canScrollHorizontally() { + return mOrientation == HORIZONTAL; + } + + /** + * @return true if {@link #getOrientation()} is {@link #VERTICAL} + */ + @Override + public boolean canScrollVertically() { + return mOrientation == VERTICAL; + } + + /** + * Returns the current orientation of the layout. + * + * @return Current orientation, either {@link #HORIZONTAL} or {@link #VERTICAL} + * @see #setOrientation(int) + */ + public int getOrientation() { + return mOrientation; + } + + /** + * Sets the orientation of the layout. {@link ViewPagerLayoutManager} + * will do its best to keep scroll position. + * + * @param orientation {@link #HORIZONTAL} or {@link #VERTICAL} + */ + public void setOrientation(int orientation) { + if (orientation != HORIZONTAL && orientation != VERTICAL) { + throw new IllegalArgumentException("invalid orientation:" + orientation); + } + assertNotInLayoutOrScroll(null); + if (orientation == mOrientation) { + return; + } + mOrientation = orientation; + mOrientationHelper = null; + mDistanceToBottom = INVALID_SIZE; + removeAllViews(); + } + + /** + * Returns the max visible item count, {@link #DETERMINE_BY_MAX_AND_MIN} means it haven't been set now + * And it will use {@link #maxRemoveOffset()} and {@link #minRemoveOffset()} to handle the range + * + * @return Max visible item count + */ + public int getMaxVisibleItemCount() { + return mMaxVisibleItemCount; + } + + /** + * Set the max visible item count, {@link #DETERMINE_BY_MAX_AND_MIN} means it haven't been set now + * And it will use {@link #maxRemoveOffset()} and {@link #minRemoveOffset()} to handle the range + * + * @param mMaxVisibleItemCount Max visible item count + */ + public void setMaxVisibleItemCount(int mMaxVisibleItemCount) { + assertNotInLayoutOrScroll(null); + if (this.mMaxVisibleItemCount == mMaxVisibleItemCount) return; + this.mMaxVisibleItemCount = mMaxVisibleItemCount; + removeAllViews(); + } + + /** + * Calculates the view layout order. (e.g. from end to start or start to end) + * RTL layout support is applied automatically. So if layout is RTL and + * {@link #getReverseLayout()} is {@code true}, elements will be laid out starting from left. + */ + private void resolveShouldLayoutReverse() { + // A == B is the same result, but we rather keep it readable + if (mOrientation == VERTICAL || !isLayoutRTL()) { + mShouldReverseLayout = mReverseLayout; + } else { + mShouldReverseLayout = !mReverseLayout; + } + } + + /** + * Returns if views are laid out from the opposite direction of the layout. + * + * @return If layout is reversed or not. + * @see #setReverseLayout(boolean) + */ + public boolean getReverseLayout() { + return mReverseLayout; + } + + /** + * Used to reverse item traversal and layout order. + * This behaves similar to the layout change for RTL views. When set to true, first item is + * laid out at the end of the UI, second item is laid out before it etc. + *

+ * For horizontal layouts, it depends on the layout direction. + * When set to true, If {@link android.support.v7.widget.RecyclerView} is LTR, than it will + * layout from RTL, if {@link android.support.v7.widget.RecyclerView}} is RTL, it will layout + * from LTR. + */ + public void setReverseLayout(boolean reverseLayout) { + assertNotInLayoutOrScroll(null); + if (reverseLayout == mReverseLayout) { + return; + } + mReverseLayout = reverseLayout; + removeAllViews(); + } + + public void setSmoothScrollInterpolator(Interpolator smoothScrollInterpolator) { + this.mSmoothScrollInterpolator = smoothScrollInterpolator; + } + + @Override + public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) { + final int offsetPosition; + + // fix wrong scroll direction when infinite enable + if (mInfinite) { + final int currentPosition = getCurrentPosition(); + final int total = getItemCount(); + final int targetPosition; + if (position < currentPosition) { + int d1 = currentPosition - position; + int d2 = total - currentPosition + position; + targetPosition = d1 < d2 ? (currentPosition - d1) : (currentPosition + d2); + } else { + int d1 = position - currentPosition; + int d2 = currentPosition + total - position; + targetPosition = d1 < d2 ? (currentPosition + d1) : (currentPosition - d2); + } + + offsetPosition = getOffsetToPosition(targetPosition); + } else { + offsetPosition = getOffsetToPosition(position); + } + + if (mOrientation == VERTICAL) { + recyclerView.smoothScrollBy(0, offsetPosition, mSmoothScrollInterpolator); + } else { + recyclerView.smoothScrollBy(offsetPosition, 0, mSmoothScrollInterpolator); + } + } + + @Override + public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { + if (state.getItemCount() == 0) { + removeAndRecycleAllViews(recycler); + mOffset = 0; + return; + } + + ensureLayoutState(); + resolveShouldLayoutReverse(); + + //make sure properties are correct while measure more than once + View scrap = getMeasureView(recycler, state, 0); + if (scrap == null) { + removeAndRecycleAllViews(recycler); + mOffset = 0; + return; + } + + measureChildWithMargins(scrap, 0, 0); + mDecoratedMeasurement = mOrientationHelper.getDecoratedMeasurement(scrap); + mDecoratedMeasurementInOther = mOrientationHelper.getDecoratedMeasurementInOther(scrap); + mSpaceMain = (mOrientationHelper.getTotalSpace() - mDecoratedMeasurement) / 2; + if (mDistanceToBottom == INVALID_SIZE) { + mSpaceInOther = (mOrientationHelper.getTotalSpaceInOther() - mDecoratedMeasurementInOther) / 2; + } else { + mSpaceInOther = mOrientationHelper.getTotalSpaceInOther() - mDecoratedMeasurementInOther - mDistanceToBottom; + } + + mInterval = setInterval(); + setUp(); + if (mInterval == 0) { + mLeftItems = 1; + mRightItems = 1; + } else { + mLeftItems = (int) Math.abs(minRemoveOffset() / mInterval) + 1; + mRightItems = (int) Math.abs(maxRemoveOffset() / mInterval) + 1; + } + + if (mPendingSavedState != null) { + mShouldReverseLayout = mPendingSavedState.isReverseLayout; + mPendingScrollPosition = mPendingSavedState.position; + mOffset = mPendingSavedState.offset; + } + + if (mPendingScrollPosition != NO_POSITION) { + mOffset = mShouldReverseLayout ? + mPendingScrollPosition * -mInterval : mPendingScrollPosition * mInterval; + } + + layoutItems(recycler); + } + + private View getMeasureView(RecyclerView.Recycler recycler, RecyclerView.State state, int index) { + if (index >= state.getItemCount() || index < 0) return null; + try { + return recycler.getViewForPosition(index); + } catch (Exception e) { + return getMeasureView(recycler, state, index + 1); + } + } + + @Override + public void onLayoutCompleted(RecyclerView.State state) { + super.onLayoutCompleted(state); + mPendingSavedState = null; + mPendingScrollPosition = NO_POSITION; + } + + @Override + public boolean onAddFocusables(RecyclerView recyclerView, ArrayList views, int direction, int focusableMode) { + final int currentPosition = getCurrentPosition(); + final View currentView = findViewByPosition(currentPosition); + if (currentView == null) return true; + if (recyclerView.hasFocus()) { + final int movement = getMovement(direction); + if (movement != DIRECTION_NO_WHERE) { + final int targetPosition = movement == DIRECTION_BACKWARD ? + currentPosition - 1 : currentPosition + 1; + ScrollHelper.smoothScrollToPosition(recyclerView, this, targetPosition); + } + } else { + currentView.addFocusables(views, direction, focusableMode); + } + return true; + } + + @Override + public View onFocusSearchFailed(View focused, int focusDirection, RecyclerView.Recycler recycler, RecyclerView.State state) { + return null; + } + + private int getMovement(int direction) { + if (mOrientation == VERTICAL) { + if (direction == View.FOCUS_UP) { + return mShouldReverseLayout ? DIRECTION_FORWARD : DIRECTION_BACKWARD; + } else if (direction == View.FOCUS_DOWN) { + return mShouldReverseLayout ? DIRECTION_BACKWARD : DIRECTION_FORWARD; + } else { + return DIRECTION_NO_WHERE; + } + } else { + if (direction == View.FOCUS_LEFT) { + return mShouldReverseLayout ? DIRECTION_FORWARD : DIRECTION_BACKWARD; + } else if (direction == View.FOCUS_RIGHT) { + return mShouldReverseLayout ? DIRECTION_BACKWARD : DIRECTION_FORWARD; + } else { + return DIRECTION_NO_WHERE; + } + } + } + + void ensureLayoutState() { + if (mOrientationHelper == null) { + mOrientationHelper = OrientationHelper.createOrientationHelper(this, mOrientation); + } + } + + /** + * You can set up your own properties here or change the exist properties like mSpaceMain and mSpaceInOther + */ + protected void setUp() { + + } + + private float getProperty(int position) { + return mShouldReverseLayout ? position * -mInterval : position * mInterval; + } + + @Override + public void onAdapterChanged(RecyclerView.Adapter oldAdapter, RecyclerView.Adapter newAdapter) { + removeAllViews(); + mOffset = 0; + } + + @Override + public void scrollToPosition(int position) { + if (!mInfinite && (position < 0 || position >= getItemCount())) return; + mPendingScrollPosition = position; + mOffset = mShouldReverseLayout ? position * -mInterval : position * mInterval; + requestLayout(); + } + + @Override + public int computeHorizontalScrollOffset(RecyclerView.State state) { + return computeScrollOffset(); + } + + @Override + public int computeVerticalScrollOffset(RecyclerView.State state) { + return computeScrollOffset(); + } + + @Override + public int computeHorizontalScrollExtent(RecyclerView.State state) { + return computeScrollExtent(); + } + + @Override + public int computeVerticalScrollExtent(RecyclerView.State state) { + return computeScrollExtent(); + } + + @Override + public int computeHorizontalScrollRange(RecyclerView.State state) { + return computeScrollRange(); + } + + @Override + public int computeVerticalScrollRange(RecyclerView.State state) { + return computeScrollRange(); + } + + private int computeScrollOffset() { + if (getChildCount() == 0) { + return 0; + } + + if (!mSmoothScrollbarEnabled) { + return !mShouldReverseLayout ? + getCurrentPosition() : getItemCount() - getCurrentPosition() - 1; + } + + final float realOffset = getOffsetOfRightAdapterPosition(); + return !mShouldReverseLayout ? (int) realOffset : (int) ((getItemCount() - 1) * mInterval + realOffset); + } + + private int computeScrollExtent() { + if (getChildCount() == 0) { + return 0; + } + + if (!mSmoothScrollbarEnabled) { + return 1; + } + + return (int) mInterval; + } + + private int computeScrollRange() { + if (getChildCount() == 0) { + return 0; + } + + if (!mSmoothScrollbarEnabled) { + return getItemCount(); + } + + return (int) (getItemCount() * mInterval); + } + + @Override + public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) { + if (mOrientation == VERTICAL) { + return 0; + } + return scrollBy(dx, recycler, state); + } + + @Override + public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) { + if (mOrientation == HORIZONTAL) { + return 0; + } + return scrollBy(dy, recycler, state); + } + + private int scrollBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) { + if (getChildCount() == 0 || dy == 0) { + return 0; + } + ensureLayoutState(); + int willScroll = dy; + + float realDx = dy / getDistanceRatio(); + if (Math.abs(realDx) < 0.00000001f) { + return 0; + } + float targetOffset = mOffset + realDx; + + //handle the boundary + if (!mInfinite && targetOffset < getMinOffset()) { + willScroll -= (targetOffset - getMinOffset()) * getDistanceRatio(); + } else if (!mInfinite && targetOffset > getMaxOffset()) { + willScroll = (int) ((getMaxOffset() - mOffset) * getDistanceRatio()); + } + + realDx = willScroll / getDistanceRatio(); + + mOffset += realDx; + + //handle recycle + layoutItems(recycler); + + return willScroll; + } + + private void layoutItems(RecyclerView.Recycler recycler) { + detachAndScrapAttachedViews(recycler); + positionCache.clear(); + + final int itemCount = getItemCount(); + if (itemCount == 0) return; + + // make sure that current position start from 0 to 1 + final int currentPos = mShouldReverseLayout ? + -getCurrentPositionOffset() : getCurrentPositionOffset(); + int start = currentPos - mLeftItems; + int end = currentPos + mRightItems; + + // handle max visible count + if (useMaxVisibleCount()) { + boolean isEven = mMaxVisibleItemCount % 2 == 0; + if (isEven) { + int offset = mMaxVisibleItemCount / 2; + start = currentPos - offset + 1; + end = currentPos + offset + 1; + } else { + int offset = (mMaxVisibleItemCount - 1) / 2; + start = currentPos - offset; + end = currentPos + offset + 1; + } + } + + if (!mInfinite) { + if (start < 0) { + start = 0; + if (useMaxVisibleCount()) end = mMaxVisibleItemCount; + } + if (end > itemCount) end = itemCount; + } + + float lastOrderWeight = Float.MIN_VALUE; + for (int i = start; i < end; i++) { + if (useMaxVisibleCount() || !removeCondition(getProperty(i) - mOffset)) { + // start and end base on current position, + // so we need to calculate the adapter position + int adapterPosition = i; + if (i >= itemCount) { + adapterPosition %= itemCount; + } else if (i < 0) { + int delta = (-adapterPosition) % itemCount; + if (delta == 0) delta = itemCount; + adapterPosition = itemCount - delta; + } + final View scrap = recycler.getViewForPosition(adapterPosition); + measureChildWithMargins(scrap, 0, 0); + resetViewProperty(scrap); + // we need i to calculate the real offset of current view + final float targetOffset = getProperty(i) - mOffset; + layoutScrap(scrap, targetOffset); + final float orderWeight = mEnableBringCenterToFront ? + setViewElevation(scrap, targetOffset) : adapterPosition; + if (orderWeight > lastOrderWeight) { + addView(scrap); + } else { + addView(scrap, 0); + } + if (i == currentPos) currentFocusView = scrap; + lastOrderWeight = orderWeight; + positionCache.put(i, scrap); + } + } + + currentFocusView.requestFocus(); + } + + private boolean useMaxVisibleCount() { + return mMaxVisibleItemCount != DETERMINE_BY_MAX_AND_MIN; + } + + private boolean removeCondition(float targetOffset) { + return targetOffset > maxRemoveOffset() || targetOffset < minRemoveOffset(); + } + + private void resetViewProperty(View v) { + v.setRotation(0); + v.setRotationY(0); + v.setRotationX(0); + v.setScaleX(1f); + v.setScaleY(1f); + v.setAlpha(1f); + } + + /* package */ float getMaxOffset() { + return !mShouldReverseLayout ? (getItemCount() - 1) * mInterval : 0; + } + + /* package */ float getMinOffset() { + return !mShouldReverseLayout ? 0 : -(getItemCount() - 1) * mInterval; + } + + private void layoutScrap(View scrap, float targetOffset) { + final int left = calItemLeft(scrap, targetOffset); + final int top = calItemTop(scrap, targetOffset); + if (mOrientation == VERTICAL) { + layoutDecorated(scrap, mSpaceInOther + left, mSpaceMain + top, + mSpaceInOther + left + mDecoratedMeasurementInOther, mSpaceMain + top + mDecoratedMeasurement); + } else { + layoutDecorated(scrap, mSpaceMain + left, mSpaceInOther + top, + mSpaceMain + left + mDecoratedMeasurement, mSpaceInOther + top + mDecoratedMeasurementInOther); + } + setItemViewProperty(scrap, targetOffset); + } + + protected int calItemLeft(View itemView, float targetOffset) { + return mOrientation == VERTICAL ? 0 : (int) targetOffset; + } + + protected int calItemTop(View itemView, float targetOffset) { + return mOrientation == VERTICAL ? (int) targetOffset : 0; + } + + /** + * when the target offset reach this, + * the view will be removed and recycled in {@link #layoutItems(RecyclerView.Recycler)} + */ + protected float maxRemoveOffset() { + return mOrientationHelper.getTotalSpace() - mSpaceMain; + } + + /** + * when the target offset reach this, + * the view will be removed and recycled in {@link #layoutItems(RecyclerView.Recycler)} + */ + protected float minRemoveOffset() { + return -mDecoratedMeasurement - mOrientationHelper.getStartAfterPadding() - mSpaceMain; + } + + protected float getDistanceRatio() { + return 1f; + } + + public int getCurrentPosition() { + if (getItemCount() == 0) return 0; + + int position = getCurrentPositionOffset(); + if (!mInfinite) return Math.abs(position); + + position = !mShouldReverseLayout ? + //take care of position = getItemCount() + (position >= 0 ? + position % getItemCount() : + getItemCount() + position % getItemCount()) : + (position > 0 ? + getItemCount() - position % getItemCount() : + -position % getItemCount()); + return position == getItemCount() ? 0 : position; + } + + @Override + public View findViewByPosition(int position) { + final int itemCount = getItemCount(); + if (itemCount == 0) return null; + for (int i = 0; i < positionCache.size(); i++) { + final int key = positionCache.keyAt(i); + if (key >= 0) { + if (position == key % itemCount) return positionCache.valueAt(i); + } else { + int delta = key % itemCount; + if (delta == 0) delta = -itemCount; + if (itemCount + delta == position) return positionCache.valueAt(i); + } + } + return null; + } + + public int getLayoutPositionOfView(View v) { + for (int i = 0; i < positionCache.size(); i++) { + int key = positionCache.keyAt(i); + View value = positionCache.get(key); + if (value == v) return key; + } + return -1; + } + + /* package */ int getCurrentPositionOffset() { + if (mInterval == 0) return 0; + return Math.round(mOffset / mInterval); + } + + /** + * Sometimes we need to get the right offset of matching adapter position + * cause when {@link #mInfinite} is set true, there will be no limitation of {@link #mOffset} + */ + private float getOffsetOfRightAdapterPosition() { + if (mShouldReverseLayout) + return mInfinite ? + (mOffset <= 0 ? + (mOffset % (mInterval * getItemCount())) : + (getItemCount() * -mInterval + mOffset % (mInterval * getItemCount()))) : + mOffset; + else + return mInfinite ? + (mOffset >= 0 ? + (mOffset % (mInterval * getItemCount())) : + (getItemCount() * mInterval + mOffset % (mInterval * getItemCount()))) : + mOffset; + } + + /** + * used by {@link CenterSnapHelper} to center the current view + * + * @return the dy between center and current position + */ + public int getOffsetToCenter() { + if (mInfinite) + return (int) ((getCurrentPositionOffset() * mInterval - mOffset) * getDistanceRatio()); + return (int) ((getCurrentPosition() * + (!mShouldReverseLayout ? mInterval : -mInterval) - mOffset) * getDistanceRatio()); + } + + public int getOffsetToPosition(int position) { + if (mInfinite) + return (int) (((getCurrentPositionOffset() + + (!mShouldReverseLayout ? position - getCurrentPositionOffset() : -getCurrentPositionOffset() - position)) * + mInterval - mOffset) * getDistanceRatio()); + return (int) ((position * + (!mShouldReverseLayout ? mInterval : -mInterval) - mOffset) * getDistanceRatio()); + } + + public void setOnPageChangeListener(OnPageChangeListener onPageChangeListener) { + this.onPageChangeListener = onPageChangeListener; + } + + public void setInfinite(boolean enable) { + assertNotInLayoutOrScroll(null); + if (enable == mInfinite) { + return; + } + mInfinite = enable; + requestLayout(); + } + + public boolean getInfinite() { + return mInfinite; + } + + public int getDistanceToBottom() { + return mDistanceToBottom == INVALID_SIZE ? + (mOrientationHelper.getTotalSpaceInOther() - mDecoratedMeasurementInOther) / 2 : mDistanceToBottom; + } + + public void setDistanceToBottom(int mDistanceToBottom) { + assertNotInLayoutOrScroll(null); + if (this.mDistanceToBottom == mDistanceToBottom) return; + this.mDistanceToBottom = mDistanceToBottom; + removeAllViews(); + } + + /** + * When smooth scrollbar is enabled, the position and size of the scrollbar thumb is computed + * based on the number of visible pixels in the visible items. This however assumes that all + * list items have similar or equal widths or heights (depending on list orientation). + * If you use a list in which items have different dimensions, the scrollbar will change + * appearance as the user scrolls through the list. To avoid this issue, you need to disable + * this property. + *

+ * When smooth scrollbar is disabled, the position and size of the scrollbar thumb is based + * solely on the number of items in the adapter and the position of the visible items inside + * the adapter. This provides a stable scrollbar as the user navigates through a list of items + * with varying widths / heights. + * + * @param enabled Whether or not to enable smooth scrollbar. + * @see #setSmoothScrollbarEnabled(boolean) + */ + public void setSmoothScrollbarEnabled(boolean enabled) { + mSmoothScrollbarEnabled = enabled; + } + + public void setEnableBringCenterToFront(boolean bringCenterToTop) { + assertNotInLayoutOrScroll(null); + if (mEnableBringCenterToFront == bringCenterToTop) { + return; + } + this.mEnableBringCenterToFront = bringCenterToTop; + requestLayout(); + } + + public boolean getEnableBringCenterToFront() { + return mEnableBringCenterToFront; + } + + /** + * Returns the current state of the smooth scrollbar feature. It is enabled by default. + * + * @return True if smooth scrollbar is enabled, false otherwise. + * @see #setSmoothScrollbarEnabled(boolean) + */ + public boolean getSmoothScrollbarEnabled() { + return mSmoothScrollbarEnabled; + } + + private static class SavedState implements Parcelable { + int position; + float offset; + boolean isReverseLayout; + + SavedState() { + + } + + SavedState(Parcel in) { + position = in.readInt(); + offset = in.readFloat(); + isReverseLayout = in.readInt() == 1; + } + + public SavedState(SavedState other) { + position = other.position; + offset = other.offset; + isReverseLayout = other.isReverseLayout; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(position); + dest.writeFloat(offset); + dest.writeInt(isReverseLayout ? 1 : 0); + } + + public static final Creator CREATOR + = new Creator() { + @Override + public SavedState createFromParcel(Parcel in) { + return new SavedState(in); + } + + @Override + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + } + + public interface OnPageChangeListener { + void onPageSelected(int position); + + void onPageScrollStateChanged(int state); + } +} diff --git a/app/src/main/java/com/chwl/app/vip/VipBroadcastView.kt b/app/src/main/java/com/chwl/app/vip/VipBroadcastView.kt new file mode 100644 index 0000000..501a430 --- /dev/null +++ b/app/src/main/java/com/chwl/app/vip/VipBroadcastView.kt @@ -0,0 +1,108 @@ +package com.chwl.app.vip + +import android.animation.ObjectAnimator +import android.annotation.SuppressLint +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.widget.FrameLayout +import androidx.core.animation.doOnEnd +import androidx.core.view.isGone +import androidx.core.view.isVisible +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage +import com.chwl.app.databinding.LayoutVipBroadcastViewBinding +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.core.im.custom.bean.VipMessageAttachment +import com.chwl.core.room.anotherroompk.ShowUserInfoDialogEvent +import com.chwl.core.utils.extension.subAndReplaceDot +import com.chwl.core.vip.VipBroadcastMsgEvent +import com.chwl.library.rxbus.RxBus +import io.reactivex.Observable +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode +import java.util.concurrent.TimeUnit + +class VipBroadcastView @JvmOverloads constructor( + context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 +) : FrameLayout(context, attrs, defStyleAttr) { + + private val binding = LayoutVipBroadcastViewBinding.inflate(LayoutInflater.from(context)) + private val messages: MutableList by lazy { ArrayList() } + private var disposable: Disposable? = null + + init { + addView(binding.root, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)) + binding.llRoot.setOnClickListener { + RxBus.get().post(ShowUserInfoDialogEvent(binding.llRoot.tag as String)) + } + EventBus.getDefault().register(this) + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + EventBus.getDefault().unregister(this) + disposable?.dispose() + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onVipBroadcastMsgEvent(event: VipBroadcastMsgEvent) { + event.message?.let { addMessage(it) } + } + + private fun addMessage(chatRoomMessage: ChatRoomMessage) { + messages.add(chatRoomMessage) + if (isGone) { + isVisible = true + ObjectAnimator.ofFloat( + this, + "alpha", + 0f, + 1f + ) + .setDuration(500) + .start() + } + if (disposable == null || messages.size == 1) { + disposable = Observable.interval(0, 5, TimeUnit.SECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .doOnDispose { + ObjectAnimator.ofFloat( + this, + "alpha", + 1f, + 0f + ) + .setDuration(200) + .apply { + doOnEnd { + binding.tvContent.stop() + isGone = true + } + } + .start() + } + .takeWhile { messages.size > 0 } + .subscribe { + showMessage(messages.removeAt(0)) + } + } + } + + @SuppressLint("SetTextI18n") + private fun showMessage(chatRoomMessage: ChatRoomMessage?) { + val attachment = chatRoomMessage?.attachment as? VipMessageAttachment ?: return + attachment.vipMessageInfo?.let { + ImageLoadUtils.loadAvatar(it.avatar, binding.ivAvatar) + ImageLoadUtils.loadImage(context, it.vipIcon, binding.ivVipIcon) + binding.tvNick.text = it.nick.subAndReplaceDot(7) + ":" + binding.tvContent.text = it.content + binding.tvContent.start() + binding.llRoot.tag = it.uid.toString() + } + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/vip/VipCenterActivity.kt b/app/src/main/java/com/chwl/app/vip/VipCenterActivity.kt new file mode 100644 index 0000000..681d705 --- /dev/null +++ b/app/src/main/java/com/chwl/app/vip/VipCenterActivity.kt @@ -0,0 +1,520 @@ +package com.chwl.app.vip + +import android.annotation.SuppressLint +import android.content.Context +import android.content.Intent +import android.util.Log +import android.view.View +import android.widget.TextView +import androidx.activity.viewModels +import androidx.core.view.isVisible +import androidx.lifecycle.Observer +import androidx.lifecycle.lifecycleScope +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.base.TitleBar +import com.chwl.app.common.EmptyViewHelper +import com.chwl.app.constants.BundleKeys +import com.chwl.app.databinding.ActivityVipCenterBinding +import com.chwl.app.ui.pay.ChargeActivity +import com.chwl.app.ui.utils.RVDelegate +import com.chwl.app.ui.webview.CommonWebViewActivity +import com.chwl.app.vip.adapter.OnItemClickListener +import com.chwl.app.vip.adapter.VipAuthAdapter +import com.chwl.app.vip.adapter.VipCenterBannerAdapter +import com.chwl.app.vip.adapter.VipCenterIdentificationsAdapter +import com.chwl.app.vip.adapter.VipMagicIndicatorAdapter +import com.chwl.app.vip.adapter.VipRebateAdapter +import com.chwl.app.vip.dialog.SelectPayTypeDialog +import com.chwl.app.vip.dialog.VipAuthDetailsDialog +import com.chwl.core.UriProvider +import com.chwl.core.pay.PayModel +import com.chwl.core.pay.bean.ChargeBean +import com.chwl.core.utils.extension.toast +import com.chwl.core.vip.bean.VipAuthInfo +import com.chwl.core.vip.bean.VipInfo +import com.example.module_base.support.billing.IBillingService +import com.example.module_base.support.billing.IProductDetails +import com.example.module_base.support.billing.IPurchase +import com.netease.nim.uikit.StatusBarUtil +import com.youth.banner.Banner +import com.youth.banner.listener.OnPageChangeListener +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import org.greenrobot.eventbus.EventBus + + +class VipCenterActivity : BaseViewBindingActivity(), + VipMagicIndicatorAdapter.OnItemSelectListener, OnItemClickListener, IBillingService.Listener { + + private val authAdapter = VipAuthAdapter() // 用户权限 + private val vipViewModel: VipViewModel by viewModels() + private var chargeList: List? = null + private var authInfoList: List? = null + private val rebateAdapter = VipRebateAdapter() + private var currentChargeInfo: ChargeBean? = null + private lateinit var rvDelegate: RVDelegate + private lateinit var banner:Banner + + private lateinit var recyclerView: RecyclerView + private lateinit var vipIdentificationsAdapter: VipCenterIdentificationsAdapter + + private var currentIndex = 0 + + companion object { + + @JvmStatic + fun start(context: Context) { +// val starter = Intent(context, VipCenterActivity::class.java) +// context.startActivity(starter) + CommonWebViewActivity.start(context, UriProvider.getVipCenter()) + } + + @JvmStatic + fun start(context: Context,vipLevel:Int) { + val starter = Intent(context, VipCenterActivity::class.java) + starter.putExtra(BundleKeys.KEY_EXTRA_1,vipLevel) + context.startActivity(starter) + } + + private const val BIND_CODE_GOLD = 200 + private const val TAG = "VipCenterActivity" + } + + @SuppressLint("SetTextI18N") + override fun init() { + EventBus.getDefault().register(this) + initVipCenterBar(getString(R.string.vip_center)) + updateVipCenterBar() + + initView() + initObserve() + + rvDelegate = RVDelegate.Builder() + .setLayoutManager(GridLayoutManager(this, 3)) + .setRecyclerView(binding.recyclerViewBottom) + .setEmptyView( + EmptyViewHelper.createEmptyTextView( + context, + getString(R.string.me_no_search_results) + ) + ) + .setAdapter(authAdapter) + .build() + + handleAuthAdapter() + handleViewModel() + handleBinding() + + requestChargeList{ + loadChargeList(it) + } + } + + + override fun needSteepStateBar(): Boolean { + return true + } + + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + StatusBarUtil.StatusBarLightMode(this) + } + + private fun initView() { + banner = findViewById(R.id.banner_view) + banner.setBannerGalleryEffect(20, 20, 15) + banner.addOnPageChangeListener(object : OnPageChangeListener { + override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) { + // 页面滑动中 + } + + override fun onPageSelected(position: Int) { + // 页面被选中,position 已更新 + currentIndex = position + vipViewModel.onItemSelect(position) + refreshBottomArea() + } + + override fun onPageScrollStateChanged(state: Int) { + // 页面滚动状态改变 + } + }) + + recyclerView = findViewById(R.id.recycler_view) + recyclerView.layoutManager = GridLayoutManager(this, 2) + } + + + private fun updateVipCenterBar() { + mTitleBar = findViewById(R.id.title_bar) +// if (mTitleBar != null) { +// mTitleBar.addAction(object : TitleBar.ImageAction(R.drawable.vip_center_help_button) { +// override fun performAction(view: View) { +// CommonWebViewActivity.start( +// this@VipCenterActivity, +// UriProvider.getVipHelpUrl()) +// } +// }) +// } + } + + private fun handleAuthAdapter() { + authAdapter.setOnItemClickListener { _, _, position -> + authAdapter.getItem(position)?.let { + VipAuthDetailsDialog.newInstance(it.descPic, it.authName, it.authIntro).show(this) + } + } + } + + private fun handleBinding() { + binding.layoutOpenVip.setOnClickListener { + checkBuyVip { + buyVip() + } + } + + binding.recyclerViewBottom.isNestedScrollingEnabled = false + } + + @SuppressLint("NotifyDataSetChanged") + private fun handleViewModel() { + vipViewModel.getVipPageInfo() + + vipViewModel.loadingLiveData.observe(this) { + if (it == true) { + dialogManager.showProgressDialog(this) + } else { + dialogManager.dismissDialog() + } + } + + vipViewModel.authInfosLiveData.observe(this) { + // ArrayList[VipAuthInfo] // 全部特权列表 + it?.let { +// val filteredList = it.filter { authInfo -> +// authInfo.authType == 4 || authInfo.authType == 6 || authInfo.authType == 10 || authInfo.authType == 14 || authInfo.authType == 15 || authInfo.authType == 12 || authInfo.authType == 13 +// } + authInfoList = it + //xxx vip 奖励 配置 + authAdapter.setNewData(it) + //xxx vip 奖励 配置 + vipIdentificationsAdapter = VipCenterIdentificationsAdapter(this, it, this) + recyclerView.adapter = vipIdentificationsAdapter + } +// authAdapter.setNewData(it) +// it?.let { +// vipIdentificationsAdapter = VipCenterIdentificationsAdapter(this, it, this) +// recyclerView.adapter = vipIdentificationsAdapter +// } + } + + vipViewModel.pageLiveData.observe(this) { + it?.let { // 当前显示的 index + // TODO 处理轮播组件 index 更新 + currentIndex = it + } + } + + vipViewModel.vipInfosLiveData.observe(this) { + it?.let { // ArrayList[VipInfo] 每个等级的 VIP 内容 + // TODO 初始化轮播组件 + } + } + + vipViewModel.myVipInfoLiveData.observe(this) { + val adapter = vipViewModel.vipInfosLiveData.value?.let { it1 -> + VipCenterBannerAdapter(this, + it1, it) + } + banner.setAdapter(adapter, false) + it?.let { + + + if (it.ownAuthTypes?.contains(13) == true && mTitleBar.actionCount == 1) { + mTitleBar.addAction(object : TitleBar.ImageAction(R.drawable.ic_vip_setting) { + override fun performAction(view: View?) { + VipSettingActivity.start(this@VipCenterActivity) + } + }, 0) + } + } ?: run { +// binding.layoutLevelInfo.isVisible = false +// binding.layoutLevelProgress.isVisible = false + binding.slAuth.isVisible = true +// binding.tvNotOpen.text = getString(R.string.me_no_aristocracy_yet) + } + + banner?.postDelayed(object : Runnable { + override fun run() { + val intExtra = intent?.getIntExtra(BundleKeys.KEY_EXTRA_1, -1)?.minus(1) + val vipIndex = (it?.vipLevel ?: 0) - 1 + if (intExtra != null && intExtra > 0) { + banner.setCurrentItem(intExtra) + }else if (vipIndex > 0){ + banner.setCurrentItem(vipIndex) + } + } + }, 200) + + } + + vipViewModel.currVipInfoLiveData.observe(this) { + it?.let { // VipInfo + if (it.comingSoon == 2) { + /// 处理敬请期待情况, 补充显示 SVGA + binding.slAuth.isVisible = false +// binding.bannerView.isVisible = false + binding.layoutBottomPanel.isVisible = false + } else { + val myVipInfo = vipViewModel.myVipInfoLiveData.value + // TODO 根据当前显示的 VIP 信息更新 UI + //xxx vip 奖励 配置 + authAdapter.setVipInfo(it) + authAdapter.notifyDataSetChanged() + handleIdentificationAreaContent(it) + vipIdentificationsAdapter.setVipInfo(it) + refreshBottomArea() + } + + } ?: run { + getString(R.string.me_failed_to_get_aristocrat_data).toast() + } + } + + vipViewModel.openVipData.observe(this,object : Observer { + override fun onChanged(value: Boolean?) { + requestChargeList{ + vipViewModel.getVipPageInfo() + } + } + }) + + + } + + override fun onItemClick(position: Int) { + authAdapter.getItem(position)?.let { + VipAuthDetailsDialog.newInstance(it.descPic, it.authName, it.authIntro).show(this) + } + } + + private fun handleIdentificationAreaContent(vipInfo: VipInfo) { + val exclusivePrivilegesTitle = findViewById(R.id.center_title_2) + var count = 0 + authInfoList?.map { info -> + if (vipInfo?.ownAuthTypes?.contains(info.authType) == true) { + count ++ + } + } + + "${getString(R.string.vip_center_4)}\n(${count}/${authInfoList?.size})".also { + binding.centerTitle2.text = it + } +// exclusivePrivilegesTitle.text = R.string.vip_center_4.toString() + } + + @SuppressLint("CheckResult") + private fun requestChargeList(call: (List) -> Unit) { + PayModel.get().vipList + .compose(bindToLifecycle()) + .subscribe( + { + call.invoke(it) + }, { + it.printStackTrace() + } + ) + } + + private fun initObserve(){ + lifecycleScope.launch(Dispatchers.Main) { + vipViewModel.getVipRebateSuccessFlow.collect { + rebateAdapter.notifyItemRangeChanged(0, rebateAdapter.itemCount, true) + } + } + } + + private fun loadChargeList(list: List) { + this.chargeList = list + refreshBottomArea() + } + + private fun checkBuyVip(block: () -> Unit) { + val myVipInfo = vipViewModel.myVipInfoLiveData.value + val currentVipInfo = vipViewModel.vipInfosLiveData.value?.get(currentIndex) + if (currentVipInfo != null && + myVipInfo != null && + currentVipInfo.vipLevel > myVipInfo.vipLevel) { + val message = context.getString(R.string.vip_buy_tips).format( + myVipInfo.vipName,currentVipInfo.vipName + ) + dialogManager.showOkCancelDialog(message, + context.getString(R.string.miniworld_activity_mwteamroommessageact_07), + context.getString(R.string.miniworld_activity_mwteamroommessageact_08), + true + ) { block.invoke() } + } else { + block.invoke() + } + } + + private fun buyVip() { + val currentVipInfo = vipViewModel.vipInfosLiveData.value?.get(currentIndex) + currentVipInfo?.let { + val googleUnavailable = ((currentChargeInfo?.productDetails?.getOneTimePurchaseOfferDetails() + ?.getPriceAmountMicros() + ?: "0") == "0") + var text = + currentChargeInfo?.productDetails?.getOneTimePurchaseOfferDetails()?.getFormattedPrice() + if (text.isNullOrEmpty()) { + text = it.buyAmount.toString() + } + SelectPayTypeDialog.newInstance( + text, + !googleUnavailable, + it.buyAmount + ) + .apply { + setOnDiamondChargeClick { + vipViewModel.openVipWithDiamond( + currentChargeInfo?.getProdDesc()?.toIntOrNull() ?: -1 + ) + } + setOnGoogleChargeClick { + if (googleUnavailable) { + toast(getString(R.string.Recharge_failure)) + return@setOnGoogleChargeClick + } + currentChargeInfo?.let { charge -> + buyProduct(charge.productDetails) + } + } + setOnChargeClick { + ChargeActivity.start(this@VipCenterActivity) + } + } + .show(context) + } + } + + /*购买商品*/ + @SuppressLint("CheckResult") + fun buyProduct(productDetails: IProductDetails?) { + if (productDetails != null) { + Log.d(VipCenterActivity.TAG, "BuyProduct:" + productDetails.getProductId()) +// PayModel.get().placeOrder(productDetails.getProductId()) +// .compose(bindToLifecycle()) +// .subscribe( +// { recordId: PayRecordId -> +// billingManager?.initiatePurchaseFlow( +// productDetails, +// recordId.recordId +// ) +// } +// ) { throwable: Throwable -> +// SingleToastUtil.showToast( +// throwable.message +// ) +// } + } else { + Log.w(VipCenterActivity.TAG, "skuDetails ==null") + } + } + + private fun refreshBottomArea() { + val currentPageVipInfo = vipViewModel.vipInfosLiveData.value?.get(currentIndex) + currentPageVipInfo?.let { + currentChargeInfo = chargeList?.firstOrNull { + it.prodDesc?.toIntOrNull() == currentPageVipInfo.vipLevel + } + if (it.buyAmount == 0) { + binding.tvNoticeText.visibility = View.VISIBLE + binding.tvOpenVip.visibility = View.GONE + binding.layoutOpenVip.visibility = View.GONE + binding.tvIcon.visibility = View.GONE + + getString(R.string.vip_center_9).format( + currentPageVipInfo.vipLevel + ).also { binding.tvNoticeText.text = it } + } else { + var myVipIsHighLevel = false + val myVipInfo = vipViewModel.myVipInfoLiveData.value + myVipInfo?.let { + myVipIsHighLevel = myVipInfo.vipLevel >= currentPageVipInfo.vipLevel + } + + binding.tvNoticeText.visibility = View.GONE + binding.tvOpenVip.visibility = View.VISIBLE + binding.layoutOpenVip.visibility = View.VISIBLE + binding.tvIcon.visibility = View.VISIBLE + "${it.buyAmount} ${ + getString(R.string.vip_center_5).format( + " / 30" + ) + }".also { binding.tvOpenVip.text = it } + + + } + } + } + + private fun refreshOpenVipState() { + val currentVipInfo = vipViewModel.currVipInfoLiveData.value + val myVipInfo = vipViewModel.myVipInfoLiveData.value + if (currentVipInfo != null) { + currentChargeInfo = chargeList?.firstOrNull { + it.prodDesc?.toIntOrNull() == currentVipInfo.vipLevel + } + + if (currentChargeInfo != null){ + "${vipViewModel.myVipInfoLiveData.value?.buyAmount} ${ + getString(R.string.vip_center_5).format( + " / 30" + ) + }".also { binding.tvOpenVip.text = it } + } + + + } else { + currentChargeInfo = null +// binding.layoutOpenVip.isVisible = false + } +// if (binding.layoutOpenVip.isVisible && binding.layoutLevelProgress.isVisible) { +// binding.layoutBottomPanel.setBackgroundDrawable(binding.layoutLevelProgress.background) +// } else { +// binding.layoutBottomPanel.setBackgroundDrawable(null) +// } + } + + override fun onItemSelect(position: Int, view: TextView?) { + + } + + override fun onBillingClientSetupFinished() { + TODO("Not yet implemented") + } + + override fun onPurchasesUpdated(purchases: List) { + TODO("Not yet implemented") + } + + override fun onConsumeFinished(token: String?, result: Int) { + TODO("Not yet implemented") + } + + override fun onFailedHandle(result: Int) { + TODO("Not yet implemented") + } + + + override fun onDestroy() { + super.onDestroy() + EventBus.getDefault().unregister(this) + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/vip/VipSettingActivity.kt b/app/src/main/java/com/chwl/app/vip/VipSettingActivity.kt new file mode 100644 index 0000000..08ffc4e --- /dev/null +++ b/app/src/main/java/com/chwl/app/vip/VipSettingActivity.kt @@ -0,0 +1,70 @@ +package com.chwl.app.vip + +import android.annotation.SuppressLint +import android.content.Context +import android.content.Intent +import androidx.activity.viewModels +import com.netease.nim.uikit.StatusBarUtil +import com.chwl.app.R +import com.chwl.app.base.BaseViewBindingActivity +import com.chwl.app.databinding.ActivityVipSettingBinding +import com.chwl.core.user.UserModel +import com.chwl.library.utils.ResUtil + +class VipSettingActivity : BaseViewBindingActivity() { + + companion object { + + @JvmStatic + fun start(context: Context) { + val starter = Intent(context, VipSettingActivity::class.java) + context.startActivity(starter) + } + + } + + private val vipViewModel: VipViewModel by viewModels() + + @SuppressLint("SetTextI18n") + override fun init() { + initWhiteTitleBar(ResUtil.getString(R.string.erban_vip_vipsettingactivity_01)) + vipViewModel.loadingLiveData.observe(this) { + if (it == true) { + dialogManager.showProgressDialog(this) + } else { + dialogManager.dismissDialog() + } + } + + vipViewModel.enterHideLiveData.observe(this) { + binding.switchHideGoRoom.isOn = it == true + } + + binding.switchHideGoRoom.isOn = UserModel.get().cacheLoginUserInfo?.userVipInfoVO?.enterHide == true + + binding.switchHideGoRoom.setOnSwitchStateChangeListener { + vipViewModel.changeInvisibleInRoom(it) + } + + } + + override fun initWhiteTitleBar(title: String?) { + mTitleBar = findViewById(R.id.title_bar) + if (mTitleBar != null) { + mTitleBar.setTitle(title) + mTitleBar.setImmersive(false) + mTitleBar.setTitleColor(resources.getColor(R.color.white)) + mTitleBar.setLeftImageResource(R.drawable.arrow_left_white) + mTitleBar.setBackgroundResource(R.color.transparent) + mTitleBar.setLeftClickListener { onLeftClickListener() } + } + } + + override fun needSteepStateBar() = true + + override fun setStatusBar() { + super.setStatusBar() + StatusBarUtil.transparencyBar(this) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/vip/VipViewModel.kt b/app/src/main/java/com/chwl/app/vip/VipViewModel.kt new file mode 100644 index 0000000..f39882d --- /dev/null +++ b/app/src/main/java/com/chwl/app/vip/VipViewModel.kt @@ -0,0 +1,181 @@ +package com.chwl.app.vip + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import com.chwl.app.R +import com.chwl.app.base.BaseViewModel +import com.chwl.core.bean.response.BeanResult +import com.chwl.core.user.UserInfoUiMgr +import com.chwl.core.user.UserModel +import com.chwl.core.vip.bean.VipAuthInfo +import com.chwl.core.vip.bean.VipBroadcastInfo +import com.chwl.core.vip.bean.VipInfo +import com.chwl.core.utils.extension.toast +import com.chwl.core.vip.VipModel +import com.chwl.core.vip.bean.VipRebateInfo +import com.chwl.library.utils.ResUtil +import kotlinx.coroutines.flow.MutableSharedFlow + +class VipViewModel : BaseViewModel() { + val userId: Long by lazy { + UserInfoUiMgr.get().uid + } + + private val _authInfosLiveData = MutableLiveData?>() + val authInfosLiveData: LiveData?> = _authInfosLiveData + + private val _vipInfosLiveData = MutableLiveData?>() + val vipInfosLiveData: LiveData?> = _vipInfosLiveData + + private val _myVipInfoLiveData = MutableLiveData() + val myVipInfoLiveData: LiveData = _myVipInfoLiveData + + private val _currVipInfoLiveData = MutableLiveData() + val currVipInfoLiveData: LiveData = _currVipInfoLiveData + + private val _pageLiveData = MutableLiveData() + val pageLiveData: LiveData = _pageLiveData + + private val _saveOriginDisguiseResult = MutableLiveData() + val saveOriginDisguiseResult = _saveOriginDisguiseResult + + private val _sendBroadcastLiveData = MutableLiveData() + val sendBroadcastLiveData: LiveData = _sendBroadcastLiveData + + private val _vipBroadcastInfoLiveData = MutableLiveData>() + val vipBroadcastInfoLiveData: LiveData> = _vipBroadcastInfoLiveData + + private val _enterHideLiveData = MutableLiveData() + val enterHideLiveData: LiveData = _enterHideLiveData + + val getVipRebateSuccessFlow = MutableSharedFlow() + + val openVipData = MutableLiveData() + + +// private val _sendBroadcastLiveData = MutableLiveData() +// val sendBroadcastLiveData: LiveData = _sendBroadcastLiveData + + fun getVipPageInfo() { + safeLaunch( + true, + block = { + val vipPageInfo = VipModel.getVipPageInfo() + vipPageInfo?.let { + _authInfosLiveData.value = it.vipAuthInfos + _vipInfosLiveData.value = it.vipInfos + var position = 0 + _myVipInfoLiveData.value = it.vipInfos?.findLast { vipInfo -> + vipInfo.remainSeconds > 0 + }?.copy() + ?.apply { + position = it.vipInfos?.indexOf(this) ?: -1 + val nextVipInfo = it.vipInfos?.getOrNull(position + 1) + nextVipName = if (nextVipInfo?.vipName == vipName) null else nextVipInfo?.vipName +// remainSeconds = it.remainSeconds + currLevel = it.currLevel + currScore = it.currScore + isMaxLevel = it.isMaxLevel + } + onItemSelect(if (position < 0) 0 else position) + } + + } + ) + + } + + /** + * 获取用户家族和公会信息,不一定是自己的 + * 特别注意,这里的HallInfo里面是没有RoleType的 + */ +// fun getUserHallAndClan() { +// safeLaunch ( +// onError = { +// _homeLiveTopInfoLiveData.value = null +// }, +// block = { +// _homeLiveTopInfoLiveData.value = HallModel.get().getUserHallAndClan(userId) +// } +// ) +// } + + fun saveOriginDisguise() { + safeLaunch( + true, + onError = { + it.message.toast() + _saveOriginDisguiseResult.value = false + }, + block = { + VipModel.saveOriginDisguise() + _saveOriginDisguiseResult.value = true + //换回装扮刷新缓存数据 + UserModel.get().onlyUpdateLoginUserInfoCache() + } + ) + } + + fun getVipBroadcastInfo() { + safeLaunch( + true, + onError = { + _vipBroadcastInfoLiveData.value = BeanResult.failed(it) + }, + block = { + _vipBroadcastInfoLiveData.value = BeanResult.success(VipModel.getVipBroadcastInfo()) + } + ) + } + + fun sendVipBroadcast(content: String) { + safeLaunch( + true, + onError = { + it.message.toast() + _sendBroadcastLiveData.value = false + }, + block = { + VipModel.sendVipBroadcast(content) + _sendBroadcastLiveData.value = true + } + ) + } + + fun changeInvisibleInRoom(open: Boolean) { + safeLaunch( + true, + onError = { + it.message.toast() + _enterHideLiveData.value = !open + }, + block = { + VipModel.changeInvisibleInRoom(open) + _enterHideLiveData.value = open + UserModel.get().cacheLoginUserInfo?.userVipInfoVO?.enterHide = open + ResUtil.getString(R.string.erban_vip_vipviewmodel_01).toast() + } + ) + } + + fun onItemSelect(position: Int) { + _currVipInfoLiveData.value = vipInfosLiveData.value?.getOrNull(position) + _pageLiveData.value = position + } + + fun openVipWithDiamond(vipLevel: Int) { + safeLaunch(true) { + VipModel.openVipWithDiamond(vipLevel) + openVipData.postValue(true) + } + } + + fun getVipRebate(rebateInfo: VipRebateInfo) { + safeLaunch(true) { + VipModel.getVipRebate(rebateInfo.returnProfitRecordId ?: 0L) + rebateInfo.isReceive = true + getVipRebateSuccessFlow.emit(rebateInfo) + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/vip/adapter/PayAdapter.kt b/app/src/main/java/com/chwl/app/vip/adapter/PayAdapter.kt new file mode 100644 index 0000000..4c9fcf3 --- /dev/null +++ b/app/src/main/java/com/chwl/app/vip/adapter/PayAdapter.kt @@ -0,0 +1,20 @@ +package com.chwl.app.vip.adapter + +import android.widget.CheckBox +import android.widget.ImageView +import androidx.appcompat.widget.AppCompatTextView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.vip.bean.PayInfo + +class PayAdapter : + BaseQuickAdapter(R.layout.item_pay) { + + override fun convert(helper: BaseViewHolder, item: PayInfo) { + helper.getView(R.id.ivIcon).setImageResource(item.url) + helper.getView(R.id.tvPayType).text = item.name + helper.getView(R.id.cbPay).isChecked = item.isSelect + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/vip/adapter/VipAuthAdapter.kt b/app/src/main/java/com/chwl/app/vip/adapter/VipAuthAdapter.kt new file mode 100644 index 0000000..889cd36 --- /dev/null +++ b/app/src/main/java/com/chwl/app/vip/adapter/VipAuthAdapter.kt @@ -0,0 +1,26 @@ +package com.chwl.app.vip.adapter + +import android.widget.ImageView +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.app.ui.utils.load +import com.chwl.core.vip.bean.VipAuthInfo +import com.chwl.core.vip.bean.VipInfo + +class VipAuthAdapter : + BaseQuickAdapter(R.layout.item_vip_auth) { + + + private var vipInfo: VipInfo? = null + + fun setVipInfo(vipInfo: VipInfo?) { + this.vipInfo = vipInfo + } + + override fun convert(helper: BaseViewHolder, item: VipAuthInfo) { + helper.setText(R.id.tv_auth_name, item.authName) + helper.getView(R.id.iv_auth_icon).load(item.authIcon) + helper.itemView.alpha = if (vipInfo?.ownAuthTypes?.contains(item.authType) == true) 1f else 0.5f + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/vip/adapter/VipCenterBannerAdapter.kt b/app/src/main/java/com/chwl/app/vip/adapter/VipCenterBannerAdapter.kt new file mode 100644 index 0000000..ff2f516 --- /dev/null +++ b/app/src/main/java/com/chwl/app/vip/adapter/VipCenterBannerAdapter.kt @@ -0,0 +1,187 @@ +package com.chwl.app.vip.adapter +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.load.DataSource +import com.bumptech.glide.load.engine.GlideException +import com.bumptech.glide.request.RequestListener +import com.bumptech.glide.request.target.Target +import com.chwl.app.R +import com.chwl.core.vip.bean.VipInfo +import com.chwl.library.common.glide.GlideUtils +import com.chwl.library.utils.ResUtil.getString +import com.tencent.qgame.animplayer.AnimConfig +import com.tencent.qgame.animplayer.AnimView +import com.tencent.qgame.animplayer.inter.IAnimListener +import com.tencent.qgame.animplayer.util.ScaleType +import com.youth.banner.adapter.BannerAdapter +import java.io.File +import java.text.DateFormat +import java.text.SimpleDateFormat +import java.util.Calendar +import java.util.Date +import java.util.Locale + +class VipCenterBannerAdapter( + private val context: Context, + private val vipInfos: List, + private val myVipInfo: VipInfo? +) : BannerAdapter(vipInfos) { + + private val DOWNLOAD_TAG = "gift_effect_download" + + override fun onCreateHolder(parent: ViewGroup, viewType: Int): BannerViewHolder { + val view = LayoutInflater.from(context).inflate( + R.layout.banner_vip_center_custom, + parent, + false) + return BannerViewHolder(view) + } + + override fun onBindView(holder: BannerViewHolder, data: VipInfo, position: Int, size: Int) { + holder.dueText.visibility = View.GONE + + if (myVipInfo != null) { + myVipInfo.let { + if (it.vipLevel >= data.vipLevel) { + var result = getString(R.string.vip_center_8) + if (data.remainSeconds>0){ + val calendar = Calendar.getInstance() + calendar.add(Calendar.SECOND, data.remainSeconds) + val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH) + val formattedDate = dateFormat.format(calendar.time) + result = "${getString(R.string.vip_center_2)}$formattedDate" + } + holder.dueText.text = result + holder.dueText.visibility = View.VISIBLE + } else if (it.vipLevel < data.vipLevel) { + holder.dueText.text = getString(R.string.vip_center_8) + holder.dueText.visibility = View.VISIBLE + } else { + holder.dueText.visibility = View.GONE + } + } + }else{ + holder.dueText.text = getString(R.string.vip_center_8) + holder.dueText.visibility = View.VISIBLE + } + + + when(position) { + 0-> { + holder.dueText.setTextColor(context.resources.getColor(R.color.color_3A4D14)) + holder.imgBackground.setImageResource(R.drawable.vip_center_level_1) + } + 1-> { + holder.dueText.setTextColor(context.resources.getColor(R.color.color_4D143A)) + holder.imgBackground.setImageResource(R.drawable.vip_center_level_2) + } + 2-> { + holder.dueText.setTextColor(context.resources.getColor(R.color.color_4D2C14)) + holder.imgBackground.setImageResource(R.drawable.vip_center_level_3) + } + 3-> { + holder.dueText.setTextColor(context.resources.getColor(R.color.color_44144D)) + holder.imgBackground.setImageResource(R.drawable.vip_center_level_4) + } + 4-> { + holder.dueText.setTextColor(context.resources.getColor(R.color.color_1C344D)) + holder.imgBackground.setImageResource(R.drawable.vip_center_level_5) + } + 5-> { + holder.dueText.setTextColor(context.resources.getColor(R.color.color_1C4D35)) + holder.imgBackground.setImageResource(R.drawable.vip_center_level_6) + } + 6-> { + holder.dueText.setTextColor(context.resources.getColor(R.color.color_44144D)) + holder.imgBackground.setImageResource(R.drawable.vip_center_level_7) + } + 7-> { + holder.dueText.setTextColor(context.resources.getColor(R.color.color_4D371C)) + holder.imgBackground.setImageResource(R.drawable.vip_center_level_8) + } + 8-> { + holder.dueText.setTextColor(context.resources.getColor(R.color.color_4D1C1C)) + holder.imgBackground.setImageResource(R.drawable.vip_center_level_9) + } + } + + holder.vapAnimView.setScaleType(ScaleType.FIT_XY) + holder.vapAnimView.setLoop(Int.MAX_VALUE) + holder.vapAnimView.setAnimListener(object : IAnimListener { + override fun onFailed(errorType: Int, errorMsg: String?) { + println(errorMsg) + } + + override fun onVideoComplete() { + println("complete") + } + + override fun onVideoDestroy() { + println("destory") + } + + override fun onVideoRender(frameIndex: Int, config: AnimConfig?) { + println("rendering") + } + + override fun onVideoStart() { + println("start") + } + + }) + + GlideUtils.instance().downloadFromUrl2(holder.vapAnimView.context,data.vipLogo.trim(),object : RequestListener { + override fun onLoadFailed( + e: GlideException?, + model: Any?, + target: Target?, + isFirstResource: Boolean + ): Boolean { + return true + } + + override fun onResourceReady( + resource: File?, + model: Any?, + target: Target?, + dataSource: DataSource?, + isFirstResource: Boolean + ): Boolean { + if (resource != null) { + holder.vapAnimView.startPlay(resource) + } + return true + } + }) + +// val filePath = generateResourcesFilePath(data.vipLogo) +// val request = build(data.vipLogo, filePath, DOWNLOAD_TAG, null, 60000L) +// download(request, object : FileDownloadListener() { +// override fun onDownloadCompleted(task: DownloadTask) { +// val path = task.getRequest().getPath() +// holder.vapAnimView.startPlay(File(path)) +// } +// +// override fun onDownloadError(exception: DownloadException) { +// exception.printStackTrace() +// } +// }) + } + + inner class BannerViewHolder(view: View) : RecyclerView.ViewHolder(view) { + val imgBackground: ImageView = view.findViewById(R.id.img_background) +// val svgaImage: SVGAImageView = view.findViewById(R.id.iv_vip_icon) + val vapAnimView: AnimView = view.findViewById(R.id.vap_anim_view) + val dueText: TextView = view.findViewById(R.id.due_date_textview) + } + + fun millis2String(millis: Long, format: DateFormat): String { + return format.format(Date(millis)) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/vip/adapter/VipCenterIdentificationsAdapter.kt b/app/src/main/java/com/chwl/app/vip/adapter/VipCenterIdentificationsAdapter.kt new file mode 100644 index 0000000..9a4de86 --- /dev/null +++ b/app/src/main/java/com/chwl/app/vip/adapter/VipCenterIdentificationsAdapter.kt @@ -0,0 +1,278 @@ +package com.chwl.app.vip.adapter +import android.annotation.SuppressLint +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import com.chwl.app.R +import com.chwl.core.vip.bean.VipAuthInfo +import com.chwl.core.vip.bean.VipInfo + +interface OnItemClickListener { + fun onItemClick(position: Int) +} + +class VipCenterIdentificationsAdapter( + private val context: Context, + private val items: List, + private val listener: OnItemClickListener +) : RecyclerView.Adapter() { + + private var vipInfo: VipInfo? = null + + override fun onCreateViewHolder( + parent: ViewGroup, + viewType: Int + ): VipCenterIdentificationsAdapter.ItemViewHolder { + val view = LayoutInflater.from(context).inflate(R.layout.vip_center_idnetifications_layout, parent, false) + return ItemViewHolder(view) + } + + override fun onBindViewHolder( + holder: VipCenterIdentificationsAdapter.ItemViewHolder, + position: Int + ) { + // 1.铭牌 5.用户卡片 8.麦位光圈 11.聊天气泡 12 进厂特效 2.头饰 +// val filteredList = items.filter { +// it.authType == 1 || it.authType == 2 || it.authType == 5 || it.authType == 8 || it.authType == 11 || it.authType == 12 +// } + val filteredList = items.filter { + getVipFilter(vipInfo?.vipLevel?:1,it.authType) + } + + val sortedBy = filteredList.sortedBy { it.seq } + val item = sortedBy.getOrNull(position)?:sortedBy[0] + vipInfo?.let { + setView(holder,item.authName,item.authType,it.vipLevel) + } + val screenWidth = context.resources.displayMetrics.widthPixels + val itemWidth = (screenWidth * 160)/375 + val layoutParams = holder.itemView.layoutParams + layoutParams.width = itemWidth + holder.itemView.layoutParams = layoutParams + } + + private fun getVipFilter(level: Int, authType: Int) : Boolean{ + // 1.铭牌 2.头饰 5.用户卡片 8.麦位光圈 11.聊天气泡 12 进厂特效 + return when (level) { + 1 -> authType == 1 || authType == 2 + 2 -> authType == 1 || authType == 2 || authType == 5 + 3 -> authType == 1 || authType == 2 || authType == 5 || authType == 8 + 4 -> authType == 1 || authType == 2 || authType == 5 || authType == 8 || authType == 11 + 5 -> authType == 1 || authType == 2 || authType == 5 || authType == 8 || authType == 11 || authType == 12 + 6 -> authType == 1 || authType == 2 || authType == 5 || authType == 8 || authType == 11 || authType == 12 + 7 -> authType == 1 || authType == 2 || authType == 5 || authType == 8 || authType == 11 || authType == 12 + 8 -> authType == 1 || authType == 2 || authType == 5 || authType == 8 || authType == 11 || authType == 12 + 9 -> authType == 1 || authType == 2 || authType == 5 || authType == 8 || authType == 11 || authType == 12 + else -> false + } + } + + private fun setView(holder: VipCenterIdentificationsAdapter.ItemViewHolder,authName:String,authType:Int ,vipLevel: Int) { + // 1.铭牌 5.用户卡片 8.麦位光圈 11.聊天气泡 12 进厂特效 2.头饰 + holder.titleTextView.text = authName + + when (authType) { + //铭牌 + 1 -> { + when (vipLevel) { + 1 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_vipidentity_lv1) + 2 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_vipidentity_lv2) + 3 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_vipidentity_lv3) + 4 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_vipidentity_lv4) + 5 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_vipidentity_lv5) + 6 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_vipidentity_lv6) + 7 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_vipidentity_lv7) + 8 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_vipidentity_lv8) + 9 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_vipidentity_lv9) + } + } + //2.头饰 + 2 -> { + when (vipLevel) { + 1 -> holder.contentImageView.setImageResource(R.drawable.icon_vip_head_lv_1) + 2 -> holder.contentImageView.setImageResource(R.drawable.icon_vip_head_lv_2) + 3 -> holder.contentImageView.setImageResource(R.drawable.icon_vip_head_lv_3) + 4 -> holder.contentImageView.setImageResource(R.drawable.icon_vip_head_lv_4) + 5 -> holder.contentImageView.setImageResource(R.drawable.icon_vip_head_lv_5) + 6 -> holder.contentImageView.setImageResource(R.drawable.icon_vip_head_lv_6) + 7 -> holder.contentImageView.setImageResource(R.drawable.icon_vip_head_lv_7) + 8 -> holder.contentImageView.setImageResource(R.drawable.icon_vip_head_lv_8) + 9 -> holder.contentImageView.setImageResource(R.drawable.icon_vip_head_lv_9) + } + } + //5.用户卡片 + 5 -> { + when (vipLevel) { + 1 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_roomcard_lv1) + 2 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_roomcard_lv2) + 3 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_roomcard_lv3) + 4 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_roomcard_lv4) + 5 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_roomcard_lv5) + 6 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_roomcard_lv6) + 7 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_roomcard_lv7) + 8 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_roomcard_lv8) + 9 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_roomcard_lv9) + } + } + //8.麦位光圈 + 8 -> { + when (vipLevel) { +// 1 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_mic_lv1) +// 2 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_mic_lv2) + 3 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_mic_lv3) + 4 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_mic_lv4) + 5 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_mic_lv5) + 6 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_mic_lv6) + 7 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_mic_lv7) + 8 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_mic_lv8) + 9 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_mic_lv9) + } + } + // 11.聊天气泡 + 11 -> { + when (vipLevel) { +// 1 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_bubble_lv1) +// 2 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_bubble_lv2) +// 3 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_bubble_lv3) + 4 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_bubble_lv4) + 5 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_bubble_lv5) + 6 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_bubble_lv6) + 7 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_bubble_lv7) + 8 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_bubble_lv8) + 9 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_bubble_lv9) + } + } + //12 进厂特效 + 12 -> { + when (vipLevel) { +// 1 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_entry_lv1) +// 2 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_entry_lv2) +// 3 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_entry_lv3) + 4 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_entry_lv4) + 5 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_entry_lv5) + 6 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_entry_lv6) + 7 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_entry_lv7) + 8 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_entry_lv8) + 9 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_entry_lv9) + } + } + + } + } + + + override fun getItemCount(): Int { + return vipInfo?.let { + when (it.vipLevel) { + 1 -> 2 + 2 -> 3 + 3 -> 4 + 4 -> 5 + else -> 6 + } + } ?: 0 // items.size + } + + @SuppressLint("NotifyDataSetChanged") + fun setVipInfo(vipInfo: VipInfo?) { + this.vipInfo = vipInfo + this.notifyDataSetChanged() + } + + inner class ItemViewHolder(view: View) : RecyclerView.ViewHolder(view) { + val contentImageView: ImageView = view.findViewById(R.id.item_image) + val titleTextView: TextView = view.findViewById(R.id.item_title) + } + + + //when (authType) { + // //铭牌 + // 1 -> { + // when (vipLevel) { + // 1 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_vipidentity_lv1) + // 2 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_vipidentity_lv2) + // 3 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_vipidentity_lv3) + // 4 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_vipidentity_lv4) + // 5 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_vipidentity_lv5) + // 6 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_vipidentity_lv6) + // 7 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_vipidentity_lv7) + // 8 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_vipidentity_lv8) + // 9 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_vipidentity_lv9) + // } + //// resourceName = "vip_center_identification_vipidentity_lv$lv" + // } + // //资料卡片 + // 1 -> { + //// resourceName = "vip_center_identification_roomcard_lv$lv" + // when (vipLevel) { + // 1 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_roomcard_lv1) + // 2 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_roomcard_lv2) + // 3 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_roomcard_lv3) + // 4 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_roomcard_lv4) + // 5 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_roomcard_lv5) + // 6 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_roomcard_lv6) + // 7 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_roomcard_lv7) + // 8 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_roomcard_lv8) + // 9 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_roomcard_lv9) + // } + // } + // //头饰 ,4以上是 进厂特效 + // 2 -> { + //// resourceName = "vip_center_identification_mic_lv$lv" + // when (vipLevel) { + // 1 -> holder.contentImageView.setImageResource(R.drawable.icon_vip_head_lv_1) + // 2 -> holder.contentImageView.setImageResource(R.drawable.icon_vip_head_lv_2) + // 3 -> holder.contentImageView.setImageResource(R.drawable.icon_vip_head_lv_3) + // 4 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_entry_lv4) + // 5 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_entry_lv5) + // 6 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_entry_lv6) + // 7 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_entry_lv7) + // 8 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_entry_lv8) + // 9 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_entry_lv9) + // } + // } + // //3是麦位光圈 ,4以上是 头饰 + // 3 -> { + //// resourceName = "vip_center_identification_bubble_lv$lv" + // when (vipLevel) { + // 3 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_mic_lv3) + // 4 -> holder.contentImageView.setImageResource(R.drawable.icon_vip_head_lv_4) + // 5 -> holder.contentImageView.setImageResource(R.drawable.icon_vip_head_lv_5) + // 6 -> holder.contentImageView.setImageResource(R.drawable.icon_vip_head_lv_6) + // 7 -> holder.contentImageView.setImageResource(R.drawable.icon_vip_head_lv_7) + // 8 -> holder.contentImageView.setImageResource(R.drawable.icon_vip_head_lv_8) + // 9 -> holder.contentImageView.setImageResource(R.drawable.icon_vip_head_lv_9) + // } + // } + // // 4以上的麦位光圈 + // 4 -> { + //// resourceName = "vip_center_identification_entry_lv$lv" + // when (vipLevel) { + // 4 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_mic_lv4) + // 5 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_mic_lv5) + // 6 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_mic_lv6) + // 7 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_mic_lv7) + // 8 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_mic_lv8) + // 9 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_mic_lv9) + // } + // } + // //4以上的气泡 + // 5 -> { + //// resourceName = "vip_center_identification_entry_lv$lv" + // when (vipLevel) { + // 4 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_bubble_lv4) + // 5 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_bubble_lv5) + // 6 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_bubble_lv6) + // 7 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_bubble_lv7) + // 8 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_bubble_lv8) + // 9 -> holder.contentImageView.setImageResource(R.drawable.vip_center_identification_bubble_lv9) + // } + // } + // + // } +} + diff --git a/app/src/main/java/com/chwl/app/vip/adapter/VipMagicIndicatorAdapter.java b/app/src/main/java/com/chwl/app/vip/adapter/VipMagicIndicatorAdapter.java new file mode 100644 index 0000000..eafe9f6 --- /dev/null +++ b/app/src/main/java/com/chwl/app/vip/adapter/VipMagicIndicatorAdapter.java @@ -0,0 +1,99 @@ +package com.chwl.app.vip.adapter; + +import android.content.Context; +import android.graphics.Color; +import android.view.Gravity; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.TextView; + +import com.chwl.app.ui.widget.XRecyclerView.ScaleTransitionPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.UIUtil; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.CommonNavigatorAdapter; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerIndicator; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerTitleView; +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.indicators.LinePagerIndicator; +import com.chwl.app.vip.view.VipTabView; +import com.chwl.core.vip.bean.VipInfo; + +import java.util.List; + +public class VipMagicIndicatorAdapter extends CommonNavigatorAdapter { + private final Context mContext; + private final List mTitleList; + + private int textSize = 15; + private float minScale = 1f; + private boolean showIndicator = true; + private OnItemSelectListener mOnItemSelectListener; + + public VipMagicIndicatorAdapter(Context context, List charSequences) { + this.mContext = context; + this.mTitleList = charSequences; + } + + @Override + public int getCount() { + return mTitleList == null ? 0 : mTitleList.size(); + } + + @Override + public IPagerTitleView getTitleView(Context context, final int i) { + VipTabView tabView = new VipTabView(context); + VipInfo item = mTitleList.get(i); + tabView.setData(item.getVipName(), item.isRebate()); + tabView.setOnClickListener(view -> { + if (mOnItemSelectListener != null) { + mOnItemSelectListener.onItemSelect(i, tabView.getTextView()); + } + }); + return tabView; + } + + @Override + public IPagerIndicator getIndicator(Context context) { + if (!showIndicator) return null; + LinePagerIndicator indicator = new LinePagerIndicator(context); + indicator.setMode(LinePagerIndicator.MODE_EXACTLY); + indicator.setLineHeight(UIUtil.dip2px(mContext, 3)); + indicator.setRoundRadius(UIUtil.dip2px(mContext, 10)); + indicator.setLineWidth(UIUtil.dip2px(mContext, 26)); + indicator.setColors(Color.parseColor("#FFFFD3A8")); + FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + lp.bottomMargin = UIUtil.dip2px(mContext, 0); + indicator.setLayoutParams(lp); + return indicator; + } + + public int getTextSize() { + return textSize; + } + + public void setTextSize(int textSize) { + this.textSize = textSize; + } + + public float getMinScale() { + return minScale; + } + + public void setMinScale(float minScale) { + this.minScale = minScale; + } + + public boolean isShowIndicator() { + return showIndicator; + } + + public void setShowIndicator(boolean showIndicator) { + this.showIndicator = showIndicator; + } + + public void setOnItemSelectListener(OnItemSelectListener onItemSelectListener) { + mOnItemSelectListener = onItemSelectListener; + } + + public interface OnItemSelectListener { + void onItemSelect(int position, TextView view); + } +} diff --git a/app/src/main/java/com/chwl/app/vip/adapter/VipRebateAdapter.kt b/app/src/main/java/com/chwl/app/vip/adapter/VipRebateAdapter.kt new file mode 100644 index 0000000..47adb01 --- /dev/null +++ b/app/src/main/java/com/chwl/app/vip/adapter/VipRebateAdapter.kt @@ -0,0 +1,68 @@ +package com.chwl.app.vip.adapter + +import android.view.View +import android.widget.TextView +import androidx.core.view.isVisible +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.BaseViewHolder +import com.chwl.app.R +import com.chwl.core.vip.bean.VipRebateInfo +import com.example.lib_utils.ktx.getColorById + +/** + * Created by Max on 2024/3/28 11:19 + * Desc: + **/ +class VipRebateAdapter : BaseQuickAdapter(R.layout.item_vip_rebate) { + + var onGetListener: ((VipRebateInfo) -> Unit)? = null + + override fun convertPayloads( + helper: BaseViewHolder, + item: VipRebateInfo, + payloads: MutableList + ) { + super.convertPayloads(helper, item, payloads) + convertStatus(helper, item) + } + + override fun convert(helper: BaseViewHolder, item: VipRebateInfo) { + if (item.profitDate == 0L) { + helper.setText( + R.id.tv_date, R.string.vip_rebate_now + ) + } else { + helper.setText( + R.id.tv_date, + helper.itemView.context.getString(R.string.vip_rebate_day_format) + .format("${item.profitDate}") + ) + } + helper.setText(R.id.tv_num, "${item.profitAmount}") + convertStatus(helper, item) + helper.getView(R.id.v_line).isVisible = + (helper.absoluteAdapterPosition != itemCount - 1) + } + + private fun convertStatus(helper: BaseViewHolder, item: VipRebateInfo) { + val statusView = helper.getView(R.id.tv_status) + val statusLayout = helper.getView(R.id.layout_status) + statusLayout.setOnClickListener(null) + if (item.isReceive == true) { + statusView.setBackgroundResource(R.drawable.shape_47ffffff_9dp) + statusView.setTextColor(statusView.context.getColorById(R.color.color_B3B3C3)) + statusView.setText(R.string.vip_rebate_received) + } else if (item.isReach == true) { + statusView.setBackgroundResource(R.drawable.shape_f6ad3f_9dp) + statusView.setTextColor(statusView.context.getColorById(R.color.color_white)) + statusView.setText(R.string.vip_rebate_get) + statusLayout.setOnClickListener { + onGetListener?.invoke(item) + } + } else { + statusView.setBackgroundResource(R.drawable.shape_726041_9dp) + statusView.setTextColor(statusView.context.getColorById(R.color.color_white)) + statusView.setText(R.string.vip_rebate_no_get) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/vip/bean/PayInfo.kt b/app/src/main/java/com/chwl/app/vip/bean/PayInfo.kt new file mode 100644 index 0000000..7884901 --- /dev/null +++ b/app/src/main/java/com/chwl/app/vip/bean/PayInfo.kt @@ -0,0 +1,8 @@ +package com.chwl.app.vip.bean + +data class PayInfo( + val url: Int = 0, + val name: String = "", + val diamondNum: Int = 0, + var isSelect: Boolean = false +) \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/vip/dialog/PaymentDialog.kt b/app/src/main/java/com/chwl/app/vip/dialog/PaymentDialog.kt new file mode 100644 index 0000000..1a7bcc3 --- /dev/null +++ b/app/src/main/java/com/chwl/app/vip/dialog/PaymentDialog.kt @@ -0,0 +1,76 @@ +package com.chwl.app.vip.dialog + +import android.annotation.SuppressLint +import android.view.Gravity +import android.view.WindowManager +import androidx.recyclerview.widget.LinearLayoutManager +import com.chwl.app.R +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.databinding.DialogPaymentBinding +import com.chwl.app.ui.utils.RVDelegate +import com.chwl.app.vip.adapter.PayAdapter +import com.chwl.app.vip.bean.PayInfo +import com.chwl.library.utils.ResUtil + +/** + * 支付选择弹窗 + */ +class PaymentDialog : BaseDialogFragment() { + + private lateinit var rvDelegate: RVDelegate + + private val payAdapter by lazy { PayAdapter() } + + private val payList = listOf( + PayInfo( + url = R.drawable.ic_diamond, + name = ResUtil.getString(R.string.diamond_pay), + isSelect = true + ), + PayInfo( + url = R.drawable.ic_google, + name = ResUtil.getString(R.string.google_pay), + isSelect = false + ), + PayInfo( + url = R.drawable.ic_payermax, + name = ResUtil.getString(R.string.payermax_pay), + isSelect = false + ) + ) + + private var selectIndex = -1 + + override var width = WindowManager.LayoutParams.MATCH_PARENT + override var gravity = Gravity.BOTTOM + + @SuppressLint("CheckResult") + override fun init() { + rvDelegate = RVDelegate.Builder() + .setAdapter(payAdapter) + .setRecyclerView(binding?.mRecyclerView) + .setLayoutManager(LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)) + .build() + + payAdapter.setNewData(payList) + + payAdapter.setOnItemClickListener { _, _, position -> + if (selectIndex != -1) { + payAdapter.data.getOrNull(selectIndex)?.isSelect = false + payAdapter.notifyItemChanged(selectIndex) + } else if (position != 0) { + payAdapter.data.getOrNull(0)?.isSelect = false + payAdapter.notifyItemChanged(0) + } + selectIndex = position + payAdapter.data.getOrNull(selectIndex)?.isSelect = true + payAdapter.notifyItemChanged(selectIndex) + } + + binding?.tvConfirmPay?.setOnClickListener { + + } + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/vip/dialog/SelectPayTypeDialog.kt b/app/src/main/java/com/chwl/app/vip/dialog/SelectPayTypeDialog.kt new file mode 100644 index 0000000..df0d425 --- /dev/null +++ b/app/src/main/java/com/chwl/app/vip/dialog/SelectPayTypeDialog.kt @@ -0,0 +1,181 @@ +package com.chwl.app.vip.dialog + +import android.annotation.SuppressLint +import android.content.res.ColorStateList +import android.os.Bundle +import android.text.style.TextAppearanceSpan +import android.view.Gravity +import android.view.View +import android.view.WindowManager +import androidx.core.graphics.toColorInt +import com.netease.nim.uikit.common.util.sys.ScreenUtil +import com.chwl.app.R +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.databinding.DialogSelectPayTypeBinding +import com.chwl.app.ui.widget.dialog.CommonTipDialog +import com.chwl.app.utils.SpannableBuilder +import com.chwl.core.pay.PayModel +import com.chwl.core.pay.bean.WalletInfo +import com.chwl.core.utils.CoreLogger +import com.chwl.library.utils.FormatUtils +import com.chwl.library.utils.ResUtil +import com.chwl.library.utils.SingleToastUtil + +/** + * 充值方式选择弹窗 + */ +class SelectPayTypeDialog : BaseDialogFragment() { + + private val descText by lazy { requireArguments().getString("descText", "") } + private val coins by lazy { requireArguments().getLong("coins", 0) } + private val showGoogleCharge by lazy { + requireArguments().getBoolean( + "showGoogleCharge", + false + ) + } + + private var onDiamondChargeClick: (() -> Unit)? = null + + private var onGoogleChargeClick: (() -> Unit)? = null + + private var onChargeClick: (() -> Unit)? = null + + private var walletInfo: WalletInfo? = null + + companion object { + /** + * @param money 真实货币(目前比例1:1000) + */ + @JvmStatic + fun newInstance( + descText: String, + showGoogleCharge: Boolean = false, + money: Int = 0 + ): SelectPayTypeDialog { + return newInstance(descText, money.toLong(), showGoogleCharge) + } + + + /** + * @param coins 虚拟货币:金币 + */ + @JvmStatic + fun newInstance( + descText: String, + coins: Long, + showGoogleCharge: Boolean = false, + ): SelectPayTypeDialog { + return SelectPayTypeDialog().apply { + arguments = Bundle().apply { + putString("descText", descText) + putBoolean("showGoogleCharge", showGoogleCharge) + putLong("coins", coins) + } + } + } + } + + fun setOnDiamondChargeClick(onDiamondChargeClick: (() -> Unit)) { + this.onDiamondChargeClick = onDiamondChargeClick + } + + fun setOnGoogleChargeClick(onGoogleChargeClick: (() -> Unit)) { + this.onGoogleChargeClick = onGoogleChargeClick + } + + fun setOnChargeClick(onChargeClick: (() -> Unit)) { + this.onChargeClick = onChargeClick + } + + override fun onStart() { + width = WindowManager.LayoutParams.MATCH_PARENT + gravity = Gravity.BOTTOM + super.onStart() + } + + @SuppressLint("CheckResult") + override fun init() { + PayModel.get().walletInfo + .compose(bindToLifecycle()) + .subscribe({ + setWalletData(it) + }, { + SingleToastUtil.showToast(it.message) + it.printStackTrace() + }) + + binding?.tvConfirmPay?.setOnClickListener { + if (binding?.rbDiamond?.isChecked == true) { + if (binding?.tvDiamondNum?.text.toString().toInt() > (walletInfo?.diamondNum ?: 0.0).toInt() + ) { + val tipDialog = CommonTipDialog(context) + tipDialog.setTipMsg(ResUtil.getString(R.string.Diamond_balance_is_insufficient)) + tipDialog.setOkText(getString(R.string.charge)) + tipDialog.setOnActionListener( + object : CommonTipDialog.OnActionListener { + override fun onOk() { + onChargeClick?.invoke() + } + } + ) + tipDialog.show() + } else { + onDiamondChargeClick?.invoke() + } + } else { + onGoogleChargeClick?.invoke() + } + dismissAllowingStateLoss() + } + + if (showGoogleCharge) { + binding?.rbGoogle?.visibility = View.VISIBLE + binding?.rg?.setOnCheckedChangeListener { _, _ -> + if (binding?.rbDiamond?.isChecked == true) { + binding?.tvDiamondNum?.text = coins.toString() + binding?.tvDiamond?.visibility = View.VISIBLE + } else { + binding?.tvDiamondNum?.text = descText + binding?.tvDiamond?.visibility = View.GONE + } + } + } else { + binding?.rbGoogle?.visibility = View.GONE + binding?.tvDiamondNum?.text = descText + } + } + + /** + * defaultPay 1:默认支付宝,2:默认微信 + */ + private fun setWalletData(walletInfo: WalletInfo) { + CoreLogger.info("dshsad", walletInfo.toString()) + this.walletInfo = walletInfo + val states = arrayOf(intArrayOf(android.R.attr.state_enabled)) + val colors = intArrayOf("#8A8CAB".toColorInt()) + binding?.rbDiamond?.text = SpannableBuilder() + .append(ResUtil.getString(R.string.diamond_payment)) + .append( + "(${FormatUtils.formatBigInteger(walletInfo.diamondNum)}${ResUtil.getString(R.string.gift_income_gold)})", + TextAppearanceSpan( + null, + 0, + ScreenUtil.sp2px(10f), + ColorStateList(states, colors), + null + ) + ) + .build() + var defaultDiamond = coins <= walletInfo.diamondNum + if (showGoogleCharge) { + binding?.rbGoogle?.visibility = View.VISIBLE + binding?.rbGoogle?.isChecked = !defaultDiamond + } else { + binding?.rbGoogle?.visibility = View.GONE + defaultDiamond = true + } + binding?.rbDiamond?.isChecked = defaultDiamond + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/vip/dialog/VipAuthDetailsDialog.kt b/app/src/main/java/com/chwl/app/vip/dialog/VipAuthDetailsDialog.kt new file mode 100644 index 0000000..e0f7255 --- /dev/null +++ b/app/src/main/java/com/chwl/app/vip/dialog/VipAuthDetailsDialog.kt @@ -0,0 +1,29 @@ +package com.chwl.app.vip.dialog + +import android.os.Bundle +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.databinding.DialogVipAuthDetailsBinding +import com.chwl.app.ui.utils.load + +class VipAuthDetailsDialog : BaseDialogFragment() { + + companion object { + @JvmStatic + fun newInstance(icon: String, name: String, desc: String): VipAuthDetailsDialog { + val args = Bundle() + args.putString("icon", icon) + args.putString("name", name) + args.putString("desc", desc) + val fragment = VipAuthDetailsDialog() + fragment.arguments = args + return fragment + } + } + + override fun init() { + binding?.ivClose?.setOnClickListener { dismissAllowingStateLoss() } + binding?.ivAuthIcon?.load(requireArguments().getString("icon", "")) + binding?.tvAuthDesc?.text = requireArguments().getString("desc", "") + binding?.tvAuthName?.text = requireArguments().getString("name", "") + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/vip/dialog/VipBroadcastDialog.kt b/app/src/main/java/com/chwl/app/vip/dialog/VipBroadcastDialog.kt new file mode 100644 index 0000000..0e9a7c8 --- /dev/null +++ b/app/src/main/java/com/chwl/app/vip/dialog/VipBroadcastDialog.kt @@ -0,0 +1,94 @@ +package com.chwl.app.vip.dialog + +import android.annotation.SuppressLint +import android.os.Bundle +import androidx.core.view.isVisible +import androidx.fragment.app.viewModels +import com.chwl.app.R +import com.chwl.app.base.BaseActivity +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.databinding.DialogVipBroadcastBinding +import com.chwl.app.vip.VipViewModel +import com.chwl.core.utils.CurrentTimeUtils +import com.chwl.core.utils.extension.toast +import com.chwl.library.utils.ResUtil +import com.example.lib_utils.ktx.getString +import io.reactivex.Observable +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import java.util.concurrent.TimeUnit + +class VipBroadcastDialog : BaseDialogFragment() { + + companion object { + @JvmStatic + fun newInstance(): VipBroadcastDialog { + val args = Bundle() + val fragment = VipBroadcastDialog() + fragment.arguments = args + return fragment + } + } + + private val viewModel: VipViewModel by viewModels() + private var disposable: Disposable? = null + + @SuppressLint("SetTextI18n") + override fun init() { + binding?.ivClose?.setOnClickListener { dismissAllowingStateLoss() } + binding?.ivSend?.setOnClickListener { + if (binding?.editContent?.text.isNullOrBlank()) { + ResUtil.getString(R.string.erban_vip_vipbroadcastdialog_01).toast() + } else { + viewModel.sendVipBroadcast(binding?.editContent?.text.toString()) + } + } + + viewModel.sendBroadcastLiveData.observe(viewLifecycleOwner) { + if (it == true) { + dismissAllowingStateLoss() + } + } + + if (activity != null && activity is BaseActivity) { + val manager = (activity as BaseActivity).dialogManager + viewModel.loadingLiveData.observe(viewLifecycleOwner) { + if (it == true) { + manager.showProgressDialog(activity) + } else { + manager.dismissDialog() + } + } + } + + viewModel.getVipBroadcastInfo() + viewModel.vipBroadcastInfoLiveData.observe(viewLifecycleOwner) { beanResult -> + if (beanResult.isSuccess) { + beanResult.data?.let { + binding?.clRoot?.isVisible = true + binding?.tvSendLimit?.text = R.string.layout_dialog_vip_broadcast_03.getString(it.remainCount,it.totalCount) + disposable?.dispose() + disposable = Observable.interval(0, 1, TimeUnit.SECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { _ -> + val remainTime = + (CurrentTimeUtils.getCurrentTime() - it.lastSendTime) / 1000 + if (remainTime > 60) { + binding?.tvSendTip?.text = R.string.layout_dialog_vip_broadcast_05.getString() + binding?.ivSend?.isEnabled = true + disposable?.dispose() + } else { + binding?.ivSend?.isEnabled = false + binding?.tvSendTip?.text = R.string.roomBroadcast.getString((60 - remainTime)) + } + } + } + } else { + beanResult.message.toast() + dismissAllowingStateLoss() + } + + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/vip/dialog/VipRemainTimeDialog.kt b/app/src/main/java/com/chwl/app/vip/dialog/VipRemainTimeDialog.kt new file mode 100644 index 0000000..a0bd396 --- /dev/null +++ b/app/src/main/java/com/chwl/app/vip/dialog/VipRemainTimeDialog.kt @@ -0,0 +1,22 @@ +package com.chwl.app.vip.dialog + +import android.os.Bundle +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.databinding.DialogVipRemainTimeBinding + +class VipRemainTimeDialog : BaseDialogFragment() { + + companion object { + @JvmStatic + fun newInstance(): VipRemainTimeDialog { + val args = Bundle() + val fragment = VipRemainTimeDialog() + fragment.arguments = args + return fragment + } + } + + override fun init() { + binding?.ivClose?.setOnClickListener { dismissAllowingStateLoss() } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/vip/dialog/VipUpgradeDialog.kt b/app/src/main/java/com/chwl/app/vip/dialog/VipUpgradeDialog.kt new file mode 100644 index 0000000..fe1f1ef --- /dev/null +++ b/app/src/main/java/com/chwl/app/vip/dialog/VipUpgradeDialog.kt @@ -0,0 +1,80 @@ +package com.chwl.app.vip.dialog + +import android.annotation.SuppressLint +import android.os.Bundle +import androidx.fragment.app.activityViewModels +import com.chwl.app.R +import com.opensource.svgaplayer.SVGADrawable +import com.opensource.svgaplayer.SVGAParser +import com.opensource.svgaplayer.SVGAVideoEntity +import com.chwl.app.base.BaseActivity +import com.chwl.app.base.BaseDialogFragment +import com.chwl.app.databinding.DialogVipUpgradeBinding +import com.chwl.app.ui.utils.loadAnim +import com.chwl.app.ui.utils.loadAnim2 +import com.chwl.app.vip.VipViewModel +import com.chwl.core.vip.bean.VipInfo + +class VipUpgradeDialog : BaseDialogFragment() { + + companion object { + @JvmStatic + fun newInstance(vipInfo: VipInfo): VipUpgradeDialog { + val args = Bundle() + args.putSerializable("vipInfo", vipInfo) + val fragment = VipUpgradeDialog() + fragment.arguments = args + return fragment + } + } + + private val vm: VipViewModel by activityViewModels() + + private val vipInfo by lazy { requireArguments().getSerializable("vipInfo") as VipInfo } + + @SuppressLint("SetTextI18n") + override fun init() { + binding?.ivClose?.setOnClickListener { dismissAllowingStateLoss() } + + vm.saveOriginDisguiseResult.observe(this) { + if (it == true) { + dismissAllowingStateLoss() + } + } + if (activity != null && activity is BaseActivity) { + val manager = (activity as BaseActivity).dialogManager + vm.loadingLiveData.observe(this) { + if (it == true) { + manager.showProgressDialog(activity) + } else { + manager.dismissDialog() + } + } + } + binding?.tvVipUplevel?.setOnClickListener { dismissAllowingStateLoss() } + binding?.tvVipOrigin?.setOnClickListener { vm.saveOriginDisguise() } + binding?.ivVipIconMp4?.setLoop(Int.MAX_VALUE) + binding?.ivVipIconMp4?.loadAnim(vipInfo.vipLogo) + + + +// try { +// SVGAParser.shareParser() +// .decodeFromURL(URL(vipInfo.vipLogo), object : SVGAParser.ParseCompletion { +// override fun onComplete(videoItem: SVGAVideoEntity) { +// val drawable = SVGADrawable(videoItem) +// if (isViewLoaded) { +// _binding?.ivVipIcon?.setImageDrawable(drawable) +// _binding?.ivVipIcon?.startAnimation() +// } +// } +// +// override fun onError() { +// } +// }) +// } catch (e: MalformedURLException) { +// +// } + binding?.tvLevelDesc?.text = getString(R.string.level_up_wear_dress_tips_format).format(vipInfo.vipName) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/vip/util/VipHelper.java b/app/src/main/java/com/chwl/app/vip/util/VipHelper.java new file mode 100644 index 0000000..8b99a43 --- /dev/null +++ b/app/src/main/java/com/chwl/app/vip/util/VipHelper.java @@ -0,0 +1,82 @@ +package com.chwl.app.vip.util; + +import android.graphics.Color; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.chwl.app.ui.utils.ImageLoadUtils; +import com.chwl.core.user.UserModel; +import com.chwl.core.user.bean.UserInfo; +import com.chwl.core.utils.CoreTextUtils; +import com.chwl.core.vip.bean.UserVipInfo; + +public class VipHelper { + + public static void loadVipIcon(@NonNull ImageView ivVipIcon, @Nullable UserVipInfo vipInfo) { + if (vipInfo == null || CoreTextUtils.isEmptyText(vipInfo.getVipIcon())) { + ivVipIcon.setVisibility(View.GONE); + } else { + ivVipIcon.setVisibility(View.VISIBLE); + ImageLoadUtils.loadImage(ivVipIcon.getContext(), vipInfo.getVipIcon(), ivVipIcon); + } + } + + public static void loadVipNameplate(@NonNull ImageView ivVipIcon, @Nullable UserVipInfo vipInfo) { + if (vipInfo == null || CoreTextUtils.isEmptyText(vipInfo.getNameplateUrl())) { + ivVipIcon.setVisibility(View.GONE); + } else { + ivVipIcon.setVisibility(View.VISIBLE); + ImageLoadUtils.loadImage(ivVipIcon.getContext(), vipInfo.getNameplateUrl(), ivVipIcon); + } + } + + public static void loadVipNickColor(@NonNull TextView tvNick, @Nullable UserVipInfo vipInfo, String defaultColor) { + try { + if (vipInfo == null || CoreTextUtils.isEmptyText(vipInfo.getFriendNickColour())) { + tvNick.setTextColor(Color.parseColor(defaultColor)); + } else { + tvNick.setTextColor(Color.parseColor(vipInfo.getFriendNickColour())); + } + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + + } + + public static int getMyVipLevel() { + UserInfo userInfo = UserModel.get().getCacheLoginUserInfo(); + if (userInfo == null) return 0; + return userInfo.getUserVipInfoVO() == null ? 0 : userInfo.getUserVipInfoVO().getVipLevel(); + } + + public static String getVipName(UserInfo userInfo) { + return (userInfo != null && userInfo.getUserVipInfoVO() != null) ? userInfo.getUserVipInfoVO().getVipName() : ""; + } + + public static boolean notKick(UserInfo userInfo) { + return userInfo != null && userInfo.getUserVipInfoVO() != null && userInfo.getUserVipInfoVO().getPreventKick(); + } + public static boolean notTrace(UserInfo userInfo) { + return userInfo != null && userInfo.getUserVipInfoVO() != null && userInfo.getUserVipInfoVO().getPreventTrace(); + } + public static boolean cantGifAvatar(UserInfo userInfo) { + return userInfo != null && userInfo.getUserVipInfoVO() != null && userInfo.getUserVipInfoVO().getUploadGifAvatar(); + } + public static boolean enterHide(UserInfo userInfo) { + return userInfo != null && userInfo.getUserVipInfoVO() != null && userInfo.getUserVipInfoVO().getEnterHide(); + } + public static boolean roomPicScreen(UserInfo userInfo) { + return userInfo != null && userInfo.getUserVipInfoVO() != null && userInfo.getUserVipInfoVO().getRoomPicScreen(); + } + + public static boolean showFind(UserVipInfo vipInfo) { + if (vipInfo != null) { + return !(vipInfo.getPreventTrace() || vipInfo.getEnterHide()); + } + return false; + } +} diff --git a/app/src/main/java/com/chwl/app/vip/view/VipBroadcastView.kt b/app/src/main/java/com/chwl/app/vip/view/VipBroadcastView.kt new file mode 100644 index 0000000..261707d --- /dev/null +++ b/app/src/main/java/com/chwl/app/vip/view/VipBroadcastView.kt @@ -0,0 +1,108 @@ +package com.chwl.app.vip.view + +import android.animation.ObjectAnimator +import android.annotation.SuppressLint +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.widget.FrameLayout +import androidx.core.animation.doOnEnd +import androidx.core.view.isGone +import androidx.core.view.isVisible +import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage +import com.chwl.app.databinding.LayoutVipBroadcastViewBinding +import com.chwl.app.ui.utils.ImageLoadUtils +import com.chwl.core.im.custom.bean.VipMessageAttachment +import com.chwl.core.room.anotherroompk.ShowUserInfoDialogEvent +import com.chwl.core.utils.extension.subAndReplaceDot +import com.chwl.core.vip.VipBroadcastMsgEvent +import com.chwl.library.rxbus.RxBus +import io.reactivex.Observable +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode +import java.util.concurrent.TimeUnit + +class VipBroadcastView @JvmOverloads constructor( + context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 +) : FrameLayout(context, attrs, defStyleAttr) { + + private val binding = LayoutVipBroadcastViewBinding.inflate(LayoutInflater.from(context)) + private val messages: MutableList by lazy { ArrayList() } + private var disposable: Disposable? = null + + init { + addView(binding.root, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)) + binding.llRoot.setOnClickListener { + RxBus.get().post(ShowUserInfoDialogEvent(binding.llRoot.tag as String)) + } + EventBus.getDefault().register(this) + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + EventBus.getDefault().unregister(this) + disposable?.dispose() + } + + @Subscribe(threadMode = ThreadMode.MAIN) + fun onVipBroadcastMsgEvent(event: VipBroadcastMsgEvent) { + event.message?.let { addMessage(it) } + } + + private fun addMessage(chatRoomMessage: ChatRoomMessage) { + messages.add(chatRoomMessage) + if (isGone) { + isVisible = true + ObjectAnimator.ofFloat( + this, + "alpha", + 0f, + 1f + ) + .setDuration(500) + .start() + } + if (disposable == null || messages.size == 1) { + disposable = Observable.interval(0, 5, TimeUnit.SECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .doOnDispose { + ObjectAnimator.ofFloat( + this, + "alpha", + 1f, + 0f + ) + .setDuration(200) + .apply { + doOnEnd { + binding.tvContent.stop() + isGone = true + } + } + .start() + } + .takeWhile { messages.size > 0 } + .subscribe { + showMessage(messages.removeAt(0)) + } + } + } + + @SuppressLint("SetTextI18n") + private fun showMessage(chatRoomMessage: ChatRoomMessage?) { + val attachment = chatRoomMessage?.attachment as? VipMessageAttachment ?: return + attachment.vipMessageInfo?.let { + ImageLoadUtils.loadAvatar(it.avatar, binding.ivAvatar) + ImageLoadUtils.loadImage(context, it.vipIcon, binding.ivVipIcon) + binding.tvNick.text = it.nick.subAndReplaceDot(7) + ":" + binding.tvContent.text = it.content + binding.tvContent.start() + binding.llRoot.tag = it.uid.toString() + } + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/chwl/app/vip/view/VipTabView.kt b/app/src/main/java/com/chwl/app/vip/view/VipTabView.kt new file mode 100644 index 0000000..0e834ef --- /dev/null +++ b/app/src/main/java/com/chwl/app/vip/view/VipTabView.kt @@ -0,0 +1,48 @@ +package com.chwl.app.vip.view + +import android.content.Context +import android.graphics.Color +import android.view.LayoutInflater +import android.view.View +import android.widget.TextView +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.view.isInvisible +import com.chwl.app.R +import com.chwl.app.ui.widget.magicindicator.buildins.commonnavigator.abs.IPagerTitleView + +/** + * Created by Max on 2024/3/28 17:05 + * Desc: + **/ +class VipTabView(context: Context) : ConstraintLayout(context), IPagerTitleView { + + val textView: TextView + private val rebateView: View + private var selectedColor = Color.parseColor("#FFBC9E66") + private var normalColor = Color.parseColor("#FFFFE3AF") + + init { + LayoutInflater.from(context).inflate(R.layout.vip_tab_item, this) + textView = findViewById(R.id.tv_title) + rebateView = findViewById(R.id.iv_rebate) + } + + override fun onSelected(index: Int, totalCount: Int) { + textView.setTextColor(selectedColor) + } + + override fun onDeselected(index: Int, totalCount: Int) { + textView.setTextColor(normalColor) + } + + override fun onLeave(index: Int, totalCount: Int, leavePercent: Float, leftToRight: Boolean) { + } + + override fun onEnter(index: Int, totalCount: Int, enterPercent: Float, leftToRight: Boolean) { + } + + fun setData(title: CharSequence, isRebate: Boolean) { + textView.text = title + rebateView.isInvisible = !isRebate + } +} \ No newline at end of file