Junqin Wang 8 years ago
parent
commit
ffba8e2b25
83 changed files with 2003 additions and 458 deletions
  1. 4 4
      app/README.md
  2. 13 7
      app/app.iml
  3. 1 0
      app/build.gradle
  4. 12 1
      app/proguard.cfg
  5. BIN
      app/res/drawable-hdpi/trade_follow.png
  6. BIN
      app/res/drawable-hdpi/trade_followed.png
  7. BIN
      app/res/drawable-hdpi/trade_unfollowed.png
  8. BIN
      app/res/drawable-mdpi/trade_follow.png
  9. BIN
      app/res/drawable-mdpi/trade_followed.png
  10. BIN
      app/res/drawable-mdpi/trade_unfollowed.png
  11. BIN
      app/res/drawable-xhdpi/trade_follow.png
  12. BIN
      app/res/drawable-xhdpi/trade_followed.png
  13. BIN
      app/res/drawable-xhdpi/trade_unfollowed.png
  14. BIN
      app/res/drawable-xxhdpi/trade_follow.png
  15. BIN
      app/res/drawable-xxhdpi/trade_followed.png
  16. BIN
      app/res/drawable-xxhdpi/trade_unfollowed.png
  17. BIN
      app/res/drawable-xxxhdpi/trade_follow.png
  18. BIN
      app/res/drawable-xxxhdpi/trade_followed.png
  19. BIN
      app/res/drawable-xxxhdpi/trade_unfollowed.png
  20. 0 7
      app/res/drawable/actionbar_dark_logo.xml
  21. 0 7
      app/res/drawable/actionbar_dark_logo_space.xml
  22. 0 6
      app/res/drawable/splash_bg.xml
  23. 6 0
      app/res/drawable/style_edittext_rounded_corner_2.xml
  24. 1 1
      app/res/drawable/style_rounded_corner_editext.xml
  25. 1 1
      app/res/layout/action_bar_layout.xml
  26. 1 1
      app/res/layout/area_groups_list_fragment.xml
  27. 0 156
      app/res/layout/login_activity.xml
  28. 4 2
      app/res/layout/main.xml
  29. 5 0
      app/res/layout/recent_contacts_list_activity.xml
  30. 18 0
      app/res/layout/session_list.xml
  31. 1 1
      app/res/layout/system_notification_message_activity.xml
  32. 12 0
      app/res/layout/team_chat_create_team.xml
  33. 8 5
      app/res/layout/trade_list_fragment.xml
  34. 23 9
      app/res/layout/trade_list_item.xml
  35. 2 2
      app/res/menu/main_botton_navi_menu.xml
  36. 5 5
      app/res/values/strings.xml
  37. 1 1
      app/res/values/styles-activity.xml
  38. 1 1
      app/src/com/sheishuo/app/common/imageView/GroupHeadImageView.java
  39. 2 0
      app/src/com/sheishuo/app/common/util/net/NetInfo.java
  40. 6 2
      app/src/com/sheishuo/app/common/views/BaseToolbar.java
  41. 1016 0
      app/src/com/sheishuo/app/common/views/BottomNavigationViewEx.java
  42. 13 8
      app/src/com/sheishuo/app/common/views/ImgGridView.java
  43. 9 0
      app/src/com/sheishuo/app/common/views/PartlyHighLightTextView.java
  44. 14 2
      app/src/com/sheishuo/app/core_module/recent_contacts/activity/ContactsListActivity.java
  45. 98 1
      app/src/com/sheishuo/app/core_module/trade/model/TradeModel.java
  46. 21 0
      app/src/com/sheishuo/app/core_module/trade/presenter/TradePresenter.java
  47. 266 0
      app/src/com/sheishuo/app/core_module/trade/view/adapter/TradeItemAdapter.java
  48. 1 1
      app/src/com/sheishuo/app/main/activity/GlobalSearchActivity.java
  49. 1 1
      app/src/com/sheishuo/app/main/activity/WelcomeActivity.java
  50. 15 8
      app/src/com/sheishuo/app/main/adapter/CircleListAdapter.java
  51. 4 2
      app/src/com/sheishuo/app/main/fragment/AreaGroupsFragment.java
  52. 1 1
      app/src/com/sheishuo/app/main/fragment/ChatRoomListFragment.java
  53. 4 0
      app/src/com/sheishuo/app/main/fragment/CircleOfFriendsFragment.java
  54. 16 3
      app/src/com/sheishuo/app/main/fragment/HomeFragment.java
  55. 12 1
      app/src/com/sheishuo/app/main/fragment/SessionListFragment.java
  56. 172 2
      app/src/com/sheishuo/app/main/fragment/TradeListFragment.java
  57. 1 1
      app/src/com/sheishuo/app/session/SessionHelper.java
  58. 1 1
      app/src/com/sheishuo/app/session/search/SearchMessageActivity.java
  59. 1 0
      app/src/com/sheishuo/app/team/TeamCreateHelper.java
  60. 1 1
      app/src/com/sheishuo/app/team/activity/AdvancedTeamJoinActivity.java
  61. 2 2
      app/src/com/sheishuo/app/team/activity/AdvancedTeamSearchActivity.java
  62. 7 0
      build.gradle
  63. 164 164
      gradlew
  64. BIN
      uikit/res/drawable-hdpi/blank_ico.png
  65. BIN
      uikit/res/drawable-hdpi/nim_actionbar_dark_logo_icon.png
  66. BIN
      uikit/res/drawable-mdpi/blank_ico.png
  67. BIN
      uikit/res/drawable-xhdpi/blank_ico.png
  68. BIN
      uikit/res/drawable-xhdpi/nim_actionbar_dark_logo_icon.png
  69. BIN
      uikit/res/drawable-xxhdpi/blank_ico.png
  70. BIN
      uikit/res/drawable-xxxhdpi/blank_ico.png
  71. 0 7
      uikit/res/drawable/nim_actionbar_nest_dark_logo.xml
  72. 1 1
      uikit/res/layout/mass_message_activity.xml
  73. 3 3
      uikit/res/values/strings.xml
  74. 2 2
      uikit/src/com/netease/nim/uikit/NimUIKit.java
  75. 1 1
      uikit/src/com/netease/nim/uikit/contact/core/item/ItemTypes.java
  76. 1 1
      uikit/src/com/netease/nim/uikit/model/ToolBarOptions.java
  77. 1 1
      uikit/src/com/netease/nim/uikit/recent/RecentContactsFragment.java
  78. 1 1
      uikit/src/com/netease/nim/uikit/session/SessionEventListener.java
  79. 2 2
      uikit/src/com/netease/nim/uikit/session/activity/TeamMessageActivity.java
  80. 12 12
      uikit/src/com/netease/nim/uikit/session/helper/TeamNotificationHelper.java
  81. 1 1
      uikit/src/com/netease/nim/uikit/session/module/list/MessageListPanelEx.java
  82. 1 1
      uikit/src/com/netease/nim/uikit/team/activity/AdvancedTeamInfoActivity.java
  83. 10 7
      uikit/uikit.iml

+ 4 - 4
app/README.md

@@ -1,6 +1,6 @@
 # 网易云通信安卓 Demo 结构说明
 
-网易云通信 Demo 工程基于网易云通信 SDK,演示了 SDK 聊天、群组、白板、实时音视频等功能接口的使用方法。Demo 工程依赖于 UIKit 工程,UIKit 实现了基本的消息收发,群组服务以及通讯录等功能,包含有完整的界面显示。开发者可以直接调用UIKit 中的接口,来进行功能开发,加快开发速度。用户可参照该 Demo,将网易云通信 SDK 接入自己的 APP。
+网易云通信 Demo 工程基于网易云通信 SDK,演示了 SDK 聊天、聊天室、白板、实时音视频等功能接口的使用方法。Demo 工程依赖于 UIKit 工程,UIKit 实现了基本的消息收发,聊天室服务以及通讯录等功能,包含有完整的界面显示。开发者可以直接调用UIKit 中的接口,来进行功能开发,加快开发速度。用户可参照该 Demo,将网易云通信 SDK 接入自己的 APP。
 
 ## <span id="工程导入指引"> 工程导入指引</span>
 - [Eclipse导入Demo](http://note.youdao.com/groupshare/?token=7565E66468734B5C89D114AFD7AAB493&gid=14302436  "target=_blank")
@@ -43,9 +43,9 @@
 
 - Application 入口:NimApplication, 包含 SDK 的初始化,UIKit的初始化以及配置示例。
 - 登录相关:login 包,包含一个比较典型的从第三方 APP 授权,然后登录到网易云通信服务器的例子。
-- 主界面:main 包,包含最近联系人列表和好友/群组列表。该包作为各个功能的入口点,内含获取和管理最近联系人,获取群组列表,收发自定义通知等 SDK 接口使用示例。
+- 主界面:main 包,包含最近联系人列表和好友/聊天室列表。该包作为各个功能的入口点,内含获取和管理最近联系人,获取聊天室列表,收发自定义通知等 SDK 接口使用示例。
 - 消息相关:session 包,包含消息历史,聊天信息和搜索消息界面。消息的具体展示和收发都在 UIKit 中。可以使用 NimUIKit 直接展示和使用。也可以使用 SessionHelper 进行消息界面的定制。
-- 群组相关:team 包,包含搜索群组和加入群组界面。包含创建高级群和讨论组的接口使用示例。
+- 聊天室相关:team 包,包含搜索聊天室和加入聊天室界面。包含创建高级群和讨论组的接口使用示例。
 - 音视频通话相关:avchat 包,包含音视频通话界面。内含网络通话功能的 SDK 接口使用示例,以及一个完整的网络通话流程示例,开发者可直接参考开发音视频通话功能。
 - 实时会话(白版):rts 包,包含白板教学的示例,支持实时音频、白板数据收发。
 
@@ -54,7 +54,7 @@
 - UIKit 调用接口:NimUIKit,包含构建好友和群的缓存,打开聊天窗口,打开联系人选择器,打开群资料。
 - 基础组件相关:common 包, 包含 Activity、Fragment 和 Adapter的基类,一些自定义 UI 控件以及系统工具类。
 - 消息相关:session包,包含单聊/群聊界面,内含收发消息,上传下载消息附件,使用高清语音,管理消息历史等 SDK 接口使用示例。该包还有消息展示,使用 emoji 表情,发送图片等示例代码,可供开发者参考。
-- 群组相关:team 包,包含群组信息界面。内含展示群资料,修改群资料,展示群成员列表,管理群成员列表等 SDK 接口使用示例。
+- 聊天室相关:team 包,包含聊天室信息界面。内含展示群资料,修改群资料,展示群成员列表,管理群成员列表等 SDK 接口使用示例。
 - 最近联系人相关:recent 包,包含最近联系人列表界面
 - 通讯录相关:contact_selector 包和 contact 包,包含联系人选择器和通讯录。内含用户信息等 SDK 接口使用示例。
 

+ 13 - 7
app/app.iml

@@ -59,13 +59,6 @@
       <sourceFolder url="file://$MODULE_DIR$/assets" type="java-resource" />
       <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
       <sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
-      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
-      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
-      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
-      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
       <sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
       <sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
       <sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
@@ -73,6 +66,16 @@
       <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
       <sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
       <sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
+      <excludeFolder url="file://$MODULE_DIR$/build/.DS_Store" />
+      <excludeFolder url="file://$MODULE_DIR$/build/freeline" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/.DS_Store" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/builds" />
@@ -90,6 +93,7 @@
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/proguard-rules" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/reload-dex" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/res.job" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/restart-dex" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" />
@@ -108,6 +112,7 @@
     <orderEntry type="library" exported="" name="video_effect" level="project" />
     <orderEntry type="library" exported="" name="design-25.3.1" level="project" />
     <orderEntry type="library" exported="" name="support-core-ui-25.3.1" level="project" />
+    <orderEntry type="library" exported="" scope="TEST" name="runtime-no-op-0.8.7" level="project" />
     <orderEntry type="library" exported="" name="cardview-v7-25.1.1" level="project" />
     <orderEntry type="library" exported="" name="rxandroid-2.0.1" level="project" />
     <orderEntry type="library" exported="" name="HMS-SDK-2.4.0.300-" level="project" />
@@ -124,6 +129,7 @@
     <orderEntry type="library" exported="" name="okio-1.13.0" level="project" />
     <orderEntry type="library" exported="" name="retrofit-2.3.0" level="project" />
     <orderEntry type="library" exported="" name="converter-gson-2.3.0" level="project" />
+    <orderEntry type="library" exported="" name="runtime-0.8.7" level="project" />
     <orderEntry type="library" exported="" name="okhttp-3.8.0" level="project" />
     <orderEntry type="library" exported="" name="AMap_Services_V2.3.1" level="project" />
     <orderEntry type="library" exported="" name="overscroll-decor-android-1.0.4" level="project" />

+ 1 - 0
app/build.gradle

@@ -1,4 +1,5 @@
 apply plugin: 'com.android.application'
+apply plugin: 'com.antfortune.freeline'
 
 def static getGitVersion() {
     try {

+ 12 - 1
app/proguard.cfg

@@ -162,6 +162,17 @@
 ##---------------End: proguard configuration for Gson ----------
 
 
+
+
+##---------------Begin: proguard configuration for BottomNavigationViewEx ----------
+
+-keep public class android.support.design.widget.BottomNavigationView { *; }
+-keep public class android.support.design.internal.BottomNavigationMenuView { *; }
+-keep public class android.support.design.internal.BottomNavigationPresenter { *; }
+-keep public class android.support.design.internal.BottomNavigationItemView { *; }
+
+##---------------End: proguard configuration for BottomNavigationViewEx ----------
+
+
 -dontwarn okio.**
 -dontwarn javax.annotation.**
-

BIN
app/res/drawable-hdpi/trade_follow.png


BIN
app/res/drawable-hdpi/trade_followed.png


BIN
app/res/drawable-hdpi/trade_unfollowed.png


BIN
app/res/drawable-mdpi/trade_follow.png


BIN
app/res/drawable-mdpi/trade_followed.png


BIN
app/res/drawable-mdpi/trade_unfollowed.png


BIN
app/res/drawable-xhdpi/trade_follow.png


BIN
app/res/drawable-xhdpi/trade_followed.png


BIN
app/res/drawable-xhdpi/trade_unfollowed.png


BIN
app/res/drawable-xxhdpi/trade_follow.png


BIN
app/res/drawable-xxhdpi/trade_followed.png


BIN
app/res/drawable-xxhdpi/trade_unfollowed.png


BIN
app/res/drawable-xxxhdpi/trade_follow.png


BIN
app/res/drawable-xxxhdpi/trade_followed.png


BIN
app/res/drawable-xxxhdpi/trade_unfollowed.png


+ 0 - 7
app/res/drawable/actionbar_dark_logo.xml

@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<layer-list
-    xmlns:android="http://schemas.android.com/apk/res/android">
-    <item
-        android:drawable="@drawable/actionbar_dark_logo_icon"
-        android:right="15dp"/>
-</layer-list>

+ 0 - 7
app/res/drawable/actionbar_dark_logo_space.xml

@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<layer-list
-    xmlns:android="http://schemas.android.com/apk/res/android">
-    <item
-        android:drawable="@drawable/actionbar_dark_logo_icon"
-        android:left="5dp"/>
-</layer-list>

+ 0 - 6
app/res/drawable/splash_bg.xml

@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
-
-    <item android:drawable="@drawable/welcome_bg"/>
-
-</layer-list>

+ 6 - 0
app/res/drawable/style_edittext_rounded_corner_2.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <corners android:radius="16dp"/>
+    <solid android:color="@color/white"/>
+
+</shape>

+ 1 - 1
app/res/drawable/style_rounded_corner_editext.xml

@@ -2,5 +2,5 @@
 <shape xmlns:android="http://schemas.android.com/apk/res/android">
     <corners android:radius="8dp"/>
     <stroke android:color="@color/color_grey_555555"
-        android:width="1dp"/>
+        android:width="1dp" />
 </shape>

+ 1 - 1
app/res/layout/action_bar_layout.xml

@@ -28,7 +28,7 @@
             android:layout_height="wrap_content"
             android:contentDescription="@string/empty"
             android:layout_marginRight="5dp"
-            android:src="@drawable/actionbar_dark_logo_icon" />
+            android:src="@drawable/blank_ico" />
     </LinearLayout>
 
     <TextView

+ 1 - 1
app/res/layout/area_groups_list_fragment.xml

@@ -82,7 +82,7 @@
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:gravity="end"
-                android:text="用户创建群组" />
+                android:text="用户创建聊天室" />
         </LinearLayout>
 
         <View style="@style/horizontal_light_thin_divider" />

+ 0 - 156
app/res/layout/login_activity.xml

@@ -1,156 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:background="@drawable/login_bg"
-    android:orientation="vertical">
-
-    <android.support.design.widget.AppBarLayout
-        android:id="@+id/app_bar_layout"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:theme="@style/AppTheme.AppBarOverlay"
-        app:elevation="0dp">
-
-        <android.support.v7.widget.Toolbar
-            android:id="@+id/toolbar"
-            android:layout_width="match_parent"
-            android:layout_height="?attr/actionBarSize"
-            android:background="?attr/colorPrimary"
-            app:titleTextAppearance="@style/Toolbar.TitleText">
-
-            <include layout="@layout/nim_action_bar_right_clickable_tv" />
-        </android.support.v7.widget.Toolbar>
-    </android.support.design.widget.AppBarLayout>
-
-    <ScrollView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content">
-
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:orientation="vertical">
-
-            <ImageView
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center_horizontal"
-                android:layout_marginTop="59dp"
-                android:background="@drawable/logo"
-                android:contentDescription="@string/empty"/>
-
-            <FrameLayout
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:layout_marginLeft="10dip"
-                android:layout_marginRight="10dip"
-                android:layout_marginTop="74dp">
-
-                <LinearLayout
-                    android:id="@+id/login_layout"
-                    android:layout_width="match_parent"
-                    android:layout_height="match_parent"
-                    android:orientation="vertical">
-
-                    <com.netease.nim.uikit.common.ui.widget.ClearableEditTextWithIcon
-                        android:id="@+id/edit_login_account"
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:background="@drawable/edittext_white_normal"
-                        android:drawablePadding="15dp"
-                        android:hint="@string/login_hint_account"
-                        android:paddingLeft="15dp"
-                        android:paddingRight="15dp"
-                        android:textColor="@color/white"
-                        android:textColorHint="@color/color_white_66ffffff"
-                        android:textCursorDrawable="@null"
-                        android:textSize="15sp"/>
-
-                    <com.netease.nim.uikit.common.ui.widget.ClearableEditTextWithIcon
-                        android:id="@+id/edit_login_password"
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:background="@drawable/edittext_white_normal"
-                        android:drawablePadding="15dp"
-                        android:hint="@string/login_hint_password"
-                        android:inputType="textPassword"
-                        android:longClickable="false"
-                        android:paddingLeft="15dp"
-                        android:paddingRight="15dp"
-                        android:textColor="@color/white"
-                        android:textColorHint="@color/color_white_66ffffff"
-                        android:textCursorDrawable="@null"
-                        android:textSize="15sp"/>
-                </LinearLayout>
-
-                <LinearLayout
-                    android:id="@+id/register_layout"
-                    android:layout_width="match_parent"
-                    android:layout_height="match_parent"
-                    android:orientation="vertical"
-                    android:visibility="gone">
-
-                    <com.netease.nim.uikit.common.ui.widget.ClearableEditTextWithIcon
-                        android:id="@+id/edit_register_account"
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:background="@drawable/edittext_white_normal"
-                        android:digits="1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
-                        android:drawablePadding="15dp"
-                        android:hint="@string/input_account"
-                        android:inputType="text"
-                        android:paddingLeft="15dp"
-                        android:paddingRight="15dp"
-                        android:textColor="@color/white"
-                        android:textColorHint="@color/color_white_66ffffff"
-                        android:textCursorDrawable="@null"
-                        android:textSize="15sp"/>
-
-                    <com.netease.nim.uikit.common.ui.widget.ClearableEditTextWithIcon
-                        android:id="@+id/edit_register_nickname"
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:background="@drawable/edittext_white_normal"
-                        android:drawablePadding="15dp"
-                        android:hint="@string/input_nickname"
-                        android:inputType="text"
-                        android:paddingLeft="15dp"
-                        android:paddingRight="15dp"
-                        android:textColor="@color/white"
-                        android:textColorHint="@color/color_white_66ffffff"
-                        android:textCursorDrawable="@null"
-                        android:textSize="15sp"/>
-
-                    <com.netease.nim.uikit.common.ui.widget.ClearableEditTextWithIcon
-                        android:id="@+id/edit_register_password"
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:background="@drawable/edittext_white_normal"
-                        android:drawablePadding="15dp"
-                        android:hint="@string/input_password"
-                        android:inputType="textPassword"
-                        android:longClickable="false"
-                        android:paddingLeft="15dp"
-                        android:paddingRight="15dp"
-                        android:textColor="@color/white"
-                        android:textColorHint="@color/color_white_66ffffff"
-                        android:textCursorDrawable="@null"
-                        android:textSize="15sp"/>
-                </LinearLayout>
-            </FrameLayout>
-
-            <TextView
-                android:id="@+id/register_login_tip"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center_horizontal"
-                android:layout_marginTop="10dip"
-                android:padding="15dip"
-                android:text="@string/register"
-                android:textColor="@drawable/register_tip_selector"
-                android:textSize="15sp"/>
-        </LinearLayout>
-    </ScrollView>
-</LinearLayout>

+ 4 - 2
app/res/layout/main.xml

@@ -45,11 +45,13 @@
             android:layout_below="@id/tabs"/>
 
 
-        <android.support.design.widget.BottomNavigationView
+        <com.sheishuo.app.common.views.BottomNavigationViewEx
             android:id="@+id/main_navigationbar"
-            android:layout_width="match_parent"
+            android:layout_width="wrap_content"
             android:layout_height="0dp"
             android:layout_weight="1"
+            android:background="?android:attr/windowBackground"
+            android:layout_gravity="bottom"
             app:menu="@menu/main_botton_navi_menu" />
 
 

+ 5 - 0
app/res/layout/recent_contacts_list_activity.xml

@@ -2,6 +2,11 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical" android:layout_width="match_parent"
     android:layout_height="match_parent">
+    <com.sheishuo.app.common.views.BaseToolbar
+        android:id="@+id/toolbar"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        style="@style/fullToolbarStyle"/>
     <LinearLayout
         android:id="@+id/recent_contacts_list_layout"
         android:layout_width="match_parent"

+ 18 - 0
app/res/layout/session_list.xml

@@ -9,5 +9,23 @@
     <include layout="@layout/network_status_bar" />
     <include layout="@layout/multiport_status_bar" />
 
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:background="@color/color_grey_eaeaea"
+        android:padding="8dp">
+        <TextView
+            android:id="@+id/session_list_search_tv"
+            android:layout_width="300dp"
+            android:layout_height="wrap_content"
+            android:background="@drawable/style_edittext_rounded_corner_2"
+            android:text="请输入ID或手机号进行查找"
+            android:textSize="10sp"
+            android:textColor="@color/color_grey_999999"
+            android:gravity="center"
+            android:padding="8dp"/>
+    </LinearLayout>
+
 
 </LinearLayout>

+ 1 - 1
app/res/layout/system_notification_message_activity.xml

@@ -44,7 +44,7 @@
                 android:fadingEdge="none"
                 android:focusable="false"
                 android:listSelector="@android:color/transparent"
-                android:scrollbars="vertical"></com.netease.nim.uikit.common.ui.listview.MessageListView>
+                android:scrollbars="vertical"/>
         </LinearLayout>
     </FrameLayout>
 </LinearLayout>

+ 12 - 0
app/res/layout/team_chat_create_team.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical" android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <com.sheishuo.app.common.views.BaseToolbar
+        android:id="@+id/toolbar"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        style="@style/fullToolbarStyle" />
+
+
+</LinearLayout>

+ 8 - 5
app/res/layout/trade_list_fragment.xml

@@ -2,10 +2,11 @@
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
     android:orientation="vertical" android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="match_parent"
+    android:background="@color/color_background">
     <LinearLayout
         android:id="@+id/trade_list_notifications_layout"
-        android:layout_width="368dp"
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:orientation="vertical"
         tools:layout_editor_absoluteY="0dp"
@@ -13,8 +14,8 @@
 
     <android.support.v7.widget.RecyclerView
         android:id="@+id/trade_list_recyclerview"
-        android:layout_width="368dp"
-        android:layout_height="551dp"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
         tools:layout_editor_absoluteY="8dp"
         tools:layout_editor_absoluteX="8dp"
         android:layout_alignParentBottom="true"
@@ -22,6 +23,8 @@
         android:layout_alignParentEnd="true"
         android:layout_alignParentTop="true"
         android:layout_alignParentLeft="true"
-        android:layout_alignParentStart="true" />
+        android:layout_alignParentStart="true"
+        android:paddingLeft="8dp"
+        android:paddingRight="8dp"/>
 
 </RelativeLayout>

+ 23 - 9
app/res/layout/trade_list_item.xml

@@ -2,14 +2,19 @@
 <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
+    android:layout_height="wrap_content"
     android:orientation="vertical"
-    android:padding="8dp">
+    android:layout_marginTop="16dp"
+    android:clickable="true"
+    android:foreground="?android:attr/selectableItemBackground"
+    android:id="@+id/trade_list_item_layout">
+
 
 
     <android.support.constraint.ConstraintLayout
         android:layout_width="match_parent"
-        android:layout_height="match_parent">
+        android:layout_height="wrap_content"
+        android:padding="8dp">
 
         <com.netease.nim.uikit.common.ui.imageview.HeadImageView
             android:id="@+id/trade_list_item_avatar"
@@ -24,8 +29,13 @@
 
         <ImageView
             android:id="@+id/trade_list_item_follow_img"
-            android:layout_width="48dp"
-            android:layout_height="48dp" />
+            android:layout_width="32dp"
+            android:layout_height="32dp"
+            android:src="@drawable/trade_unfollowed"
+            app:layout_constraintTop_toTopOf="parent"
+            android:layout_marginTop="16dp"
+            android:layout_marginRight="16dp"
+            app:layout_constraintRight_toRightOf="parent" />
         <TextView
             android:id="@+id/trade_list_item_name"
             android:layout_width="wrap_content"
@@ -46,7 +56,7 @@
             app:layout_constraintLeft_toLeftOf="@+id/trade_list_item_name"
             app:layout_constraintTop_toBottomOf="@+id/trade_list_item_name" />
 
-        <TextView
+        <com.sheishuo.app.common.views.PartlyHighLightTextView
             android:id="@+id/trade_list_item_content"
             android:layout_width="0dp"
             android:layout_height="wrap_content"
@@ -60,18 +70,22 @@
             app:layout_constraintLeft_toLeftOf="parent"
             app:layout_constraintRight_toRightOf="parent"
             app:layout_constraintTop_toBottomOf="@+id/trade_list_item_avatar"
-            app:layout_constraintHorizontal_bias="1.0" />
+            app:layout_constraintHorizontal_bias="1.0"
+            app:hightlight_str=""
+            app:highlight_color="@color/green_4DC0A4"
+            />
 
         <com.sheishuo.app.common.views.ImgGridView
             android:id="@+id/trade_list_item_imgs_gridview"
             android:layout_width="0dp"
             android:layout_height="wrap_content"
-            android:layout_marginTop="16dp"
             android:numColumns="2"
             app:layout_constraintLeft_toLeftOf="@+id/trade_list_item_content"
             app:layout_constraintTop_toBottomOf="@+id/trade_list_item_content"
             app:layout_constraintRight_toRightOf="@+id/trade_list_item_content"
-            app:layout_constraintHorizontal_bias="0.0" />
+            app:layout_constraintHorizontal_bias="0.0"
+            android:scrollbarDefaultDelayBeforeFade="0"
+            android:padding="16dp"/>
 
         <TextView
             android:id="@+id/trade_list_item_priority"

+ 2 - 2
app/res/menu/main_botton_navi_menu.xml

@@ -1,13 +1,13 @@
 <?xml version="1.0" encoding="utf-8"?>
 <menu xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:id="@+id/main_navi_groups"
-        android:title="群组"
+        android:title="谁说"
         android:icon="@drawable/bottom_navi_item_01_selector"/>
     <item android:id="@+id/main_navi_friends"
         android:title="朋友"
         android:icon="@drawable/_02_unchecked"/>
     <item android:id="@+id/main_navi_trade"
-        android:title="交易帖"
+        android:title="便民帖"
         android:icon="@drawable/_03_unchecked"/>
     <item android:id="@+id/main_navi_circle_of_friends"
         android:title="朋友圈"

+ 5 - 5
app/res/values/strings.xml

@@ -4,8 +4,8 @@
     <string name="title_activity_main">MainActivity</string>
     <string name="hello_world">Hello world!</string>
     <string name="empty"></string>
-    <string name="main_tab_groups">群组</string>
-    <string name="main_tab_trade">交易帖</string>
+    <string name="main_tab_groups">聊天室</string>
+    <string name="main_tab_trade">便民帖</string>
     <string name="main_tab_circleoffriends">朋友圈</string>
     <string name="main_tab_session">会话</string>
     <string name="main_tab_contact">通讯录</string>
@@ -100,7 +100,7 @@
     <string name="black_list_tip">你不会接收到列表中联系人的任何消息</string>
 
     <!-- 群 -->
-    <string name="create_team_activity">创建聊</string>
+    <string name="create_team_activity">创建聊天室</string>
     <string name="add_buddy">添加好友</string>
     <string name="create_normal_team">创建讨论组</string>
     <string name="team_apply_sending">发送中…</string>
@@ -108,7 +108,7 @@
     <string name="no_normal_team">您还没有讨论组</string>
     <string name="team_search_hint">请输入群号进行搜索</string>
     <string name="team_number_not_exist">群号不存在</string>
-    <string name="team_join">加入群组</string>
+    <string name="team_join">加入聊天室</string>
     <string name="team_join_success">成功加入群: %1$s</string>
     <string name="team_apply_to_join_send_success">申请已发出</string>
     <string name="has_exist_in_team">已经在群里</string>
@@ -128,7 +128,7 @@
     <string name="send_custom_notification_success">自定义通知发送成功</string>
     <string name="send_custom_notification_failed">自定义通知发送失败</string>
     <string name="send_custom_notification_to_buddy">发送给好友</string>
-    <string name="send_custom_notification_to_team">发送给群组</string>
+    <string name="send_custom_notification_to_team">发送给聊天室</string>
 
     <!-- 消息类型 -->
     <string name="msg_type_image">图片</string>

+ 1 - 1
app/res/values/styles-activity.xml

@@ -57,7 +57,7 @@
     <!-- 欢迎界面主题 -->
     <style name="WelcomeEntranceActionBarTheme" parent="AppTheme.NoActionBar">
         <item name="android:windowFullscreen">true</item>
-        <item name="android:windowBackground">@drawable/splash_bg</item>
+        <!--<item name="android:windowBackground">@drawable/splash_bg</item>-->
     </style>
 
     <!-- 搜索界面主题 -->

+ 1 - 1
app/src/com/sheishuo/app/common/imageView/GroupHeadImageView.java

@@ -19,7 +19,7 @@ import java.util.ArrayList;
 import java.util.List;
 
 /**
- * 群组头像合成控件
+ * 聊天室头像合成控件
  * <p/>
  * Created by huangjun on 2015/6/17.
  */

+ 2 - 0
app/src/com/sheishuo/app/common/util/net/NetInfo.java

@@ -16,4 +16,6 @@ public class NetInfo {
     public final static String GET_CODE = INDEX + "?m=who&c=index&a=send_code";
     public final static String UPLOAD_IMG = INDEX + "?m=who&c=social&a=upload";
     public final static String TRADE_LIST = INDEX + "?m=who&c=trade&a=lists";
+    public final static String FOLLOW_TRADE = INDEX + "?m=who&c=trade&a=follow";
+    public final static String UNFOLLOW_TRADE = INDEX + "?m=who&c=trade&a=delete_follow";
 }

+ 6 - 2
app/src/com/sheishuo/app/common/views/BaseToolbar.java

@@ -62,8 +62,6 @@ public class BaseToolbar extends Toolbar {
 
             }
         }
-
-
     }
 
 
@@ -111,6 +109,12 @@ public class BaseToolbar extends Toolbar {
         titleTV.setVisibility(VISIBLE);
     }
 
+    public void setTitle(int resId){
+        String title = getResources().getString(resId);
+        getTitleTV().setText(title);
+        titleTV.setVisibility(VISIBLE);
+    }
+
     public void setLeftText(String leftStr){
         getLeftTV().setText(leftStr);
         leftTV.setVisibility(VISIBLE);

+ 1016 - 0
app/src/com/sheishuo/app/common/views/BottomNavigationViewEx.java

@@ -0,0 +1,1016 @@
+package com.sheishuo.app.common.views;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.Paint;
+import android.graphics.Typeface;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.design.internal.BottomNavigationItemView;
+import android.support.design.internal.BottomNavigationMenuView;
+import android.support.design.widget.BottomNavigationView;
+import android.support.transition.Transition;
+import android.support.transition.TransitionSet;
+import android.support.v4.view.ViewPager;
+import android.util.AttributeSet;
+import android.util.SparseIntArray;
+import android.util.TypedValue;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Field;
+
+/**
+ * Created by KN on 2017/8/3.
+ */
+public class BottomNavigationViewEx extends BottomNavigationView {
+    // used for animation
+    private int mShiftAmount;
+    private float mScaleUpFactor;
+    private float mScaleDownFactor;
+    private boolean animationRecord;
+    private float mLargeLabelSize;
+    private float mSmallLabelSize;
+    private boolean visibilityTextSizeRecord;
+    private boolean visibilityHeightRecord;
+    private int mItemHeight;
+    private boolean textVisibility = true;
+    // used for animation end
+
+    // used for setupWithViewPager
+    private ViewPager mViewPager;
+    private MyOnNavigationItemSelectedListener mMyOnNavigationItemSelectedListener;
+    private BottomNavigationViewExOnPageChangeListener mPageChangeListener;
+    private BottomNavigationMenuView mMenuView;
+    private BottomNavigationItemView[] mButtons;
+    // used for setupWithViewPager end
+
+    public BottomNavigationViewEx(Context context) {
+        super(context);
+        init();
+    }
+
+    public BottomNavigationViewEx(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    public BottomNavigationViewEx(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init();
+    }
+
+    private void init() {
+        try {
+            addAnimationListener();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+
+    private void addAnimationListener() {
+        /**
+         * 1. BottomNavigationMenuView mMenuView
+         * 2. private final BottomNavigationAnimationHelperBase mAnimationHelper;
+         * 3. private final TransitionSet mSet;
+         */
+        BottomNavigationMenuView mMenuView = getBottomNavigationMenuView();
+        Object mAnimationHelper = getField(mMenuView.getClass(), mMenuView, "mAnimationHelper");
+        TransitionSet mSet = getField(mAnimationHelper.getClass(), mAnimationHelper, "mSet");
+        mSet.addListener(new Transition.TransitionListener() {
+            @Override
+            public void onTransitionStart(@NonNull Transition transition) {
+            }
+
+            @Override
+            public void onTransitionEnd(@NonNull Transition transition) {
+                refreshTextViewVisibility();
+            }
+
+            @Override
+            public void onTransitionCancel(@NonNull Transition transition) {
+                refreshTextViewVisibility();
+            }
+
+            @Override
+            public void onTransitionPause(@NonNull Transition transition) {
+            }
+
+            @Override
+            public void onTransitionResume(@NonNull Transition transition) {
+            }
+        });
+    }
+
+    private void refreshTextViewVisibility() {
+        if (!textVisibility)
+            return;
+        // 1. get mMenuView
+        BottomNavigationMenuView mMenuView = getBottomNavigationMenuView();
+        // 2. get mButtons
+        BottomNavigationItemView[] mButtons = getBottomNavigationItemViews();
+
+        int currentItem = getCurrentItem();
+
+        // 3. get field mShiftingMode and TextView in mButtons
+        for (BottomNavigationItemView button : mButtons) {
+            TextView mLargeLabel = getField(button.getClass(), button, "mLargeLabel");
+            TextView mSmallLabel = getField(button.getClass(), button, "mSmallLabel");
+
+            mLargeLabel.clearAnimation();
+            mSmallLabel.clearAnimation();
+
+            // mShiftingMode
+            boolean mShiftingMode = getField(button.getClass(), button, "mShiftingMode");
+            boolean selected = button.getItemPosition() == currentItem;
+            if (mShiftingMode) {
+                if (selected) {
+                    mLargeLabel.setVisibility(VISIBLE);
+                } else {
+                    mLargeLabel.setVisibility(INVISIBLE);
+                }
+                mSmallLabel.setVisibility(INVISIBLE);
+            } else {
+                if (selected) {
+                    mLargeLabel.setVisibility(VISIBLE);
+                    mSmallLabel.setVisibility(INVISIBLE);
+                } else {
+                    mLargeLabel.setVisibility(INVISIBLE);
+                    mSmallLabel.setVisibility(VISIBLE);
+                }
+            }
+        }
+    }
+
+
+    /**
+     * change the visibility of icon
+     *
+     * @param visibility
+     */
+    public void setIconVisibility(boolean visibility) {
+        /*
+        1. get field in this class
+        private final BottomNavigationMenuView mMenuView;
+
+        2. get field in mButtons
+        private BottomNavigationItemView[] mButtons;
+
+        3. get mIcon in mButtons
+        private ImageView mIcon
+
+        4. set mIcon visibility gone
+
+        5. change mItemHeight to only text size in mMenuView
+         */
+        // 1. get mMenuView
+        final BottomNavigationMenuView mMenuView = getBottomNavigationMenuView();
+        // 2. get mButtons
+        BottomNavigationItemView[] mButtons = getBottomNavigationItemViews();
+        // 3. get mIcon in mButtons
+        for (BottomNavigationItemView button : mButtons) {
+            ImageView mIcon = getField(button.getClass(), button, "mIcon");
+            // 4. set mIcon visibility gone
+            mIcon.setVisibility(visibility ? View.VISIBLE : View.INVISIBLE);
+        }
+
+        // 5. change mItemHeight to only text size in mMenuView
+        if (!visibility) {
+            // if not record mItemHeight
+            if (!visibilityHeightRecord) {
+                visibilityHeightRecord = true;
+                mItemHeight = getItemHeight();
+            }
+
+            // change mItemHeight
+            BottomNavigationItemView button = mButtons[0];
+            if (null != button) {
+                final ImageView mIcon = getField(button.getClass(), button, "mIcon");
+//                System.out.println("mIcon.getMeasuredHeight():" + mIcon.getMeasuredHeight());
+                if (null != mIcon) {
+                    mIcon.post(new Runnable() {
+                        @Override
+                        public void run() {
+//                            System.out.println("mIcon.getMeasuredHeight():" + mIcon.getMeasuredHeight());
+                            setItemHeight(mItemHeight - mIcon.getMeasuredHeight());
+                        }
+                    });
+                }
+            }
+        } else {
+            // if not record the mItemHeight, we need do nothing.
+            if (!visibilityHeightRecord)
+                return;
+
+            // restore it
+            setItemHeight(mItemHeight);
+        }
+
+        mMenuView.updateMenuView();
+    }
+
+    /**
+     * change the visibility of text
+     *
+     * @param visibility
+     */
+    public void setTextVisibility(boolean visibility) {
+        this.textVisibility = visibility;
+        /*
+        1. get field in this class
+        private final BottomNavigationMenuView mMenuView;
+
+        2. get field in mButtons
+        private BottomNavigationItemView[] mButtons;
+
+        3. set text size in mButtons
+        private final TextView mLargeLabel
+        private final TextView mSmallLabel
+
+        4. change mItemHeight to only icon size in mMenuView
+         */
+        // 1. get mMenuView
+        BottomNavigationMenuView mMenuView = getBottomNavigationMenuView();
+        // 2. get mButtons
+        BottomNavigationItemView[] mButtons = getBottomNavigationItemViews();
+
+        // 3. change field mShiftingMode value in mButtons
+        for (BottomNavigationItemView button : mButtons) {
+            TextView mLargeLabel = getField(button.getClass(), button, "mLargeLabel");
+            TextView mSmallLabel = getField(button.getClass(), button, "mSmallLabel");
+
+            if (!visibility) {
+                // if not record the font size, record it
+                if (!visibilityTextSizeRecord && !animationRecord) {
+                    visibilityTextSizeRecord = true;
+                    mLargeLabelSize = mLargeLabel.getTextSize();
+                    mSmallLabelSize = mSmallLabel.getTextSize();
+                }
+
+                // if not visitable, set font size to 0
+                mLargeLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX, 0);
+                mSmallLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX, 0);
+
+            } else {
+                // if not record the font size, we need do nothing.
+                if (!visibilityTextSizeRecord)
+                    break;
+
+                // restore it
+                mLargeLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX, mLargeLabelSize);
+                mSmallLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX, mSmallLabelSize);
+            }
+        }
+
+        // 4 change mItemHeight to only icon size in mMenuView
+        if (!visibility) {
+            // if not record mItemHeight
+            if (!visibilityHeightRecord) {
+                visibilityHeightRecord = true;
+                mItemHeight = getItemHeight();
+            }
+
+            // change mItemHeight to only icon size in mMenuView
+            // private final int mItemHeight;
+
+            // change mItemHeight
+//            System.out.println("mLargeLabel.getMeasuredHeight():" + getFontHeight(mSmallLabelSize));
+            setItemHeight(mItemHeight - getFontHeight(mSmallLabelSize));
+
+        } else {
+            // if not record the mItemHeight, we need do nothing.
+            if (!visibilityHeightRecord)
+                return;
+            // restore mItemHeight
+            setItemHeight(mItemHeight);
+        }
+
+        mMenuView.updateMenuView();
+    }
+
+    /**
+     * get text height by font size
+     *
+     * @param fontSize
+     * @return
+     */
+    private static int getFontHeight(float fontSize) {
+        Paint paint = new Paint();
+        paint.setTextSize(fontSize);
+        Paint.FontMetrics fm = paint.getFontMetrics();
+        return (int) Math.ceil(fm.descent - fm.top) + 2;
+    }
+
+    /**
+     * enable or disable click item animation(text scale and icon move animation in no item shifting mode)
+     *
+     * @param enable It means the text won't scale and icon won't move when active it in no item shifting mode if false.
+     */
+    public void enableAnimation(boolean enable) {
+        /*
+        1. get field in this class
+        private final BottomNavigationMenuView mMenuView;
+
+        2. get field in mButtons
+        private BottomNavigationItemView[] mButtons;
+
+        3. chang mShiftAmount to 0 in mButtons
+        private final int mShiftAmount
+
+        change mScaleUpFactor and mScaleDownFactor to 1f in mButtons
+        private final float mScaleUpFactor
+        private final float mScaleDownFactor
+
+        4. change label font size in mButtons
+        private final TextView mLargeLabel
+        private final TextView mSmallLabel
+         */
+
+        // 1. get mMenuView
+        BottomNavigationMenuView mMenuView = getBottomNavigationMenuView();
+        // 2. get mButtons
+        BottomNavigationItemView[] mButtons = getBottomNavigationItemViews();
+        // 3. change field mShiftingMode value in mButtons
+        for (BottomNavigationItemView button : mButtons) {
+            TextView mLargeLabel = getField(button.getClass(), button, "mLargeLabel");
+            TextView mSmallLabel = getField(button.getClass(), button, "mSmallLabel");
+
+            // if disable animation, need animationRecord the source value
+            if (!enable) {
+                if (!animationRecord) {
+                    animationRecord = true;
+                    mShiftAmount = getField(button.getClass(), button, "mShiftAmount");
+                    mScaleUpFactor = getField(button.getClass(), button, "mScaleUpFactor");
+                    mScaleDownFactor = getField(button.getClass(), button, "mScaleDownFactor");
+
+                    mLargeLabelSize = mLargeLabel.getTextSize();
+                    mSmallLabelSize = mSmallLabel.getTextSize();
+
+//                    System.out.println("mShiftAmount:" + mShiftAmount + " mScaleUpFactor:"
+//                            + mScaleUpFactor + " mScaleDownFactor:" + mScaleDownFactor
+//                            + " mLargeLabel:" + mLargeLabelSize + " mSmallLabel:" + mSmallLabelSize);
+                }
+                // disable
+                setField(button.getClass(), button, "mShiftAmount", 0);
+                setField(button.getClass(), button, "mScaleUpFactor", 1);
+                setField(button.getClass(), button, "mScaleDownFactor", 1);
+
+                // let the mLargeLabel font size equal to mSmallLabel
+                mLargeLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX, mSmallLabelSize);
+
+                // debug start
+//                mLargeLabelSize = mLargeLabel.getTextSize();
+//                System.out.println("mLargeLabel:" + mLargeLabelSize);
+                // debug end
+
+            } else {
+                // haven't change the value. It means it was the first call this method. So nothing need to do.
+                if (!animationRecord)
+                    return;
+                // enable animation
+                setField(button.getClass(), button, "mShiftAmount", mShiftAmount);
+                setField(button.getClass(), button, "mScaleUpFactor", mScaleUpFactor);
+                setField(button.getClass(), button, "mScaleDownFactor", mScaleDownFactor);
+                // restore
+                mLargeLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX, mLargeLabelSize);
+            }
+        }
+        mMenuView.updateMenuView();
+    }
+
+    /**
+     * enable the shifting mode for navigation
+     *
+     * @param enable It will has a shift animation if true. Otherwise all items are the same width.
+     */
+    public void enableShiftingMode(boolean enable) {
+        /*
+        1. get field in this class
+        private final BottomNavigationMenuView mMenuView;
+
+        2. change field mShiftingMode value in mMenuView
+        private boolean mShiftingMode = true;
+         */
+        // 1. get mMenuView
+        BottomNavigationMenuView mMenuView = getBottomNavigationMenuView();
+        // 2. change field mShiftingMode value in mMenuView
+        setField(mMenuView.getClass(), mMenuView, "mShiftingMode", enable);
+
+        mMenuView.updateMenuView();
+    }
+
+    /**
+     * enable the shifting mode for each item
+     *
+     * @param enable It will has a shift animation for item if true. Otherwise the item text always be shown.
+     */
+    public void enableItemShiftingMode(boolean enable) {
+        /*
+        1. get field in this class
+        private final BottomNavigationMenuView mMenuView;
+
+        2. get field in this mMenuView
+        private BottomNavigationItemView[] mButtons;
+
+        3. change field mShiftingMode value in mButtons
+        private boolean mShiftingMode = true;
+         */
+        // 1. get mMenuView
+        BottomNavigationMenuView mMenuView = getBottomNavigationMenuView();
+        // 2. get mButtons
+        BottomNavigationItemView[] mButtons = getBottomNavigationItemViews();
+        // 3. change field mShiftingMode value in mButtons
+        for (BottomNavigationItemView button : mButtons) {
+            setField(button.getClass(), button, "mShiftingMode", enable);
+        }
+        mMenuView.updateMenuView();
+    }
+
+    /**
+     * get the current checked item position
+     *
+     * @return index of item, start from 0.
+     */
+    public int getCurrentItem() {
+        /*
+        1. get field in this class
+        private final BottomNavigationMenuView mMenuView;
+
+        2. get field in mMenuView
+        private BottomNavigationItemView[] mButtons;
+
+        3. get menu and traverse it to get the checked one
+         */
+
+        // 1. get mMenuView
+//        BottomNavigationMenuView mMenuView = getBottomNavigationMenuView();
+        // 2. get mButtons
+        BottomNavigationItemView[] mButtons = getBottomNavigationItemViews();
+        // 3. get menu and traverse it to get the checked one
+        Menu menu = getMenu();
+        for (int i = 0; i < mButtons.length; i++) {
+            if (menu.getItem(i).isChecked()) {
+                return i;
+            }
+        }
+        return 0;
+    }
+
+    /**
+     * get menu item position in menu
+     *
+     * @param item
+     * @return position if success, -1 otherwise
+     */
+    public int getMenuItemPosition(MenuItem item) {
+        // get item id
+        int itemId = item.getItemId();
+        // get meunu
+        Menu menu = getMenu();
+        int size = menu.size();
+        for (int i = 0; i < size; i++) {
+            if (menu.getItem(i).getItemId() == itemId) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * set the current checked item
+     *
+     * @param item start from 0.
+     */
+    public void setCurrentItem(int item) {
+        // check bounds
+        if (item < 0 || item >= getMaxItemCount()) {
+            throw new ArrayIndexOutOfBoundsException("item is out of bounds, we expected 0 - "
+                    + (getMaxItemCount() - 1) + ". Actually " + item);
+        }
+
+        /*
+        1. get field in this class
+        private final BottomNavigationMenuView mMenuView;
+
+        2. get field in mMenuView
+        private BottomNavigationItemView[] mButtons;
+        private final OnClickListener mOnClickListener;
+
+        3. call mOnClickListener.onClick();
+         */
+        // 1. get mMenuView
+        BottomNavigationMenuView mMenuView = getBottomNavigationMenuView();
+        // 2. get mButtons
+        BottomNavigationItemView[] mButtons = getBottomNavigationItemViews();
+        // get mOnClickListener
+        View.OnClickListener mOnClickListener = getField(mMenuView.getClass(), mMenuView, "mOnClickListener");
+
+//        System.out.println("mMenuView:" + mMenuView + " mButtons:" + mButtons + " mOnClickListener" + mOnClickListener);
+        // 3. call mOnClickListener.onClick();
+        mOnClickListener.onClick(mButtons[item]);
+
+    }
+
+    /**
+     * get OnNavigationItemSelectedListener
+     *
+     * @return
+     */
+    public OnNavigationItemSelectedListener getOnNavigationItemSelectedListener() {
+        // private OnNavigationItemSelectedListener mListener;
+        OnNavigationItemSelectedListener mListener = getField(BottomNavigationView.class, this, "mSelectedListener");
+        return mListener;
+    }
+
+    @Override
+    public void setOnNavigationItemSelectedListener(@Nullable OnNavigationItemSelectedListener listener) {
+        // if not set up with view pager, the same with father
+        if (null == mMyOnNavigationItemSelectedListener) {
+            super.setOnNavigationItemSelectedListener(listener);
+            return;
+        }
+
+        mMyOnNavigationItemSelectedListener.setOnNavigationItemSelectedListener(listener);
+    }
+
+    /**
+     * get private mMenuView
+     *
+     * @return
+     */
+    private BottomNavigationMenuView getBottomNavigationMenuView() {
+        if (null == mMenuView)
+            mMenuView = getField(BottomNavigationView.class, this, "mMenuView");
+        return mMenuView;
+    }
+
+    /**
+     * get private mButtons in mMenuView
+     *
+     * @return
+     */
+    public BottomNavigationItemView[] getBottomNavigationItemViews() {
+        if (null != mButtons)
+            return mButtons;
+        /*
+         * 1 private final BottomNavigationMenuView mMenuView;
+         * 2 private BottomNavigationItemView[] mButtons;
+         */
+        BottomNavigationMenuView mMenuView = getBottomNavigationMenuView();
+        mButtons = getField(mMenuView.getClass(), mMenuView, "mButtons");
+        return mButtons;
+    }
+
+    /**
+     * get private mButton in mMenuView at position
+     *
+     * @param position
+     * @return
+     */
+    public BottomNavigationItemView getBottomNavigationItemView(int position) {
+        return getBottomNavigationItemViews()[position];
+    }
+
+    /**
+     * get icon at position
+     *
+     * @param position
+     * @return
+     */
+    public ImageView getIconAt(int position) {
+        /*
+         * 1 private final BottomNavigationMenuView mMenuView;
+         * 2 private BottomNavigationItemView[] mButtons;
+         * 3 private ImageView mIcon;
+         */
+        BottomNavigationItemView mButtons = getBottomNavigationItemView(position);
+        ImageView mIcon = getField(BottomNavigationItemView.class, mButtons, "mIcon");
+        return mIcon;
+    }
+
+    /**
+     * get small label at position
+     * Each item has tow label, one is large, another is small.
+     *
+     * @param position
+     * @return
+     */
+    public TextView getSmallLabelAt(int position) {
+        /*
+         * 1 private final BottomNavigationMenuView mMenuView;
+         * 2 private BottomNavigationItemView[] mButtons;
+         * 3 private final TextView mSmallLabel;
+         */
+        BottomNavigationItemView mButtons = getBottomNavigationItemView(position);
+        TextView mSmallLabel = getField(BottomNavigationItemView.class, mButtons, "mSmallLabel");
+        return mSmallLabel;
+    }
+
+    /**
+     * get large label at position
+     * Each item has tow label, one is large, another is small.
+     *
+     * @param position
+     * @return
+     */
+    public TextView getLargeLabelAt(int position) {
+        /*
+         * 1 private final BottomNavigationMenuView mMenuView;
+         * 2 private BottomNavigationItemView[] mButtons;
+         * 3 private final TextView mLargeLabel;
+         */
+        BottomNavigationItemView mButtons = getBottomNavigationItemView(position);
+        TextView mLargeLabel = getField(BottomNavigationItemView.class, mButtons, "mLargeLabel");
+        return mLargeLabel;
+    }
+
+    /**
+     * return item count
+     *
+     * @return
+     */
+    public int getItemCount() {
+        BottomNavigationItemView[] bottomNavigationItemViews = getBottomNavigationItemViews();
+        if (null == bottomNavigationItemViews)
+            return 0;
+        return bottomNavigationItemViews.length;
+    }
+
+    /**
+     * set all item small TextView size
+     * Each item has tow label, one is large, another is small.
+     * Small one will be shown when item state is normal
+     * Large one will be shown when item checked.
+     *
+     * @param sp
+     */
+    public void setSmallTextSize(float sp) {
+        int count = getItemCount();
+        for (int i = 0; i < count; i++) {
+            getSmallLabelAt(i).setTextSize(sp);
+        }
+        mMenuView.updateMenuView();
+    }
+
+    /**
+     * set all item large TextView size
+     * Each item has tow label, one is large, another is small.
+     * Small one will be shown when item state is normal.
+     * Large one will be shown when item checked.
+     *
+     * @param sp
+     */
+    public void setLargeTextSize(float sp) {
+        int count = getItemCount();
+        for (int i = 0; i < count; i++) {
+            getLargeLabelAt(i).setTextSize(sp);
+        }
+        mMenuView.updateMenuView();
+    }
+
+    /**
+     * set all item large and small TextView size
+     * Each item has tow label, one is large, another is small.
+     * Small one will be shown when item state is normal
+     * Large one will be shown when item checked.
+     *
+     * @param sp
+     */
+    public void setTextSize(float sp) {
+        setLargeTextSize(sp);
+        setSmallTextSize(sp);
+    }
+
+    /**
+     * set item ImageView size which at position
+     *
+     * @param position position start from 0
+     * @param width    in dp
+     * @param height   in dp
+     */
+    public void setIconSizeAt(int position, float width, float height) {
+        ImageView icon = getIconAt(position);
+        // update size
+        ViewGroup.LayoutParams layoutParams = icon.getLayoutParams();
+        layoutParams.width = dp2px(getContext(), width);
+        layoutParams.height = dp2px(getContext(), height);
+        icon.setLayoutParams(layoutParams);
+
+        mMenuView.updateMenuView();
+    }
+
+    /**
+     * set all item ImageView size
+     *
+     * @param width  in dp
+     * @param height in dp
+     */
+    public void setIconSize(float width, float height) {
+        int count = getItemCount();
+        for (int i = 0; i < count; i++) {
+            setIconSizeAt(i, width, height);
+        }
+    }
+
+    /**
+     * set menu item height
+     *
+     * @param height in px
+     */
+    public void setItemHeight(int height) {
+        // 1. get mMenuView
+        final BottomNavigationMenuView mMenuView = getBottomNavigationMenuView();
+        // 2. set private final int mItemHeight in mMenuView
+        setField(mMenuView.getClass(), mMenuView, "mItemHeight", height);
+
+        mMenuView.updateMenuView();
+    }
+
+    /**
+     * get menu item height
+     *
+     * @return in px
+     */
+    public int getItemHeight() {
+        // 1. get mMenuView
+        final BottomNavigationMenuView mMenuView = getBottomNavigationMenuView();
+        // 2. get private final int mItemHeight in mMenuView
+        return getField(mMenuView.getClass(), mMenuView, "mItemHeight");
+    }
+
+    /**
+     * dp to px
+     *
+     * @param context
+     * @param dpValue dp
+     * @return px
+     */
+    public static int dp2px(Context context, float dpValue) {
+        final float scale = context.getResources().getDisplayMetrics().density;
+        return (int) (dpValue * scale + 0.5f);
+    }
+
+    /**
+     * set Typeface for all item TextView
+     *
+     * @attr ref android.R.styleable#TextView_typeface
+     * @attr ref android.R.styleable#TextView_textStyle
+     */
+    public void setTypeface(Typeface typeface, int style) {
+        int count = getItemCount();
+        for (int i = 0; i < count; i++) {
+            getLargeLabelAt(i).setTypeface(typeface, style);
+            getSmallLabelAt(i).setTypeface(typeface, style);
+        }
+        mMenuView.updateMenuView();
+    }
+
+    /**
+     * set Typeface for all item TextView
+     *
+     * @attr ref android.R.styleable#TextView_typeface
+     */
+    public void setTypeface(Typeface typeface) {
+        int count = getItemCount();
+        for (int i = 0; i < count; i++) {
+            getLargeLabelAt(i).setTypeface(typeface);
+            getSmallLabelAt(i).setTypeface(typeface);
+        }
+        mMenuView.updateMenuView();
+    }
+
+    /**
+     * get private filed in this specific object
+     *
+     * @param targetClass
+     * @param instance    the filed owner
+     * @param fieldName
+     * @param <T>
+     * @return field if success, null otherwise.
+     */
+    private <T> T getField(Class targetClass, Object instance, String fieldName) {
+        try {
+            Field field = targetClass.getDeclaredField(fieldName);
+            field.setAccessible(true);
+            return (T) field.get(instance);
+        } catch (NoSuchFieldException e) {
+            e.printStackTrace();
+        } catch (IllegalAccessException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * change the field value
+     *
+     * @param targetClass
+     * @param instance    the filed owner
+     * @param fieldName
+     * @param value
+     */
+    private void setField(Class targetClass, Object instance, String fieldName, Object value) {
+        try {
+            Field field = targetClass.getDeclaredField(fieldName);
+            field.setAccessible(true);
+            field.set(instance, value);
+        } catch (NoSuchFieldException e) {
+            e.printStackTrace();
+        } catch (IllegalAccessException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * This method will link the given ViewPager and this BottomNavigationViewEx together so that
+     * changes in one are automatically reflected in the other. This includes scroll state changes
+     * and clicks.
+     *
+     * @param viewPager
+     */
+    public void setupWithViewPager(@Nullable final ViewPager viewPager) {
+        setupWithViewPager(viewPager, false);
+    }
+
+    /**
+     * This method will link the given ViewPager and this BottomNavigationViewEx together so that
+     * changes in one are automatically reflected in the other. This includes scroll state changes
+     * and clicks.
+     *
+     * @param viewPager
+     * @param smoothScroll whether ViewPager changed with smooth scroll animation
+     */
+    public void setupWithViewPager(@Nullable final ViewPager viewPager, boolean smoothScroll) {
+        if (mViewPager != null) {
+            // If we've already been setup with a ViewPager, remove us from it
+            if (mPageChangeListener != null) {
+                mViewPager.removeOnPageChangeListener(mPageChangeListener);
+            }
+        }
+
+        if (null == viewPager) {
+            mViewPager = null;
+            super.setOnNavigationItemSelectedListener(null);
+            return;
+        }
+
+        mViewPager = viewPager;
+
+        // Add our custom OnPageChangeListener to the ViewPager
+        if (mPageChangeListener == null) {
+            mPageChangeListener = new BottomNavigationViewExOnPageChangeListener(this);
+        }
+        viewPager.addOnPageChangeListener(mPageChangeListener);
+
+        // Now we'll add a navigation item selected listener to set ViewPager's current item
+        OnNavigationItemSelectedListener listener = getOnNavigationItemSelectedListener();
+        mMyOnNavigationItemSelectedListener = new MyOnNavigationItemSelectedListener(viewPager, this, smoothScroll, listener);
+        super.setOnNavigationItemSelectedListener(mMyOnNavigationItemSelectedListener);
+    }
+
+    /**
+     * A {@link ViewPager.OnPageChangeListener} class which contains the
+     * necessary calls back to the provided {@link BottomNavigationViewEx} so that the tab position is
+     * kept in sync.
+     * <p>
+     * <p>This class stores the provided BottomNavigationViewEx weakly, meaning that you can use
+     * {@link ViewPager#addOnPageChangeListener(ViewPager.OnPageChangeListener)
+     * addOnPageChangeListener(OnPageChangeListener)} without removing the listener and
+     * not cause a leak.
+     */
+    private static class BottomNavigationViewExOnPageChangeListener implements ViewPager.OnPageChangeListener {
+        private final WeakReference<BottomNavigationViewEx> mBnveRef;
+
+        public BottomNavigationViewExOnPageChangeListener(BottomNavigationViewEx bnve) {
+            mBnveRef = new WeakReference<>(bnve);
+        }
+
+        @Override
+        public void onPageScrollStateChanged(final int state) {
+        }
+
+        @Override
+        public void onPageScrolled(final int position, final float positionOffset,
+                                   final int positionOffsetPixels) {
+        }
+
+        @Override
+        public void onPageSelected(final int position) {
+            final BottomNavigationViewEx bnve = mBnveRef.get();
+            if (null != bnve)
+                bnve.setCurrentItem(position);
+//            Log.d("onPageSelected", "--------- position " + position + " ------------");
+        }
+    }
+
+    /**
+     * Decorate OnNavigationItemSelectedListener for setupWithViewPager
+     */
+    private static class MyOnNavigationItemSelectedListener implements OnNavigationItemSelectedListener {
+        private OnNavigationItemSelectedListener listener;
+        private final WeakReference<ViewPager> viewPagerRef;
+        private boolean smoothScroll;
+        private SparseIntArray items;// used for change ViewPager selected item
+        private int previousPosition = -1;
+
+
+        MyOnNavigationItemSelectedListener(ViewPager viewPager, BottomNavigationViewEx bnve, boolean smoothScroll, OnNavigationItemSelectedListener listener) {
+            this.viewPagerRef = new WeakReference<>(viewPager);
+            this.listener = listener;
+            this.smoothScroll = smoothScroll;
+
+            // create items
+            Menu menu = bnve.getMenu();
+            int size = menu.size();
+            items = new SparseIntArray(size);
+            for (int i = 0; i < size; i++) {
+                int itemId = menu.getItem(i).getItemId();
+                items.put(itemId, i);
+            }
+        }
+
+        public void setOnNavigationItemSelectedListener(OnNavigationItemSelectedListener listener) {
+            this.listener = listener;
+        }
+
+        @Override
+        public boolean onNavigationItemSelected(@NonNull MenuItem item) {
+            int position = items.get(item.getItemId());
+            // only set item when item changed
+            if (previousPosition == position) {
+                return true;
+            }
+
+            // user listener
+            if (null != listener) {
+                boolean bool = listener.onNavigationItemSelected(item);
+                // if the selected is invalid, no need change the view pager
+                if (!bool)
+                    return false;
+            }
+
+            // change view pager
+            ViewPager viewPager = viewPagerRef.get();
+            if (null == viewPager)
+                return false;
+
+            viewPager.setCurrentItem(items.get(item.getItemId()), smoothScroll);
+
+            // update previous position
+            previousPosition = position;
+
+            return true;
+        }
+
+    }
+
+    public void enableShiftingMode(int position, boolean enable) {
+        getBottomNavigationItemView(position).setShiftingMode(enable);
+    }
+
+    public void setItemBackground(int position, int background) {
+        getBottomNavigationItemView(position).setItemBackground(background);
+    }
+
+    public void setIconTintList(int position, ColorStateList tint) {
+        getBottomNavigationItemView(position).setIconTintList(tint);
+    }
+
+    public void setTextTintList(int position, ColorStateList tint) {
+        getBottomNavigationItemView(position).setTextColor(tint);
+    }
+
+    /**
+     * 设置所有ico上边距
+     *
+     * @param marginTop in px
+     */
+    public void setIconsMarginTop(int marginTop) {
+        for (int i = 0; i < getItemCount(); i++) {
+            setIconMarginTop(i, marginTop);
+        }
+    }
+
+    /**
+     * 设置单个ico上边距
+     *
+     * @param position
+     * @param marginTop in px
+     */
+    public void setIconMarginTop(int position, int marginTop) {
+        /*
+        1. BottomNavigationItemView
+        2. private final int mDefaultMargin;
+         */
+        BottomNavigationItemView itemView = getBottomNavigationItemView(position);
+        setField(BottomNavigationItemView.class, itemView, "mDefaultMargin", marginTop);
+        mMenuView.updateMenuView();
+    }
+
+}

+ 13 - 8
app/src/com/sheishuo/app/common/views/ImgGridView.java

@@ -9,8 +9,11 @@ import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.widget.GridView;
 
+import com.sheishuo.app.common.util.img.ImgUtil;
+
 
 public class ImgGridView extends GridView {
+    private Context context;
 
     @Override
     public boolean dispatchTouchEvent(MotionEvent ev) {
@@ -20,23 +23,27 @@ public class ImgGridView extends GridView {
 
     public ImgGridView(Context context) {
         super(context);
+        this.context = context;
     }
 
 
     public ImgGridView(Context context, AttributeSet attrs) {
         super(context, attrs);
+        this.context = context;
+
     }
 
 
     public ImgGridView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
+        this.context = context;
+
     }
 
 
     @Override
 
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-
         int heightSpec,widthSpec;
 
 
@@ -45,17 +52,15 @@ public class ImgGridView extends GridView {
         } else {
             heightSpec = heightMeasureSpec;
         }
+        super.onMeasure(widthMeasureSpec, heightSpec);
+
+
+        this.setHorizontalSpacing((int) ImgUtil.convertDpToPixel(4,context));
+        this.setVerticalSpacing((int) ImgUtil.convertDpToPixel(4,context));
 
 
-//        int childCount = this.getChildCount();
-//        if (childCount >= 5){
-//            widthSpec = 128 * 3;
-//        }else {
-//            widthSpec = 128 * 2;
-//        }
 
 
-        super.onMeasure(widthMeasureSpec, heightSpec);
 
     }
 

+ 9 - 0
app/src/com/sheishuo/app/common/views/PartlyHighLightTextView.java

@@ -60,4 +60,13 @@ public class PartlyHighLightTextView extends android.support.v7.widget.AppCompat
 
         this.setText(span);
     }
+
+    public void addHightlightStr(String str,int highlightColor){
+        String oldContent = this.getText().toString();
+
+        String text = str + oldContent;
+        Spannable span = new SpannableString(text);
+        span.setSpan(new ForegroundColorSpan(getResources().getColor(highlightColor)), 0, str.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+        this.setText(span);
+    }
 }

+ 14 - 2
app/src/com/sheishuo/app/core_module/recent_contacts/activity/ContactsListActivity.java

@@ -7,6 +7,7 @@ import android.widget.LinearLayout;
 
 import com.netease.nim.uikit.contact.ContactsFragment;
 import com.sheishuo.app.R;
+import com.sheishuo.app.common.views.BaseToolbar;
 import com.sheishuo.app.uikit_implements.SheishuoUI;
 
 /**
@@ -18,6 +19,7 @@ public class ContactsListActivity extends SheishuoUI {
     private LinearLayout layout;
     private FragmentManager manager = getSupportFragmentManager();
     private FragmentTransaction transaction;
+    private BaseToolbar toolbar;
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -26,11 +28,14 @@ public class ContactsListActivity extends SheishuoUI {
         init();
     }
 
-    void findViews(){
+    private void findViews(){
+        toolbar = findView(R.id.toolbar);
         layout = findView(R.id.recent_contacts_list_layout);
     }
 
-    void init(){
+
+    private void init(){
+        initToolbar();
         if (manager != null){
             ContactsFragment fragment  = new ContactsFragment();
             transaction = manager.beginTransaction();
@@ -39,4 +44,11 @@ public class ContactsListActivity extends SheishuoUI {
         }
 
     }
+
+
+
+    private void initToolbar(){
+        toolbar.init();
+        toolbar.setTitle("联系人");
+    }
 }

+ 98 - 1
app/src/com/sheishuo/app/core_module/trade/model/TradeModel.java

@@ -1,12 +1,19 @@
 package com.sheishuo.app.core_module.trade.model;
 
+import android.util.Log;
+
+import com.google.gson.Gson;
 import com.sheishuo.app.cache.AccountCache;
+import com.sheishuo.app.common.beans.TradeBean;
 import com.sheishuo.app.common.util.net.INet;
 import com.sheishuo.app.common.util.net.NetImpl;
 import com.sheishuo.app.common.util.net.NetInfo;
 import com.sheishuo.app.common.util.net.ResponseCallback;
 import com.sheishuo.app.core_module.trade.presenter.TradePresenter;
 
+import org.json.JSONException;
+import org.json.JSONObject;
+
 import okhttp3.FormBody;
 
 /**
@@ -30,9 +37,15 @@ public class TradeModel {
         net = new NetImpl();
     }
 
+
+    /**
+     * 加载便民帖列表
+     * @param type  分类
+     * @param page  第几页
+     */
     public void loadTradeList(int type,int page){
         final FormBody body = new FormBody.Builder()
-                .add("id", AccountCache.getAccount().getId())
+                .add("user_id", AccountCache.getAccount().getId())
                 .add("province", AccountCache.getAccount().getProvince())
                 .add("page", String.valueOf(page))
                 .add("sort", String.valueOf(type))
@@ -44,6 +57,54 @@ public class TradeModel {
                 net.post(NetInfo.TRADE_LIST, body, new ResponseCallback() {
                     @Override
                     public void onSuccess(Object object) {
+                        String json = (String)object;
+                        TradeBean bean = new Gson().fromJson(json,TradeBean.class);
+                        if (0 == bean.getD().getList().size()){
+                            presenter.showToast("无更多内容");
+                        }else {
+                            try {
+                                Log.e("Test",new JSONObject(json).toString());
+                            } catch (JSONException e) {
+                                e.printStackTrace();
+                            }
+                            presenter.onPageLoaded(bean);
+                        }
+                    }
+
+                    @Override
+                    public void onFailed() {
+                        presenter.showToast("加载失败,请检查网络");
+                    }
+                });
+            }
+        }).start();
+
+    }
+
+    public void followTrade(final String tradeId){
+        final FormBody body = new FormBody.Builder()
+                .add("user_id",AccountCache.getAccount().getId())
+                .add("trade_id", tradeId)
+                .build();
+
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+                net.post(NetInfo.FOLLOW_TRADE, body, new ResponseCallback() {
+                    @Override
+                    public void onSuccess(Object object) {
+                        try {
+                            JSONObject jsonObject = new JSONObject((String)object);
+                            Log.e("json",jsonObject.toString());
+                            if (jsonObject.getJSONObject("d").getBoolean("id")){
+                                presenter.onFollowTradeSuccess(tradeId);
+                            }else {
+                                presenter.showToast("关注便民帖失败");
+                            }
+                        } catch (Exception e) {
+                            e.printStackTrace();
+                            presenter.showToast("关注便民帖失败");
+                        }
 
                     }
 
@@ -54,6 +115,42 @@ public class TradeModel {
                 });
             }
         }).start();
+    }
+
+
+    public void unfollowTrade(final String tradeId){
+        final FormBody body = new FormBody.Builder()
+                .add("user_id",AccountCache.getAccount().getId())
+                .add("trade_id", tradeId)
+                .build();
 
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+                net.post(NetInfo.UNFOLLOW_TRADE, body, new ResponseCallback() {
+                    @Override
+                    public void onSuccess(Object object) {
+                        try {
+                            JSONObject jsonObject = new JSONObject((String)object);
+                            Log.e("json",jsonObject.toString());
+                            if (jsonObject.getJSONObject("d").getBoolean("result")){
+                                presenter.onUnfollowTradeSuccess(tradeId);
+                            }else {
+                                presenter.showToast("取消关注便民帖失败");
+                            }
+                        } catch (Exception e) {
+                            e.printStackTrace();
+                            presenter.showToast("取消关注便民帖失败");
+                        }
+
+                    }
+
+                    @Override
+                    public void onFailed() {
+
+                    }
+                });
+            }
+        }).start();
     }
 }

+ 21 - 0
app/src/com/sheishuo/app/core_module/trade/presenter/TradePresenter.java

@@ -1,5 +1,6 @@
 package com.sheishuo.app.core_module.trade.presenter;
 
+import com.sheishuo.app.common.beans.TradeBean;
 import com.sheishuo.app.core_module.trade.model.TradeModel;
 import com.sheishuo.app.main.fragment.TradeListFragment;
 
@@ -14,12 +15,32 @@ public class TradePresenter {
     public TradePresenter(TradeListFragment fragment){
         this.fragment = fragment;
         model = new TradeModel(this);
+
     }
 
 
     public void loadTradeList(int type,int page){
         model.loadTradeList(type,page);
     }
+    public void onPageLoaded(TradeBean bean){
+        fragment.onPageLoaded(bean);
+    }
+
+    public void followTrade(String id){
+        model.followTrade(id);
+    }
+    public void unfollowTrade(String id){
+        model.unfollowTrade(id);
+    }
+    public void onFollowTradeSuccess(String id){
+        fragment.onFollowTradeSuccess(id);
+    }
+    public void onUnfollowTradeSuccess(String id){
+        fragment.onUnfollowTradeSuccess(id);
+    }
+    public void showToast(String str){
+        fragment.showToast(str);
+    }
 
 
 }

+ 266 - 0
app/src/com/sheishuo/app/core_module/trade/view/adapter/TradeItemAdapter.java

@@ -0,0 +1,266 @@
+package com.sheishuo.app.core_module.trade.view.adapter;
+
+import android.content.Context;
+import android.support.annotation.Nullable;
+import android.support.constraint.ConstraintLayout;
+import android.support.v7.widget.CardView;
+import android.support.v7.widget.RecyclerView;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.GridLayout;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.bumptech.glide.Glide;
+import com.netease.nimlib.sdk.NIMClient;
+import com.netease.nimlib.sdk.RequestCallback;
+import com.netease.nimlib.sdk.uinfo.UserService;
+import com.netease.nimlib.sdk.uinfo.model.NimUserInfo;
+import com.sheishuo.app.R;
+import com.sheishuo.app.cache.AccountCache;
+import com.sheishuo.app.common.beans.TradeBean;
+import com.sheishuo.app.common.util.img.ImgUtil;
+import com.sheishuo.app.common.views.GridViewAdapter;
+import com.sheishuo.app.common.views.ImgGridView;
+import com.sheishuo.app.common.views.PartlyHighLightTextView;
+import com.sheishuo.app.login.beans.LoginBean;
+import com.sheishuo.app.main.fragment.TradeListFragment;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Created by KN on 2017/8/1.
+ */
+
+public class TradeItemAdapter extends RecyclerView.Adapter<TradeItemAdapter.TradeItemViewHolder> implements View.OnClickListener{
+
+    public static final String PRIORITY_DISTRICT = "3"
+            ,PRIORITY_CITY = "2"
+            ,PRIORITY_PROVINCE = "1"
+            ,PRIORITY_COUNTRY = "0";
+
+    private List<TradeBean.DBean.ListBean> data;
+    private Context context;
+    private TradeListFragment fragment;
+    private OnTradeItemClickListener listener;
+
+    public TradeItemAdapter(TradeListFragment fragment,TradeBean bean){
+        data = new ArrayList<>();
+        this.fragment = fragment;
+        context = fragment.getActivity();
+        addAll(bean);
+    }
+
+    @Override
+    public TradeItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.trade_list_item,parent,false);
+        return new TradeItemViewHolder(view);
+    }
+
+    @Override
+    public void onBindViewHolder(TradeItemViewHolder holder, int position) {
+        TradeBean.DBean.ListBean bean = data.get(position);
+
+        //设置item点击事件
+        holder.layout.setTag(bean);
+        holder.layout.setOnClickListener(this);
+
+        //加载用户头像
+        String avatarUrl = NIMClient.getService(UserService.class).getUserInfo(bean.getUser_id()).getAvatar();
+        if (avatarUrl != null)
+            Glide.with(context).load(avatarUrl).into(holder.avatarImg);
+
+        //设置交易帖内容和地区标注
+        holder.content.setText(bean.getMsg());
+        String highLightStr = "";
+        if (!bean.getCity().isEmpty()){
+            highLightStr = "[" + bean.getCity() + "]";
+        }
+        if (!bean.getDistrict().isEmpty()){
+            highLightStr = highLightStr + "[" + bean.getDistrict() + "]";
+        }
+        if (!highLightStr.isEmpty()){
+            holder.content.addHightlightStr(highLightStr,R.color.green_4DC0A4);
+        }
+
+
+        holder.userName.setText(getUserName(bean.getUser_id()));
+        holder.date.setText(bean.getInputtime());
+
+        //判断有无置顶加权
+        switch (bean.getPriority_type()){
+            case PRIORITY_DISTRICT:
+                holder.priority.setText("地区 " + bean.getPriority());
+                break;
+            case PRIORITY_CITY:
+                holder.priority.setText("城市 " + bean.getPriority());
+                break;
+            case PRIORITY_PROVINCE:
+                holder.priority.setText("省份 " + bean.getPriority());
+                break;
+            case PRIORITY_COUNTRY:
+                holder.priority.setText("国家 " + bean.getPriority());
+                break;
+        }
+
+        //判断是否已加关注
+        if (1 == bean.getFollow()){
+            Glide.with(context).load(R.drawable.trade_followed).into(holder.followImg);
+            holder.followImg.setTag(R.drawable.trade_followed,bean.getId());
+            holder.followImg.setOnClickListener(this);
+        }else {
+            holder.followImg.setTag(R.drawable.trade_unfollowed,bean.getId());
+            holder.followImg.setOnClickListener(this);
+        }
+
+        //设置浏览量
+        holder.review.setText("浏览"+bean.getReview());
+
+        //加载thumbs
+        GridViewAdapter gridViewAdapter = new GridViewAdapter(bean.getThumbs());
+        if (bean.getThumbs().size() > 4){
+            //默认为两列,如果超过4张图则显示为3列
+            holder.imgGridView.setNumColumns(3);
+        }else {
+            holder.imgGridView.setNumColumns(2);
+        }
+        holder.imgGridView.setAdapter(gridViewAdapter);
+
+
+
+
+        //预加载
+        if (position >= data.size() - 1){
+            fragment.loadTradeList(fragment.TYPE_TO_LOAD,fragment.PAGE_TO_LOAD);
+        }
+    }
+
+    @Override
+    public int getItemCount() {
+        return data.size();
+    }
+
+    @Override
+    public void onViewRecycled(TradeItemViewHolder holder) {
+        super.onViewRecycled(holder);
+        //清空followImg设置的Tag
+        holder.followImg.setTag(R.drawable.trade_followed,null);
+        holder.followImg.setTag(R.drawable.trade_unfollowed,null);
+        Glide.with(context).load(R.drawable.trade_unfollowed).into(holder.followImg);
+    }
+
+
+    @Override
+    public void onClick(View view) {
+        if (listener != null)listener.onClick(view);
+    }
+
+
+    //添加数据
+    public void addAll(TradeBean bean){
+        final List<TradeBean.DBean.ListBean> datas = bean.getD().getList();
+
+
+        //将数据中的所有用户ID存入List
+        List<String> userIds = new ArrayList<>();
+        //遍历发布者ID
+        for (TradeBean.DBean.ListBean data : datas){
+            if (!userIds.contains(data.getUser_id()))
+                userIds.add(data.getUser_id());
+        }
+
+        NIMClient.getService(UserService.class).fetchUserInfo(userIds).setCallback(new RequestCallback<List<NimUserInfo>>() {
+            @Override
+            public void onSuccess(List<NimUserInfo> nimUserInfos) {
+                //添加数据
+                data.addAll(datas);
+                notifyDataSetChanged();
+                Log.e("添加数据成功","Success");
+            }
+
+            @Override
+            public void onFailed(int i) {
+                Log.e("Failed",i+"");
+            }
+
+            @Override
+            public void onException(Throwable throwable) {
+
+            }
+        });
+
+    }
+
+    //设置Item点击监听事件
+    public void setOnTradeItemClickListener(OnTradeItemClickListener listener){
+        this.listener = listener;
+    }
+
+    //有用户名返回用户名,无用户名返回用户ID
+    private String getUserName(String userId){
+        if (NIMClient.getService(UserService.class).getUserInfo(userId) != null) {
+            String name = NIMClient.getService(UserService.class).getUserInfo(userId).getName();
+            if (name.equals("")){
+                return userId;
+            }else {
+                return name;
+            }
+        }
+        return "";
+
+    }
+
+    //用于更新本地缓存,标注已关注的帖子
+    public void setFollowed(String id){
+        for (TradeBean.DBean.ListBean bean: data){
+            if (id.equals(bean.getId())){
+                bean.setFollow(1);
+                Log.e("notifyDataSetChanged", "    true");
+                notifyDataSetChanged();
+                break;
+            }
+        }
+    }
+    //用于更新本地缓存,标注取消关注的帖子
+    public void setUnfollowed(String id){
+        for (TradeBean.DBean.ListBean bean: data){
+            if (id.equals(bean.getId())){
+                bean.setFollow(0);
+                Log.e("notifyDataSetChanged", "    true");
+                notifyDataSetChanged();
+                break;
+            }
+        }
+    }
+
+
+    class TradeItemViewHolder extends RecyclerView.ViewHolder{
+        private CardView layout;
+        private ImageView avatarImg,followImg;
+        private TextView userName,date,priority,review;
+        private PartlyHighLightTextView content;
+        private ImgGridView imgGridView;
+        public TradeItemViewHolder(View view) {
+            super(view);
+            layout = (CardView) view.findViewById(R.id.trade_list_item_layout);
+            avatarImg = (ImageView) view.findViewById(R.id.trade_list_item_avatar);
+            followImg = (ImageView) view.findViewById(R.id.trade_list_item_follow_img);
+            userName = (TextView) view.findViewById(R.id.trade_list_item_name);
+            date = (TextView) view.findViewById(R.id.trade_list_item_date);
+            content = (PartlyHighLightTextView) view.findViewById(R.id.trade_list_item_content);
+            priority = (TextView) view.findViewById(R.id.trade_list_item_priority);
+            review = (TextView) view.findViewById(R.id.trade_list_item_views);
+            imgGridView = (ImgGridView) view.findViewById(R.id.trade_list_item_imgs_gridview);
+        }
+    }
+
+
+    public interface OnTradeItemClickListener{
+        void onClick(View view);
+    }
+}

+ 1 - 1
app/src/com/sheishuo/app/main/activity/GlobalSearchActivity.java

@@ -164,7 +164,7 @@ public class GlobalSearchActivity extends UI implements OnItemClickListener {
 
         SearchGroupStrategy() {
             add(ContactGroupStrategy.GROUP_NULL, 0, "");
-            add(GROUP_TEAM, 1, "群组");
+            add(GROUP_TEAM, 1, "聊天室");
             add(GROUP_FRIEND, 2, "好友");
             add(GROUP_MSG, 3, "聊天记录");
         }

+ 1 - 1
app/src/com/sheishuo/app/main/activity/WelcomeActivity.java

@@ -167,7 +167,7 @@ public class WelcomeActivity extends UI {
      * 首次进入,打开欢迎界面
      */
     private void showSplashView() {
-        getWindow().setBackgroundDrawableResource(R.drawable.splash_bg);
+        //getWindow().setBackgroundDrawableResource(R.drawable.splash_bg);
         customSplash = true;
     }
 

+ 15 - 8
app/src/com/sheishuo/app/main/adapter/CircleListAdapter.java

@@ -45,6 +45,7 @@ public class CircleListAdapter  extends RecyclerView.Adapter<CircleListAdapter.C
     private OnCircleItemClickListener listener;
     private Context context;
     private CircleOfFriendsFragment circleFragment;
+    private Boolean FLAGS_ALL_LOADED = false;
 
     public CircleListAdapter(CircleOfFriendsFragment fragment,CircleBean bean){
         data = new ArrayList<>();
@@ -56,7 +57,7 @@ public class CircleListAdapter  extends RecyclerView.Adapter<CircleListAdapter.C
 
     @Override
     public CircleListViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.circle_item,null);
+        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.circle_item,parent,false);
         return new CircleListViewHolder(view);
     }
 
@@ -173,16 +174,15 @@ public class CircleListAdapter  extends RecyclerView.Adapter<CircleListAdapter.C
 
 
         //判断是否需要加载更多评论
-        //判断标志为缓存的Holder小于两个且最底部的Item ID不为"1"时则自动加载
-        if (position > data.size() - 2 && !data.get(data.size() - 1).getId().equals("1")) {
-            Log.e("CircleListAdapter",data.get(data.size() - 1).getId());
+        //判断标志为缓存的Holder小于两个且最底部的Item
+        if (position > data.size() - 2 && !FLAGS_ALL_LOADED) {
+            Log.e("LOAED_ALL", String.valueOf(FLAGS_ALL_LOADED));
             circleFragment.loadCircleListMore(data.get(data.size() - 1).getId());
-        }else if(data.get(data.size() - 1).getId().equals("1")){
+        }else if (FLAGS_ALL_LOADED){
             circleFragment.showToast("已无更多内容");
         }
 
 
-
     }
 
 
@@ -210,7 +210,7 @@ public class CircleListAdapter  extends RecyclerView.Adapter<CircleListAdapter.C
     private String getUserName(String userId){
         if (NIMClient.getService(UserService.class).getUserInfo(userId) != null) {
             String name = NIMClient.getService(UserService.class).getUserInfo(userId).getName();
-            if (name.equals("")){
+            if (name.isEmpty()){
                 return userId;
             }else {
                 return name;
@@ -230,7 +230,10 @@ public class CircleListAdapter  extends RecyclerView.Adapter<CircleListAdapter.C
     //添加数据
     public void addAll(CircleBean bean){
         final List<CircleBean.DBean.ListBean> datas = bean.getD().getList();
-
+        if (0 == datas.size()){
+            FLAGS_ALL_LOADED = true;
+            return;
+        }
 
         //将数据中的所有用户ID存入List
         List<String> userIds = new ArrayList<>();
@@ -276,7 +279,11 @@ public class CircleListAdapter  extends RecyclerView.Adapter<CircleListAdapter.C
     //清空数据
     public void clearAll(){
         data.clear();
+        FLAGS_ALL_LOADED = false;
+        notifyDataSetChanged();
     }
+
+
     //点击事件
     @Override
     public void onClick(View v) {

+ 4 - 2
app/src/com/sheishuo/app/main/fragment/AreaGroupsFragment.java

@@ -13,6 +13,7 @@ import com.netease.nim.uikit.contact_selector.activity.ContactSelectActivity;
 import com.netease.nim.uikit.team.helper.TeamHelper;
 import com.netease.nimlib.sdk.NIMClient;
 import com.netease.nimlib.sdk.team.TeamService;
+import com.netease.nimlib.sdk.team.constant.TeamFieldEnum;
 import com.sheishuo.app.cache.AccountCache;
 import com.sheishuo.app.R;
 import com.sheishuo.app.cache.GiftCache;
@@ -72,7 +73,7 @@ public class AreaGroupsFragment extends MainTabFragment {
     //初始化Toolbar
     void initToolbar(){
         toolbar.init();
-        toolbar.setTitle("群组");
+        toolbar.setTitle("谁说");
         LoginBean.DBean account = AccountCache.getAccount();
         toolbar.setLeftText(account.getCity() + account.getDistrict());
         toolbar.setRightText("创建");
@@ -80,11 +81,12 @@ public class AreaGroupsFragment extends MainTabFragment {
             @Override
             public void onClick(View v) {
                 ContactSelectActivity.startActivityForResult(getActivity(), TeamHelper.getContactSelectOption(null), MainActivity.REQUEST_CODE_ADVANCED);
+
             }
         });
     }
 
-    //加载群组信息
+    //加载聊天室信息
     void loadGroups(){
         List<String> groupIds = new ArrayList<>();
         List<String> tempList = new ArrayList<>();

+ 1 - 1
app/src/com/sheishuo/app/main/fragment/ChatRoomListFragment.java

@@ -11,7 +11,7 @@ import com.sheishuo.app.R;
 public class ChatRoomListFragment extends MainTabFragment {
     private ChatRoomsFragment fragment;
     public ChatRoomListFragment() {
-        setContainerId(MainTab.CHAT_ROOM.fragmentId);
+        //setContainerId(MainTab.CHAT_ROOM.fragmentId);
     }
 
     @Override

+ 4 - 0
app/src/com/sheishuo/app/main/fragment/CircleOfFriendsFragment.java

@@ -18,6 +18,7 @@ import com.netease.nimlib.sdk.uinfo.model.NimUserInfo;
 import com.sheishuo.app.cache.AccountCache;
 import com.sheishuo.app.R;
 import com.sheishuo.app.SheishuoApplication;
+import com.sheishuo.app.common.util.net.NetStatus;
 import com.sheishuo.app.core_module.circle.activity.NewTweetingActivity;
 import com.sheishuo.app.common.beans.CircleBean;
 import com.sheishuo.app.common.views.BaseToolbar;
@@ -138,6 +139,9 @@ public class CircleOfFriendsFragment extends MainTabFragment{
         if (isVisibleToUser && toolbar != null) initToolbar();
 
         if (isVisibleToUser && isLoaded) refreshCircle();
+
+
+        NetStatus.IS_BUSY = false;
     }
 
     /**********************以下为开放调用的方法*********************/

+ 16 - 3
app/src/com/sheishuo/app/main/fragment/HomeFragment.java

@@ -5,6 +5,7 @@ import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
 import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.support.design.widget.BottomNavigationView;
 import android.support.v4.app.Fragment;
 import android.support.v4.view.ViewPager;
@@ -12,6 +13,8 @@ import android.support.v4.view.ViewPager.OnPageChangeListener;
 import android.support.v7.widget.Toolbar;
 import android.util.Log;
 import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
@@ -33,6 +36,7 @@ import com.sheishuo.app.cache.AccountCache;
 import com.sheishuo.app.R;
 import com.sheishuo.app.common.ui.viewpager.FadeInOutPageTransformer;
 import com.sheishuo.app.common.ui.viewpager.PagerSlidingTabStrip;
+import com.sheishuo.app.common.views.BottomNavigationViewEx;
 import com.sheishuo.app.main.activity.MainActivity;
 import com.sheishuo.app.main.adapter.MainTabPagerAdapter;
 import com.sheishuo.app.main.helper.SystemMessageUnreadManager;
@@ -64,7 +68,7 @@ public class HomeFragment extends TFragment implements OnPageChangeListener, Rem
 
     private View rootView;
 
-    private BottomNavigationView navigationView;
+    private BottomNavigationViewEx navigationView;
 
     private List<Integer> navigationbarItemList = new ArrayList<>();
 
@@ -84,7 +88,7 @@ public class HomeFragment extends TFragment implements OnPageChangeListener, Rem
 
 
         findViews();
-        initNavigationView();
+        initBottomNavigationView();
         setupPager();
         setupTabs();
         registerMsgUnreadInfoObserver(true);
@@ -123,7 +127,7 @@ public class HomeFragment extends TFragment implements OnPageChangeListener, Rem
     }
 
     //初始化BottomNavigationView
-    public void initNavigationView(){
+    public void initBottomNavigationView(){
         navigationbarItemList.add(R.id.main_navi_groups);
         navigationbarItemList.add(R.id.main_navi_friends);
         navigationbarItemList.add(R.id.main_navi_trade);
@@ -143,6 +147,13 @@ public class HomeFragment extends TFragment implements OnPageChangeListener, Rem
                 }
             });
         }
+
+
+        //设置BottomNavigationViewEx
+        navigationView.enableAnimation(false);
+        navigationView.enableShiftingMode(false);
+        navigationView.enableItemShiftingMode(false);
+
     }
 
 
@@ -211,6 +222,8 @@ public class HomeFragment extends TFragment implements OnPageChangeListener, Rem
         setToolBar(toolbar);
     }
 
+
+
     @Override
     public void onResume() {
         super.onResume();

+ 12 - 1
app/src/com/sheishuo/app/main/fragment/SessionListFragment.java

@@ -34,6 +34,7 @@ import com.sheishuo.app.config.preference.Preferences;
 import com.sheishuo.app.core_module.recent_contacts.activity.ContactsListActivity;
 import com.sheishuo.app.login.LoginActivity;
 import com.sheishuo.app.login.LogoutHelperBak;
+import com.sheishuo.app.main.activity.GlobalSearchActivity;
 import com.sheishuo.app.main.activity.MainActivity;
 import com.sheishuo.app.main.activity.MultiportActivity;
 import com.sheishuo.app.main.model.MainTab;
@@ -68,6 +69,8 @@ public class SessionListFragment extends MainTabFragment {
 
     private MainActivity parent;
 
+    private TextView searchTV;
+
     public SessionListFragment() {
         this.setContainerId(MainTab.RECENT_CONTACTS.fragmentId);
     }
@@ -93,6 +96,14 @@ public class SessionListFragment extends MainTabFragment {
         addRecentContactsFragment();
 
         initToolbar();
+
+
+        searchTV.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                GlobalSearchActivity.start(getActivity());
+            }
+        });
     }
 
     private void registerObservers(boolean register) {
@@ -103,7 +114,7 @@ public class SessionListFragment extends MainTabFragment {
     private void findViews() {
         parent = (MainActivity) getActivity();
         toolbar = (BaseToolbar) parent.getToolBar();
-
+        searchTV = (TextView) getView().findViewById(R.id.session_list_search_tv);
 
         notifyBar = getView().findViewById(R.id.status_notify_bar);
         notifyBarText = (TextView) getView().findViewById(R.id.status_desc_label);

+ 172 - 2
app/src/com/sheishuo/app/main/fragment/TradeListFragment.java

@@ -1,6 +1,23 @@
 package com.sheishuo.app.main.fragment;
 
+import android.os.Handler;
+import android.support.v7.widget.CardView;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.util.Log;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.Toast;
+
+import com.sheishuo.app.R;
+import com.sheishuo.app.cache.AccountCache;
+import com.sheishuo.app.common.beans.TradeBean;
+import com.sheishuo.app.common.views.BaseToolbar;
+import com.sheishuo.app.core_module.trade.model.TradeModel;
 import com.sheishuo.app.core_module.trade.presenter.TradePresenter;
+import com.sheishuo.app.core_module.trade.view.adapter.TradeItemAdapter;
+import com.sheishuo.app.main.activity.MainActivity;
 
 /**
  * Created by KN on 2017/7/31.
@@ -9,11 +26,164 @@ import com.sheishuo.app.core_module.trade.presenter.TradePresenter;
 public class TradeListFragment extends MainTabFragment {
 
     private String TAG = this.getClass().getSimpleName();
-
     private TradePresenter presenter;
+
+    private Handler handler;
+    private MainActivity parent;
+    private BaseToolbar toolbar;
+    private Toast toast;
+
+
+    //Views
+    private LinearLayout notificationLayout;
+    private RecyclerView recyclerview;
+    private TradeItemAdapter adapter;
+    private LinearLayoutManager layoutManager;
+
+    /**
+     * FLAGS
+     */
+    public int PAGE_TO_LOAD = 1;
+    public int TYPE_TO_LOAD = TradeModel.TYPE_ALL;
+
+
     @Override
     protected void onInit() {
         presenter = new TradePresenter(this);
+        findViews();
+        init();
+    }
+
+
+
+    private void findViews(){
+        notificationLayout = findView(R.id.trade_list_notifications_layout);
+        recyclerview = findView(R.id.trade_list_recyclerview);
+        handler = getHandler();
+        parent = (MainActivity) getActivity();
+        toolbar = (BaseToolbar) parent.getToolBar();
     }
-    
+
+    private void init(){
+        initToolbar();
+        layoutManager = new LinearLayoutManager(getActivity());
+        loadTradeList(TYPE_TO_LOAD,PAGE_TO_LOAD);
+    }
+
+    private void initToolbar(){
+        toolbar.init();
+        toolbar.setTitle(R.string.main_tab_trade);
+        toolbar.setLeftText(AccountCache.getAccount().getCity() + AccountCache.getAccount().getDistrict());
+        toolbar.setRightText("筛选");
+    }
+
+
+    public void loadTradeList(int type,int page){
+        presenter.loadTradeList(type,page);
+    }
+
+
+    private void setupAdapter(){
+        if (adapter != null){
+            adapter.setOnTradeItemClickListener(new TradeItemAdapter.OnTradeItemClickListener() {
+                @Override
+                public void onClick(View view) {
+                    if (view instanceof CardView){
+                        TradeBean.DBean.ListBean bean = (TradeBean.DBean.ListBean) view.getTag();
+
+                    }else if (view instanceof ImageView){
+
+                        String id;
+                        if ((id = (String) view.getTag(R.drawable.trade_unfollowed)) != null){
+                            Log.e("ID","点击之前未关注");
+                            presenter.followTrade(id);
+                        }else if ((id = (String) view.getTag(R.drawable.trade_followed)) != null){
+                            Log.e("ID","点击之前已关注关注");
+                            presenter.unfollowTrade(id);
+                        }
+
+                    }else {
+                        Log.e(TAG,"未识别View");
+                    }
+
+                }
+            });
+        }
+    }
+
+
+
+    /**
+     * ******************Override*********************************
+     */
+    @Override
+    public void setUserVisibleHint(boolean isVisibleToUser) {
+        super.setUserVisibleHint(isVisibleToUser);
+        if (isVisibleToUser && toolbar != null) initToolbar();
+    }
+
+
+
+
+    /**
+     * ******************开放给Presenter调用的方法*******************
+     */
+
+    public void showToast(final String str){
+        handler.post(new Runnable() {
+            @Override
+            public void run() {
+                if (toast == null){
+                    toast = Toast.makeText(parent,str,Toast.LENGTH_SHORT);
+                }else {
+                    toast.setText(str);
+                }
+
+                toast.show();
+            }
+        });
+    }
+
+
+    public void onPageLoaded(final TradeBean bean){
+        PAGE_TO_LOAD++;
+        Log.e(TAG, String.valueOf(PAGE_TO_LOAD));
+        handler.post(new Runnable() {
+            @Override
+            public void run() {
+                if (adapter == null){
+                    adapter = new TradeItemAdapter(TradeListFragment.this,bean);
+                    recyclerview.setAdapter(adapter);
+                    recyclerview.setLayoutManager(layoutManager);
+                    setupAdapter();
+                }else {
+                    adapter.addAll(bean);
+                }
+            }
+        });
+    }
+
+
+    public void onFollowTradeSuccess(final String id){
+        handler.post(new Runnable() {
+            @Override
+            public void run() {
+                showToast("关注成功");
+                adapter.setFollowed(id);
+            }
+        });
+    }
+
+
+    public void onUnfollowTradeSuccess(final String id){
+        handler.post(new Runnable() {
+            @Override
+            public void run() {
+                showToast("取消关注成功");
+                adapter.setUnfollowed(id);
+            }
+        });
+    }
+
+
 }

+ 1 - 1
app/src/com/sheishuo/app/session/SessionHelper.java

@@ -418,7 +418,7 @@ public class SessionHelper {
 
             @Override
             public void onAvatarLongClicked(Context context, IMMessage message) {
-                // 一般用于群组@功能,或者弹出菜单,做拉黑,加好友等功能
+                // 一般用于聊天室@功能,或者弹出菜单,做拉黑,加好友等功能
             }
         };
 

+ 1 - 1
app/src/com/sheishuo/app/session/search/SearchMessageActivity.java

@@ -59,7 +59,7 @@ public class SearchMessageActivity extends UI {
     private String sessionId;
     private SessionTypeEnum sessionType;
 
-    // 转为群组类型提供
+    // 转为聊天室类型提供
     private List<TeamMember> members;
 
     private IMMessage emptyMsg;

+ 1 - 0
app/src/com/sheishuo/app/team/TeamCreateHelper.java

@@ -98,6 +98,7 @@ public class TeamCreateHelper {
         TeamTypeEnum type = TeamTypeEnum.Advanced;
         HashMap<TeamFieldEnum, Serializable> fields = new HashMap<>();
         fields.put(TeamFieldEnum.Name, teamName);
+
         NIMClient.getService(TeamService.class).createTeam(fields, type, "",
                 memberAccounts).setCallback(
                 new RequestCallback<Team>() {

+ 1 - 1
app/src/com/sheishuo/app/team/activity/AdvancedTeamJoinActivity.java

@@ -20,7 +20,7 @@ import com.netease.nimlib.sdk.team.constant.TeamTypeEnum;
 import com.netease.nimlib.sdk.team.model.Team;
 
 /**
- * 申请加入群组界面
+ * 申请加入聊天室界面
  * Created by hzxuwen on 2015/3/20.
  */
 public class AdvancedTeamJoinActivity extends UI implements View.OnClickListener {

+ 2 - 2
app/src/com/sheishuo/app/team/activity/AdvancedTeamSearchActivity.java

@@ -18,7 +18,7 @@ import com.netease.nimlib.sdk.team.TeamService;
 import com.netease.nimlib.sdk.team.model.Team;
 
 /**
- * 搜索加入群组界面
+ * 搜索加入聊天室界面
  * Created by hzxuwen on 2015/3/20.
  */
 public class AdvancedTeamSearchActivity extends UI {
@@ -89,7 +89,7 @@ public class AdvancedTeamSearchActivity extends UI {
     }
 
     /**
-     * 搜索群组成功的回调
+     * 搜索聊天室成功的回调
      * @param team 群
      */
     private void updateTeamInfo(Team team) {

+ 7 - 0
build.gradle

@@ -2,6 +2,13 @@
 
 buildscript {
     apply from: 'script.gradle', to: buildscript
+
+    repositories {
+        jcenter()
+    }
+    dependencies {
+        classpath 'com.antfortune.freeline:gradle:0.8.7'
+    }
 }
 
 allprojects {

+ 164 - 164
gradlew

@@ -1,164 +1,164 @@
-#!/usr/bin/env bash
-
-##############################################################################
-##
-##  Gradle start up script for UN*X
-##
-##############################################################################
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
-
-APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
-
-# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
-
-warn ( ) {
-    echo "$*"
-}
-
-die ( ) {
-    echo
-    echo "$*"
-    echo
-    exit 1
-}
-
-# OS specific support (must be 'true' or 'false').
-cygwin=false
-msys=false
-darwin=false
-case "`uname`" in
-  CYGWIN* )
-    cygwin=true
-    ;;
-  Darwin* )
-    darwin=true
-    ;;
-  MINGW* )
-    msys=true
-    ;;
-esac
-
-# For Cygwin, ensure paths are in UNIX format before anything is touched.
-if $cygwin ; then
-    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
-fi
-
-# Attempt to set APP_HOME
-# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
-    ls=`ls -ld "$PRG"`
-    link=`expr "$ls" : '.*-> \(.*\)$'`
-    if expr "$link" : '/.*' > /dev/null; then
-        PRG="$link"
-    else
-        PRG=`dirname "$PRG"`"/$link"
-    fi
-done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >&-
-APP_HOME="`pwd -P`"
-cd "$SAVED" >&-
-
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
-
-# Determine the Java command to use to start the JVM.
-if [ -n "$JAVA_HOME" ] ; then
-    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
-        # IBM's JDK on AIX uses strange locations for the executables
-        JAVACMD="$JAVA_HOME/jre/sh/java"
-    else
-        JAVACMD="$JAVA_HOME/bin/java"
-    fi
-    if [ ! -x "$JAVACMD" ] ; then
-        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
-    fi
-else
-    JAVACMD="java"
-    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
-fi
-
-# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
-    MAX_FD_LIMIT=`ulimit -H -n`
-    if [ $? -eq 0 ] ; then
-        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
-            MAX_FD="$MAX_FD_LIMIT"
-        fi
-        ulimit -n $MAX_FD
-        if [ $? -ne 0 ] ; then
-            warn "Could not set maximum file descriptor limit: $MAX_FD"
-        fi
-    else
-        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
-    fi
-fi
-
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
-    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
-
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
-    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
-    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
-
-    # We build the pattern for arguments to be converted via cygpath
-    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
-    SEP=""
-    for dir in $ROOTDIRSRAW ; do
-        ROOTDIRS="$ROOTDIRS$SEP$dir"
-        SEP="|"
-    done
-    OURCYGPATTERN="(^($ROOTDIRS))"
-    # Add a user-defined pattern to the cygpath arguments
-    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
-        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
-    fi
-    # Now convert the arguments - kludge to limit ourselves to /bin/sh
-    i=0
-    for arg in "$@" ; do
-        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
-        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
-
-        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
-            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
-        else
-            eval `echo args$i`="\"$arg\""
-        fi
-        i=$((i+1))
-    done
-    case $i in
-        (0) set -- ;;
-        (1) set -- "$args0" ;;
-        (2) set -- "$args0" "$args1" ;;
-        (3) set -- "$args0" "$args1" "$args2" ;;
-        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
-        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
-        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
-        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
-        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
-        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
-    esac
-fi
-
-# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
-function splitJvmOpts() {
-    JVM_OPTS=("$@")
-}
-eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
-JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
-
-exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
+#!/usr/bin/env bash
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "$*"
+}
+
+die ( ) {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+    JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

BIN
uikit/res/drawable-hdpi/blank_ico.png


BIN
uikit/res/drawable-hdpi/nim_actionbar_dark_logo_icon.png


BIN
uikit/res/drawable-mdpi/blank_ico.png


BIN
uikit/res/drawable-xhdpi/blank_ico.png


BIN
uikit/res/drawable-xhdpi/nim_actionbar_dark_logo_icon.png


BIN
uikit/res/drawable-xxhdpi/blank_ico.png


BIN
uikit/res/drawable-xxxhdpi/blank_ico.png


+ 0 - 7
uikit/res/drawable/nim_actionbar_nest_dark_logo.xml

@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<layer-list
-    xmlns:android="http://schemas.android.com/apk/res/android">
-    <item
-        android:drawable="@drawable/nim_actionbar_dark_logo_icon"
-        android:right="5dp"/>
-</layer-list>

+ 1 - 1
uikit/res/layout/mass_message_activity.xml

@@ -30,7 +30,7 @@
         <TextView
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:text="帐号/群组id" />
+            android:text="帐号/聊天室id" />
 
         <EditText
             android:id="@+id/session_id"

+ 3 - 3
uikit/res/values/strings.xml

@@ -33,7 +33,7 @@
     <string name="delete_has_blank">删 除</string>
     <string name="voice_to_text">转文字</string>
     <string name="forward_to_person">转发到个人</string>
-    <string name="forward_to_team">转发到群组</string>
+    <string name="forward_to_team">转发到聊天室</string>
     <string name="withdrawn_msg">撤 回</string>
     <string name="save">保存</string>
     <string name="main_msg_list_delete_chatting">删除该聊天</string>
@@ -42,7 +42,7 @@
     <string name="save_to_device">保存到手机</string>
     <string name="picture_save_fail">图片保存失败</string>
     <string name="picture_save_to">图片已保存到手机</string>
-    <string name="search_join_team">搜索加入群组</string>
+    <string name="search_join_team">搜索加入聊天室</string>
     <string name="file_transfer_state_downloaded">已下载</string>
     <string name="file_transfer_state_undownload">未下载</string>
     <string name="trans_voice_failed">语音转化失败</string>
@@ -115,7 +115,7 @@
     <string name="no_permission">没有权限</string>
     <string name="set_team_admin">设为管理员</string>
     <string name="cancel_team_admin">取消管理员</string>
-    <string name="team_member_remove_confirm">确定要将其移出群组么?</string>
+    <string name="team_member_remove_confirm">确定要将其移出聊天室么?</string>
     <string name="team_annourcement">群公告</string>
     <string name="invite_member">邀请成员</string>
     <string name="team_name">群名称</string>

+ 2 - 2
uikit/src/com/netease/nim/uikit/NimUIKit.java

@@ -271,7 +271,7 @@ public final class NimUIKit {
      * 打开一个聊天窗口,开始聊天
      *
      * @param context       上下文
-     * @param id            聊天对象ID(用户帐号account或者群组ID)
+     * @param id            聊天对象ID(用户帐号account或者聊天室ID)
      * @param sessionType   会话类型
      * @param customization 定制化信息。针对不同的聊天对象,可提供不同的定制化。
      * @param anchor        跳转到指定消息的位置,不需要跳转填null
@@ -289,7 +289,7 @@ public final class NimUIKit {
      * 打开一个聊天窗口(用于从聊天信息中创建群聊时,打开群聊)
      *
      * @param context       上下文
-     * @param id            聊天对象ID(用户帐号account或者群组ID)
+     * @param id            聊天对象ID(用户帐号account或者聊天室ID)
      * @param sessionType   会话类型
      * @param customization 定制化信息。针对不同的聊天对象,可提供不同的定制化。
      * @param backToClass   返回的指定页面

+ 1 - 1
uikit/src/com/netease/nim/uikit/contact/core/item/ItemTypes.java

@@ -20,7 +20,7 @@ public interface ItemTypes {
 
     int FRIEND = 1; // 好友项
 
-    int TEAM = 2; // 群组
+    int TEAM = 2; // 聊天室
 
     int TEAM_MEMBER = 3; // 群成员
 

+ 1 - 1
uikit/src/com/netease/nim/uikit/model/ToolBarOptions.java

@@ -18,7 +18,7 @@ public class ToolBarOptions {
     /**
      * toolbar的logo资源id
      */
-    public int logoId = R.drawable.nim_actionbar_nest_dark_logo;
+    public int logoId = R.drawable.blank_ico;
     /**
      * toolbar的返回按钮资源id,默认开启的资源nim_actionbar_dark_back_icon
      */

+ 1 - 1
uikit/src/com/netease/nim/uikit/recent/RecentContactsFragment.java

@@ -350,7 +350,7 @@ public class RecentContactsFragment extends TFragment {
                                 updateOfflineContactAited(loadedRecent);
                             }
                         }
-                        // 此处如果是界面刚初始化,为了防止界面卡顿,可先在后台把需要显示的用户资料和群组资料在后台加载好,然后再刷新界面
+                        // 此处如果是界面刚初始化,为了防止界面卡顿,可先在后台把需要显示的用户资料和聊天室资料在后台加载好,然后再刷新界面
                         //
                         msgLoaded = true;
                         if (isAdded()) {

+ 1 - 1
uikit/src/com/netease/nim/uikit/session/SessionEventListener.java

@@ -12,6 +12,6 @@ public interface SessionEventListener {
     // 头像点击事件处理,一般用于打开用户资料页面
     void onAvatarClicked(Context context, IMMessage message);
 
-    // 头像长按事件处理,一般用于群组@功能,或者弹出菜单,做拉黑,加好友等功能
+    // 头像长按事件处理,一般用于聊天室@功能,或者弹出菜单,做拉黑,加好友等功能
     void onAvatarLongClicked(Context context, IMMessage message);
 }

+ 2 - 2
uikit/src/com/netease/nim/uikit/session/activity/TeamMessageActivity.java

@@ -112,7 +112,7 @@ public class TeamMessageActivity extends BaseMessageActivity {
     }
 
     private void onRequestTeamInfoFailed() {
-        Toast.makeText(TeamMessageActivity.this, "获取群组信息失败!", Toast.LENGTH_SHORT).show();
+        Toast.makeText(TeamMessageActivity.this, "获取聊天室信息失败!", Toast.LENGTH_SHORT).show();
         finish();
     }
 
@@ -235,7 +235,7 @@ public class TeamMessageActivity extends BaseMessageActivity {
     @Override
     protected void initToolBar() {
         ToolBarOptions options = new ToolBarOptions();
-        options.titleString = "聊";
+        options.titleString = "聊天室";
         setToolBar(R.id.toolbar, options);
     }
 

+ 12 - 12
uikit/src/com/netease/nim/uikit/session/helper/TeamNotificationHelper.java

@@ -151,7 +151,7 @@ public class TeamNotificationHelper {
         String tip;
         Team team = TeamDataCache.getInstance().getTeamById(teamId.get());
         if (team.getType() == TeamTypeEnum.Advanced) {
-            tip = " 离开了";
+            tip = " 离开了聊天室";
         } else {
             tip = " 离开了讨论组";
         }
@@ -182,19 +182,19 @@ public class TeamNotificationHelper {
                     sb.append(authen + NimUIKit.getContext().getString(R.string.team_not_allow_anyone_join));
                 }
             } else if (field.getKey() == TeamFieldEnum.Extension) {
-                sb.append("扩展字段被更新为 " + field.getValue());
+                sb.append("聊天室扩展字段被更新为 " + field.getValue());
             } else if (field.getKey() == TeamFieldEnum.Ext_Server) {
-                sb.append("扩展字段(服务器)被更新为 " + field.getValue());
+                sb.append("聊天室扩展字段(服务器)被更新为 " + field.getValue());
             } else if (field.getKey() == TeamFieldEnum.ICON) {
-                sb.append("头像已更新");
+                sb.append("聊天室头像已更新");
             } else if (field.getKey() == TeamFieldEnum.InviteMode) {
-                sb.append("邀请他人权限被更新为 " + field.getValue());
+                sb.append("聊天室邀请他人权限被更新为 " + field.getValue());
             } else if (field.getKey() == TeamFieldEnum.TeamUpdateMode) {
-                sb.append("资料修改权限被更新为 " + field.getValue());
+                sb.append("聊天室资料修改权限被更新为 " + field.getValue());
             } else if (field.getKey() == TeamFieldEnum.BeInviteMode) {
-                sb.append("被邀请人身份验证权限被更新为 " + field.getValue());
+                sb.append("聊天室被邀请人身份验证权限被更新为 " + field.getValue());
             } else if (field.getKey() == TeamFieldEnum.TeamExtensionUpdateMode) {
-                sb.append("扩展字段修改权限被更新为 " + field.getValue());
+                sb.append("聊天室扩展字段修改权限被更新为 " + field.getValue());
             } else if (field.getKey() == TeamFieldEnum.AllMute) {
                 TeamAllMuteModeEnum teamAllMuteModeEnum = (TeamAllMuteModeEnum) field.getValue();
                 if (teamAllMuteModeEnum == TeamAllMuteModeEnum.Cancel) {
@@ -203,7 +203,7 @@ public class TeamNotificationHelper {
                     sb.append("群全员禁言");
                 }
             } else {
-                sb.append("" + field.getKey() + "被更新为 " + field.getValue());
+                sb.append("聊天室" + field.getKey() + "被更新为 " + field.getValue());
             }
             sb.append("\r\n");
         }
@@ -215,9 +215,9 @@ public class TeamNotificationHelper {
 
     private static String buildManagerPassTeamApplyNotification(MemberChangeAttachment a) {
         StringBuilder sb = new StringBuilder();
-        sb.append("管理员通过用户 ");
+        sb.append("欢迎 ");
         sb.append(buildMemberListString(a.getTargets(), null));
-        sb.append(" 的入群申请");
+        sb.append(" 加入聊天室");
 
         return sb.toString();
     }
@@ -225,7 +225,7 @@ public class TeamNotificationHelper {
     private static String buildTransferOwnerNotification(String from, MemberChangeAttachment a) {
         StringBuilder sb = new StringBuilder();
         sb.append(getTeamMemberDisplayName(from));
-        sb.append(" 将转移给 ");
+        sb.append(" 将聊天室转移给 ");
         sb.append(buildMemberListString(a.getTargets(), null));
 
         return sb.toString();

+ 1 - 1
uikit/src/com/netease/nim/uikit/session/module/list/MessageListPanelEx.java

@@ -970,7 +970,7 @@ public class MessageListPanelEx {
             });
         }
 
-        // 长按菜单项 -- 转发到群组
+        // 长按菜单项 -- 转发到聊天室
         private void longClickItemForwardToTeam(final IMMessage item, CustomAlertDialog alertDialog) {
             alertDialog.addItem(container.activity.getString(R.string.forward_to_team), new CustomAlertDialog.onSeparateItemClickListener() {
 

+ 1 - 1
uikit/src/com/netease/nim/uikit/team/activity/AdvancedTeamInfoActivity.java

@@ -491,7 +491,7 @@ public class AdvancedTeamInfoActivity extends UI implements
     }
 
     /**
-     * 初始化群组基本信息
+     * 初始化聊天室基本信息
      */
     private void loadTeamInfo() {
         Team t = TeamDataCache.getInstance().getTeamById(teamId);

+ 10 - 7
uikit/uikit.iml

@@ -59,13 +59,6 @@
       <sourceFolder url="file://$MODULE_DIR$/assets" type="java-resource" />
       <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
       <sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
-      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
-      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
-      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
-      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
-      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
       <sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
       <sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
       <sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
@@ -73,6 +66,15 @@
       <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
       <sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
       <sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
+      <excludeFolder url="file://$MODULE_DIR$/build/.DS_Store" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/.DS_Store" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/annotations" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" />
@@ -80,6 +82,7 @@
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-safeguard" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />